테스트

aion-server 4.8

Gitteol
최고관리자 · 1 · 💬 0 클론/새로받기
 4.8 61f661d · 1 commits 새로받기(Pull)
game-server/src/com/aionemu/gameserver/questEngine/handlers/AbstractQuestHandler.java
package com.aionemu.gameserver.questEngine.handlers;

import static com.aionemu.gameserver.model.DialogAction.*;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

import com.aionemu.gameserver.ai.event.AIEventType;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.model.*;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Item;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.VisibleObject;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.gameobjects.player.QuestStateList;
import com.aionemu.gameserver.model.templates.QuestTemplate;
import com.aionemu.gameserver.model.templates.item.ItemTemplate;
import com.aionemu.gameserver.model.templates.quest.*;
import com.aionemu.gameserver.model.templates.rewards.BonusType;
import com.aionemu.gameserver.model.templates.spawns.SpawnTemplate;
import com.aionemu.gameserver.network.aion.serverpackets.*;
import com.aionemu.gameserver.network.aion.serverpackets.SM_QUEST_ACTION.ActionType;
import com.aionemu.gameserver.questEngine.QuestEngine;
import com.aionemu.gameserver.questEngine.model.QuestActionType;
import com.aionemu.gameserver.questEngine.model.QuestEnv;
import com.aionemu.gameserver.questEngine.model.QuestState;
import com.aionemu.gameserver.questEngine.model.QuestStatus;
import com.aionemu.gameserver.questEngine.task.QuestTasks;
import com.aionemu.gameserver.services.QuestService;
import com.aionemu.gameserver.services.item.ItemPacketService.ItemAddType;
import com.aionemu.gameserver.services.item.ItemPacketService.ItemUpdateType;
import com.aionemu.gameserver.services.item.ItemService;
import com.aionemu.gameserver.spawnengine.SpawnEngine;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.PositionUtil;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.WorldMapInstance;
import com.aionemu.gameserver.world.WorldPosition;
import com.aionemu.gameserver.world.geo.GeoService;
import com.aionemu.gameserver.world.zone.ZoneName;

/**
 * @author MrPoke, vlog, Majka
 */
public abstract class AbstractQuestHandler {

	protected static final QuestEngine qe = QuestEngine.getInstance();
	protected final int questId;
	protected List<QuestItems> workItems;
	protected Set<Integer> actionItems;

	/** Create a new AbstractQuestHandler object */
	protected AbstractQuestHandler(int questId) {
		this.questId = questId;
		QuestTemplate template = DataManager.QUEST_DATA.getQuestById(questId);
		if (template != null) { // Some artificial quests have dummy questIds
			loadWorkItems(template);
			loadActionItems(template);
		}
	}

	private void loadWorkItems(QuestTemplate template) {
		if (template.getQuestWorkItems() != null)
			workItems = template.getQuestWorkItems().getQuestWorkItem();
	}

	private void loadActionItems(QuestTemplate template) {
		for (QuestDrop drop : template.getQuestDrop()) {
			if (drop.getNpcId() / 100000 != 7)
				continue;
			if (actionItems == null)
				actionItems = new HashSet<>();
			actionItems.add(drop.getNpcId());
		}
	}

	public Set<Integer> getActionItems() {
		if (actionItems == null)
			return Collections.emptySet();
		return Collections.unmodifiableSet(actionItems);
	}

	public final int getQuestId() {
		return questId;
	}

	public abstract void register();

	public boolean onDialogEvent(QuestEnv env) {
		int dialogActionId = env.getDialogActionId();
		if (dialogActionId >= SELECT1 && dialogActionId <= SELECT15_4_4_4_4) {
			// simple "next page" event (action ID = next dialog page ID), but there are some quests where this default behavior does not apply (e.g.
			// 4074)
			sendDialogPacket(env, dialogActionId, questId);
			return true;
		}
		switch (dialogActionId) {
			case ASK_QUEST_ACCEPT: // show quest accept dialog (coming from pre-conversation)
				sendDialogPacket(env, DialogPage.ASK_QUEST_ACCEPT_WINDOW.id(), questId);
				return true;
			case QUEST_ACCEPT_1:
				return env.getVisibleObject() instanceof Npc ? sendQuestDialog(env, 1003) : closeDialogWindow(env);
			case QUEST_REFUSE:
			case QUEST_REFUSE_SIMPLE:
			case QUEST_REFUSE_1:
				return env.getVisibleObject() instanceof Npc ? sendQuestDialog(env, 1004) : closeDialogWindow(env);
			case QUEST_REFUSE_2:
				return env.getVisibleObject() instanceof Npc ? sendQuestDialog(env, 1005) : closeDialogWindow(env);
			case QUEST_REFUSE_3:
				return env.getVisibleObject() instanceof Npc ? sendQuestDialog(env, 1006) : closeDialogWindow(env);
			case QUEST_REFUSE_4:
				return env.getVisibleObject() instanceof Npc ? sendQuestDialog(env, 1007) : closeDialogWindow(env);
			case FINISH_DIALOG: // clicking X or ^ in quest accept window (client closes the window by itself / returns to quest selection)
				return true;
		}
		return false;
	}

	/**
	 * This method is called on every handler (which registered the event), after a player entered a map.
	 */
	public boolean onEnterWorldEvent(QuestEnv env) {
		return false;
	}

	public boolean onEnterZoneEvent(QuestEnv env, ZoneName zoneName) {
		return false;
	}

	public boolean onLeaveZoneEvent(QuestEnv env, ZoneName zoneName) {
		return false;
	}

	public HandlerResult onItemUseEvent(QuestEnv env, Item item) {
		return HandlerResult.UNKNOWN;
	}

	public boolean onHouseItemUseEvent(QuestEnv env) {
		return false;
	}

	public boolean onGetItemEvent(QuestEnv env) {
		return false;
	}

	public boolean onUseSkillEvent(QuestEnv env, int skillId) {
		return false;
	}

	public boolean onKillEvent(QuestEnv env) {
		return false;
	}

	public boolean onAttackEvent(QuestEnv env) {
		return false;
	}

	/**
	 * This method is called on every handler (which registered the event), after a player leveled up or down.
	 * 
	 * @param player
	 *          - The player whose level changed
	 */
	public void onLevelChangedEvent(Player player) {
	}

	/**
	 * This method is called on every handler (which registered the event), after a quest completed.
	 * 
	 * @param env
	 *          - QuestEnv containing the player and the quest ID he completed
	 */
	public void onQuestCompletedEvent(QuestEnv env) {
	}

	public boolean onDieEvent(QuestEnv env) {
		return false;
	}

	public boolean onLogOutEvent(QuestEnv env) {
		return false;
	}

	public boolean onNpcReachTargetEvent(QuestEnv env) {
		return false;
	}

	public boolean onNpcLostTargetEvent(QuestEnv env) {
		return false;
	}

	public void onMovieEndEvent(QuestEnv env, int movieId) {
	}

	public boolean onQuestTimerEndEvent(QuestEnv env) {
		return false;
	}

	public boolean onInvisibleTimerEndEvent(QuestEnv env) {
		return false;
	}

	public boolean onPassFlyingRingEvent(QuestEnv env, String flyingRing) {
		return false;
	}

	public boolean onKillRankedEvent(QuestEnv env) {
		return false;
	}

	public boolean onKillInWorldEvent(QuestEnv env) {
		return false;
	}

	public boolean onKillInZoneEvent(QuestEnv env) {
		return false;
	}

	public boolean onFailCraftEvent(QuestEnv env, int itemId) {
		return false;
	}

	public boolean onEquipItemEvent(QuestEnv env, int itemId) {
		return false;
	}

	public boolean onCanAct(QuestEnv env, QuestActionType questEventType, Object... objects) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(env.getQuestId());
		if (qs == null || qs.getStatus() != QuestStatus.START)
			return false;
		if (questEventType == QuestActionType.ACTION_ITEM_USE && actionItems != null) {
			QuestTemplate template = DataManager.QUEST_DATA.getQuestById(env.getQuestId());
			int droppedItem = 0;
			int dropCount = 0;
			for (QuestDrop drop : template.getQuestDrop()) {
				if (drop.getNpcId() == env.getTargetId()) {
					droppedItem = drop.getItemId();
					break;
				}
			}
			CollectItems collectItems = template.getCollectItems();
			if (collectItems != null && droppedItem != 0) {
				for (CollectItem item : collectItems.getCollectItem()) {
					if (item.getItemId() == droppedItem) {
						dropCount = item.getCount();
						break;
					}
				}
				if (dropCount != 0) {
					long currentCount = player.getInventory().getItemCountByItemId(droppedItem);
					if (currentCount >= dropCount)
						return false;
				}
			}
		}
		return true;
	}

	public boolean onAddAggroListEvent(QuestEnv env) {
		return false;
	}

	public boolean onAtDistanceEvent(QuestEnv env) {
		return false;
	}

	public boolean onEnterWindStreamEvent(QuestEnv env, int worldId) {
		return false;
	}

	public boolean rideAction(QuestEnv env, int rideItemId) {
		return false;
	}

	public boolean onDredgionRewardEvent(QuestEnv env) {
		return false;
	}

	public HandlerResult onBonusApplyEvent(QuestEnv env, BonusType bonusType, List<QuestItems> rewardItems) {
		return HandlerResult.UNKNOWN;
	}

	public boolean onProtectEndEvent(QuestEnv env) {
		return false;
	}

	public boolean onProtectFailEvent(QuestEnv env) {
		return false;
	}

	/** Update the status of the quest in player's journal */
	public void updateQuestStatus(QuestEnv env) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		PacketSendUtility.sendPacket(player, new SM_QUEST_ACTION(ActionType.UPDATE, qs));
		if (qs.getStatus() == QuestStatus.COMPLETE || qs.getStatus() == QuestStatus.REWARD)
			player.getController().updateNearbyQuests();
	}

	public void changeQuestStep(QuestEnv env, int oldStep, int newStep) {
		changeQuestStep(env, oldStep, newStep, false, oldStep > 0x3F || newStep > 0x3F ? -1 : 0);
	}

	public void changeQuestStep(QuestEnv env, int step, int nextStep, boolean reward) {
		changeQuestStep(env, step, nextStep, reward, 0);
	}

	/** Change the quest step to the next step or set quest status to reward */
	public void changeQuestStep(QuestEnv env, int step, int nextStep, boolean reward, int varNum) {
		QuestState qs = env.getPlayer().getQuestStateList().getQuestState(questId);
		if (qs != null && (varNum == -1 ? qs.getQuestVars().getQuestVars() == step : qs.getQuestVarById(varNum) == step)) {
			if (nextStep != step) { // quest can be rolled back if nextStep < step
				if (step > nextStep && qs.getStatus() == QuestStatus.START)
					PacketSendUtility.sendPacket(env.getPlayer(),
						SM_SYSTEM_MESSAGE.STR_QUEST_SYSTEMMSG_GIVEUP(DataManager.QUEST_DATA.getQuestById(questId).getL10n()));
				if (varNum == -1)
					qs.setQuestVar(nextStep);
				else
					qs.setQuestVarById(varNum, nextStep);
			}
			if (reward || nextStep != step) {
				if (reward)
					qs.setStatus(QuestStatus.REWARD);
				updateQuestStatus(env);
			}
		}
	}

	/** Send dialog to the player */
	public boolean sendQuestDialog(QuestEnv env, int dialogPageId) {
		if (dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW1.id() || dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW2.id()
			|| dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW3.id() || dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW4.id()
			|| dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW5.id() || dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW6.id()
			|| dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW7.id() || dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW8.id()
			|| dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW9.id() || dialogPageId == DialogPage.SELECT_QUEST_REWARD_WINDOW10.id()) {
			QuestState qs = env.getPlayer().getQuestStateList().getQuestState(questId);
			if (qs == null || qs.getStatus() != QuestStatus.REWARD) // reward packet exploitation fix
				return false;
		}
		// Not using handler questId, because some quests may handle events when quests are finished
		// In that case questId must be zero!!! (Kromede entry for example)
		sendDialogPacket(env, dialogPageId, env.getQuestId());
		return true;
	}

	private void sendDialogPacket(QuestEnv env, int dialogPageId, int questId) {
		int objId = 0;
		if (env.getVisibleObject() != null) {
			objId = env.getVisibleObject().getObjectId();
		}
		PacketSendUtility.sendPacket(env.getPlayer(), new SM_DIALOG_WINDOW(objId, dialogPageId, questId));
	}

	public boolean sendQuestSelectionDialog(QuestEnv env) {
		sendDialogPacket(env, 10, 0);
		return true;
	}

	public boolean closeDialogWindow(QuestEnv env) {
		sendDialogPacket(env, 0, 0);
		return true;
	}

	public boolean sendQuestStartDialog(QuestEnv env) {
		return sendQuestStartDialog(env, 0, 0); // TODO remove all calls and replace with super.onDialogEvent()
	}

	public boolean sendQuestStartDialog(QuestEnv env, QuestItems workItem) {
		return workItem == null ? sendQuestStartDialog(env, 0, 0) : sendQuestStartDialog(env, workItem.getItemId(), workItem.getCount());
	}

	/** Send default start quest dialog and start it (give the item on start) */
	public boolean sendQuestStartDialog(QuestEnv env, int itemId, long itemCount) {
		switch (env.getDialogActionId()) {
			case ASK_QUEST_ACCEPT:
				return sendQuestDialog(env, 4);
			case QUEST_ACCEPT:
			case QUEST_ACCEPT_1:
			case QUEST_ACCEPT_SIMPLE:
				if (QuestService.startQuest(env)) {
					if (itemId != 0 && itemCount != 0)
						giveQuestItem(env, itemId, itemCount);
					if (env.getDialogActionId() != QUEST_ACCEPT_SIMPLE && env.getVisibleObject() instanceof Npc)
						return sendQuestDialog(env, 1003);
					else
						return closeDialogWindow(env);
				}
				break;
			case QUEST_REFUSE_1:
			case QUEST_REFUSE_2:
				return sendQuestDialog(env, 1004);
			case QUEST_REFUSE_SIMPLE:
				return closeDialogWindow(env);
			case FINISH_DIALOG:
				return sendQuestSelectionDialog(env);
		}
		return false;
	}

	/** Remove all quest items and send and finish the quest */
	public boolean sendQuestEndDialog(QuestEnv env, int[] questItemsToRemove) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		QuestStatus status = qs == null ? null : qs.getStatus();
		for (int itemId : questItemsToRemove)
			removeQuestItem(env, itemId, player.getInventory().getItemCountByItemId(itemId), status);
		return sendQuestEndDialog(env);
	}

	/**
	 * Sends reward selection dialog of the quest or finishes it (if selection dialog was active)
	 */
	public boolean sendQuestEndDialog(QuestEnv env) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs == null || qs.getStatus() != QuestStatus.REWARD)
			return false; // reward packet exploitation fix (or buggy quest handler)

		int dialogActionId = env.getDialogActionId();
		if (dialogActionId >= SELECTED_QUEST_REWARD1 && dialogActionId <= SELECTED_QUEST_NOREWARD) {
			if (QuestService.finishQuest(env)) {
				Npc npc = (Npc) env.getVisibleObject();
				QuestNpc questNpc = QuestEngine.getInstance().getQuestNpc(npc.getNpcId());
				boolean npcHasActiveQuest = false;
				for (Integer questId : questNpc.getOnTalkEvent()) { // all quest IDs that have registered talk events for this npc
					QuestState qs2 = player.getQuestStateList().getQuestState(questId);
					if (qs2 != null && qs2.getStatus() == QuestStatus.REWARD) { // TODO make sure that this npc is the end npc
						env.setQuestId(questId);
						env.setDialogActionId(DialogAction.USE_OBJECT); // show default dialog (reward selection for next quest)
						return QuestEngine.getInstance().onDialog(new QuestEnv(npc, player, questId, DialogAction.USE_OBJECT));
					} else if (!npcHasActiveQuest && qs2 != null && qs2.getStatus() == QuestStatus.START) {
						boolean isQuestStartNpc = questNpc.getOnQuestStart().contains(questId);
						if (!isQuestStartNpc || DataManager.QUEST_DATA.getQuestById(questId).isMission() && qs2.getQuestVars().getQuestVars() == 0)
							npcHasActiveQuest = true; // TODO correct way to make sure that active quest can be continued at this npc
					}
				}
				boolean npcHasNewQuest = false;
				for (Integer questId : questNpc.getOnQuestStart()) { // all quest IDs that are registered to be started at this npc
					if (QuestService.checkStartConditions(player, questId, false)) {
						npcHasNewQuest = true;
						QuestTemplate template = DataManager.QUEST_DATA.getQuestById(questId);
						for (XMLStartCondition startCondition : template.getXMLStartConditions()) {
							List<FinishedQuestCond> finishedQuests = startCondition.getFinishedPreconditions();
							if (finishedQuests != null) {
								for (FinishedQuestCond fcondition : finishedQuests) {
									if (fcondition.getQuestId() == env.getQuestId() && isAcceptableQuest(template)) {
										env.setQuestId(questId);
										env.setDialogActionId(DialogAction.QUEST_SELECT);
										env.setDialogContinuationFromPreQuest(true);
										return QuestEngine.getInstance().onDialog(env); // show start dialog of follow-up quest
									}
								}
							}
						}
					}
				}
				return npcHasActiveQuest || npcHasNewQuest ? sendQuestSelectionDialog(env) : closeDialogWindow(env);
			}
		} else {
			switch (dialogActionId) {
				case SET_SUCCEED: // report to pre-end npc (another npc is actually responsible for rewarding, so close this window)
					return closeDialogWindow(env);
				case USE_OBJECT: // start talking to npc
				case SELECT_QUEST_REWARD: // report to end npc
				case CHECK_USER_HAS_QUEST_ITEM: // report to end npc with collect item checks
				case CHECK_USER_HAS_QUEST_ITEM_SIMPLE: // report to end npc with collect item checks
					QuestService.validateAndFixRewardGroup(qs, questId); // fixes the reward group if necessary
					// show reward selection page
					return sendQuestDialog(env, DialogPage.getRewardPageByIndex(qs.getRewardGroup()).id());
			}
		}
		return false;
	}

	private boolean isAcceptableQuest(QuestTemplate quest) {
		if (quest.getMinlevelPermitted() == 99)
			return false;
		if (quest.getRewards().isEmpty() && quest.getExtendedRewards() == null && quest.getBonus() == null && quest.getQuestDrop().isEmpty()
			&& Stream.of(PlayerClass.values()).allMatch(c -> quest.getSelectableRewardByClass(c).isEmpty())) {
			return false;
		}
		return true;
	}

	public boolean defaultCloseDialog(QuestEnv env, int step, int nextStep) {
		return defaultCloseDialog(env, step, nextStep, false, false, 0, 0, 0, 0);
	}

	public boolean defaultCloseDialog(QuestEnv env, int step, int nextStep, int giveItemId, long giveItemCount) {
		return defaultCloseDialog(env, step, nextStep, false, false, giveItemId, giveItemCount, 0, 0);
	}

	public boolean defaultCloseDialog(QuestEnv env, int step, int nextStep, boolean reward, boolean sameNpc) {
		return defaultCloseDialog(env, step, nextStep, reward, sameNpc, 0, 0, 0, 0);
	}

	public boolean defaultCloseDialog(QuestEnv env, int step, int nextStep, boolean reward, boolean sameNpc, QuestItems questItemToAdd) {
		return defaultCloseDialog(env, step, nextStep, reward, sameNpc, questItemToAdd.getItemId(), questItemToAdd.getCount(), 0, 0);
	}

	public boolean defaultCloseDialog(QuestEnv env, int step, int nextStep, int giveItemId, long giveItemCount, int removeItemId,
		long removeItemCount) {
		return defaultCloseDialog(env, step, nextStep, false, false, giveItemId, giveItemCount, removeItemId, removeItemCount);
	}

	/**
	 * Handle on close dialog event, changing the quest status and giving/removing quest items
	 */
	public boolean defaultCloseDialog(QuestEnv env, int step, int nextStep, boolean reward, boolean sameNpc, int giveItemId, long giveItemCount,
		int removeItemId, long removeItemCount) {
		QuestState qs = env.getPlayer().getQuestStateList().getQuestState(questId);
		if (qs.getQuestVarById(0) == step) {
			if (giveItemId != 0 && giveItemCount != 0) {
				if (!giveQuestItem(env, giveItemId, giveItemCount)) {
					return false;
				}
			}
			removeQuestItem(env, removeItemId, removeItemCount, qs.getStatus());
			changeQuestStep(env, step, nextStep, reward);
			if (sameNpc) {
				return sendQuestEndDialog(env);
			}
			if (env.getVisibleObject() instanceof Npc)
				((Npc) env.getVisibleObject()).getAi().onCreatureEvent(AIEventType.DIALOG_FINISH, env.getPlayer());
			return closeDialogWindow(env);
		}
		return false;
	}

	public boolean checkQuestItems(QuestEnv env, int step, int nextStep, boolean reward, int checkOkId, int checkFailId) {
		return checkQuestItems(env, step, nextStep, reward, checkOkId, checkFailId, 0, 0);
	}

	/** Check if the player has quest item, listed in the quest_data.xml in his inventory */
	public boolean checkQuestItems(QuestEnv env, int step, int nextStep, boolean reward, int checkOkId, int checkFailId, int giveItemId,
		int giveItemCount) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs.getQuestVarById(0) == step) {
			if (QuestService.collectItemCheck(env, true)) {
				if (giveItemId != 0 && giveItemCount != 0) {
					if (!giveQuestItem(env, giveItemId, giveItemCount)) {
						return false;
					}
				}
				changeQuestStep(env, step, nextStep, reward);
				return sendQuestDialog(env, checkOkId);
			} else {
				return sendQuestDialog(env, checkFailId);
			}
		}
		return false;
	}

	/** Check if the player has quest item (simple version), listed in the quest_data.xml in his inventory */
	public boolean checkQuestItemsSimple(QuestEnv env, int step, int nextStep, boolean reward, int checkOkId, int giveItemId, int giveItemCount) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs.getQuestVarById(0) == step) {
			if (QuestService.collectItemCheck(env, true)) {
				if (giveItemId != 0 && giveItemCount != 0) {
					if (!giveQuestItem(env, giveItemId, giveItemCount)) {
						return false;
					}
				}
				changeQuestStep(env, step, nextStep, reward);
				return sendQuestDialog(env, checkOkId);
			} else
				return closeDialogWindow(env);
		}
		return false;
	}

	/** To use for checking the items, not listed in the collect_items in the quest_data.xml */
	public boolean checkItemExistence(QuestEnv env, int step, int nextStep, boolean reward, int itemId, int itemCount, boolean remove, int checkOkId,
		int checkFailId, int giveItemId, int giveItemCount) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs.getQuestVarById(0) == step) {
			if (checkItemExistence(env, itemId, itemCount, remove)) {
				if (giveItemId != 0 && giveItemCount != 0) {
					if (!giveQuestItem(env, giveItemId, giveItemCount)) {
						return false;
					}
				}
				changeQuestStep(env, step, nextStep, reward);
				return sendQuestDialog(env, checkOkId);
			} else {
				return sendQuestDialog(env, checkFailId);
			}
		}
		return false;
	}

	/** Check, if item exists in the player's inventory and probably remove it */
	public boolean checkItemExistence(QuestEnv env, int itemId, int itemCount, boolean remove) {
		Player player = env.getPlayer();
		if (player.getInventory().getItemCountByItemId(itemId) >= itemCount) {
			if (remove) {
				if (!removeQuestItem(env, itemId, itemCount)) {
					return false;
				}
			}
			return true;
		} else {
			return false;
		}
	}

	public void sendEmotion(QuestEnv env, Creature emoteCreature, EmotionId emotion, boolean broadcast) {
		Player player = env.getPlayer();
		int targetId = player.equals(emoteCreature) ? env.getVisibleObject().getObjectId() : player.getObjectId();
		PacketSendUtility.broadcastPacket(player, new SM_EMOTION(emoteCreature, EmotionType.EMOTE, emotion.id(), targetId), broadcast);
	}

	/** Give the quest item to player's inventory */
	public boolean giveQuestItem(QuestEnv env, int itemId, long itemCount) {
		return giveQuestItem(env, itemId, itemCount, ItemAddType.QUEST_WORK_ITEM, ItemUpdateType.INC_ITEM_COLLECT);
	}

	public boolean giveQuestItem(QuestEnv env, int itemId, long itemCount, ItemAddType addType) {
		return giveQuestItem(env, itemId, itemCount, addType, ItemUpdateType.INC_ITEM_COLLECT);
	}

	public boolean giveQuestItem(QuestEnv env, int itemId, long itemCount, ItemAddType addType, ItemUpdateType updateType) {
		Player player = env.getPlayer();
		ItemTemplate item = DataManager.ITEM_DATA.getItemTemplate(itemId);
		if (itemId != 0 && itemCount != 0) {
			long existentItemCount = player.getInventory().getItemCountByItemId(itemId);
			if (existentItemCount < itemCount) {
				long itemsToGive = itemCount - existentItemCount; // some quest work items come from multiple quests, don't add again
				ItemService.addItem(player, itemId, itemsToGive, true, new ItemService.ItemUpdatePredicate(addType, updateType));
				return true;
			} else {
				PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_CAN_NOT_GET_LORE_ITEM((item.getL10n())));
				return true;
			}
		}
		return false;
	}

	/** Remove the specified count of this quest item from player's inventory */
	public boolean removeQuestItem(QuestEnv env, int itemId, long itemCount) {
		Player player = env.getPlayer();
		if (itemId != 0 && itemCount > 0) {
			QuestState qs = player.getQuestStateList().getQuestState(questId);
			return player.getInventory().decreaseByItemId(itemId, itemCount, qs == null ? QuestStatus.START : qs.getStatus());
		}
		return false;
	}

	public boolean removeQuestItem(QuestEnv env, int itemId, long itemCount, QuestStatus questStatus) {
		Player player = env.getPlayer();
		if (itemId != 0 && itemCount != 0) {
			return player.getInventory().decreaseByItemId(itemId, itemCount, questStatus);
		}
		return false;
	}

	public boolean playQuestMovie(QuestEnv env, int movieId) {
		return playQuestMovie(env, movieId, false);
	}

	public boolean playQuestMovie(QuestEnv env, int cutsceneId, boolean isCutsceneMovie) {
		int targetObjectId = env.getVisibleObject() == null ? 0 : env.getVisibleObject().getObjectId();
		PacketSendUtility.sendPacket(env.getPlayer(), new SM_PLAY_MOVIE(isCutsceneMovie, targetObjectId, env.getQuestId(), cutsceneId, true));
		return false;
	}

	/** For single kill */
	public boolean defaultOnKillEvent(QuestEnv env, int npcId, int startVar, int endVar) {
		int[] mobids = { npcId };
		return defaultOnKillEvent(env, mobids, startVar, endVar);
	}

	/** For multiple kills */
	public boolean defaultOnKillEvent(QuestEnv env, int[] npcIds, int startVar, int endVar) {
		return defaultOnKillEvent(env, npcIds, startVar, endVar, 0);
	}

	/** For single kill on another QuestVar */
	public boolean defaultOnKillEvent(QuestEnv env, int npcId, int startVar, int endVar, int varNum) {
		int[] mobids = { npcId };
		return defaultOnKillEvent(env, mobids, startVar, endVar, varNum);
	}

	/** Handle onKill event */
	public boolean defaultOnKillEvent(QuestEnv env, int[] npcIds, int startVar, int endVar, int varNum) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs != null && qs.getStatus() == QuestStatus.START) {
			int var = qs.getQuestVarById(varNum);
			int targetId = env.getTargetId();
			for (int id : npcIds) {
				if (targetId == id) {
					if (var >= startVar && var < endVar) {
						qs.setQuestVarById(varNum, var + 1);
						updateQuestStatus(env);
						return true;
					}
				}
			}
		}
		return false;
	}

	/** For single kill and reward status after it */
	public boolean defaultOnKillEvent(QuestEnv env, int npcId, int startVar, boolean reward) {
		int[] mobids = { npcId };
		return (defaultOnKillEvent(env, mobids, startVar, reward, 0));
	}

	/** For single kill on another QuestVar and reward status after it */
	public boolean defaultOnKillEvent(QuestEnv env, int npcId, int startVar, boolean reward, int varNum) {
		int[] mobids = { npcId };
		return (defaultOnKillEvent(env, mobids, startVar, reward, varNum));
	}

	/** For multiple kills and reward status after it */
	public boolean defaultOnKillEvent(QuestEnv env, int[] npcIds, int startVar, boolean reward) {
		return (defaultOnKillEvent(env, npcIds, startVar, reward, 0));
	}

	/** Handle onKill event with reward status */
	public boolean defaultOnKillEvent(QuestEnv env, int[] npcIds, int startVar, boolean reward, int varNum) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs != null && qs.getStatus() == QuestStatus.START) {
			int var = qs.getQuestVarById(varNum);
			int targetId = env.getTargetId();
			for (int id : npcIds) {
				if (targetId == id) {
					if (var == startVar) {
						if (reward) {
							qs.setStatus(QuestStatus.REWARD);
						} else {
							qs.setQuestVarById(varNum, var + 1);
						}
						updateQuestStatus(env);
						return true;
					}
				}
			}
		}
		return false;
	}

	public boolean defaultOnKillRankedEvent(QuestEnv env, int startVar, int endVar, boolean reward) {
		return defaultOnKillRankedEvent(env, startVar, endVar, reward, false);
	}

	public boolean defaultOnKillRankedEvent(QuestEnv env, int startVar, int endVar, boolean reward, boolean isDataDriven) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs != null && qs.getStatus() == QuestStatus.START) {
			int var = qs.getQuestVarById(0);
			if (isDataDriven) {
				int varKill = qs.getQuestVarById(1);
				if (varKill >= startVar && varKill < (endVar - 1)) {
					changeQuestStep(env, varKill, varKill + 1, false, 1);
					return true;
				} else if (varKill == (endVar - 1)) {
					if (reward)
						qs.setStatus(QuestStatus.REWARD);
					qs.setQuestVar(var + 1);
				}
			} else {
				if (var >= startVar && var < (endVar - 1)) {
					changeQuestStep(env, var, var + 1, false);
					return true;
				} else if (var == (endVar - 1)) {
					if (reward)
						qs.setStatus(QuestStatus.REWARD);
					else
						qs.setQuestVarById(0, var + 1);
				}
			}
			updateQuestStatus(env);
			return true;
		}
		return false;
	}

	public boolean defaultOnKillInZoneEvent(QuestEnv env, int startVar, int endVar, boolean reward) {
		return defaultOnKillRankedEvent(env, startVar, endVar, reward, false);
	}

	public boolean defaultOnKillInZoneEvent(QuestEnv env, int startVar, int endVar, boolean reward, boolean isDataDriven) {
		return defaultOnKillRankedEvent(env, startVar, endVar, reward, isDataDriven);
	}

	public boolean defaultOnUseSkillEvent(QuestEnv env, int startVar, int endVar, int varNum) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs != null && qs.getStatus() == QuestStatus.START) {
			int var = qs.getQuestVarById(varNum);
			if (var >= startVar && var < endVar) {
				changeQuestStep(env, var, var + 1, false, varNum);
				return true;
			}
		}
		return false;
	}

	/** NPC starts following the player to the target. Use onLostTarget and onReachTarget for further actions. */
	public boolean defaultStartFollowEvent(QuestEnv env, Npc follower, int targetNpcId, int step, int nextStep) {
		Player player = env.getPlayer();
		if (!(env.getVisibleObject() instanceof Npc)) {
			return false;
		}
		follower.overrideNpcType(CreatureType.PEACE);
		follower.getAi().onCreatureEvent(AIEventType.FOLLOW_ME, player);
		player.getController().addTask(TaskId.QUEST_FOLLOW, QuestTasks.newFollowingToTargetCheckTask(env, follower, targetNpcId));
		return step == 0 && nextStep == 0 || defaultCloseDialog(env, step, nextStep);
	}

	/** NPC starts following the player to the target location. Use onLostTarget and onReachTarget for further actions. */
	public boolean defaultStartFollowEvent(QuestEnv env, Npc follower, float x, float y, float z, int step, int nextStep) {
		final Player player = env.getPlayer();
		if (!(env.getVisibleObject() instanceof Npc)) {
			return false;
		}
		PacketSendUtility.sendPacket(player, new SM_NPC_INFO(follower, player));
		follower.getAi().onCreatureEvent(AIEventType.FOLLOW_ME, player);
		player.getController().addTask(TaskId.QUEST_FOLLOW, QuestTasks.newFollowingToTargetCheckTask(env, follower, x, y, z));
		if (step == 0 && nextStep == 0) {
			return true;
		} else {
			return defaultCloseDialog(env, step, nextStep);
		}
	}

	/** NPC stops following the player. Used in both onLostTargetEvent and onReachTargetEvent. */
	public boolean defaultFollowEndEvent(QuestEnv env, int step, int nextStep, boolean reward, int movie) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs != null && qs.getStatus() == QuestStatus.START) {
			if (qs.getQuestVarById(0) == step) {
				changeQuestStep(env, step, nextStep, reward);
				if (movie != 0)
					playQuestMovie(env, movie);
				return true;
			}
		}
		return false;
	}

	public boolean defaultFollowEndEvent(QuestEnv env, int step, int nextStep, boolean reward) {
		return defaultFollowEndEvent(env, step, nextStep, reward, 0);
	}

	/** Changing quest step on getting item */
	public boolean defaultOnGetItemEvent(QuestEnv env, int step, int nextStep, boolean reward) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs != null && qs.getStatus() == QuestStatus.START) {
			if (qs.getQuestVarById(0) == step) {
				changeQuestStep(env, step, nextStep, reward);
				return true;
			}
		}
		return false;
	}

	public boolean useQuestObject(QuestEnv env, int step, int nextStep, boolean reward, boolean die) {
		return useQuestObject(env, step, nextStep, reward, 0, 0, 0, 0, 0, 0, die);
	}

	public boolean useQuestObject(QuestEnv env, int step, int nextStep, boolean reward, int varNum, boolean die) {
		return useQuestObject(env, step, nextStep, reward, varNum, 0, 0, 0, 0, 0, die);
	}

	public boolean useQuestObject(QuestEnv env, int step, int nextStep, boolean reward, int varNum) {
		return useQuestObject(env, step, nextStep, reward, varNum, 0, 0, 0, 0, 0, false);
	}

	public boolean useQuestObject(QuestEnv env, int step, int nextStep, boolean reward, int varNum, int addItemId, int addItemCount) {
		return useQuestObject(env, step, nextStep, reward, varNum, addItemId, addItemCount, 0, 0, 0, false);
	}

	public boolean useQuestObject(QuestEnv env, int step, int nextStep, boolean reward, int varNum, int addItemId, int addItemCount, int removeItemId,
		int removeItemCount) {
		return useQuestObject(env, step, nextStep, reward, varNum, addItemId, addItemCount, removeItemId, removeItemCount, 0, false);
	}

	public boolean useQuestObject(QuestEnv env, int step, int nextStep, boolean reward, int varNum, int movieId) {
		return useQuestObject(env, step, nextStep, reward, varNum, 0, 0, 0, 0, movieId, false);
	}

	/** Handle use object event */
	public boolean useQuestObject(QuestEnv env, int step, int nextStep, boolean reward, int varNum, int addItemId, int addItemCount, int removeItemId,
		int removeItemCount, int movieId, boolean dieObject) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs == null) {
			return false;
		}
		if (qs.getQuestVarById(varNum) == step) {
			if (addItemId != 0 && addItemCount != 0) {
				if (!giveQuestItem(env, addItemId, addItemCount)) {
					return false;
				}
			}
			if (removeItemId != 0 && removeItemCount != 0) {
				removeQuestItem(env, removeItemId, removeItemCount);
			}
			if (movieId != 0) {
				playQuestMovie(env, movieId);
			}
			if (dieObject) {
				Npc npc = (Npc) player.getTarget();
				if (!env.getVisibleObject().equals(npc))
					return false;
				npc.getController().die(player);
			}
			changeQuestStep(env, step, nextStep, reward, varNum);
			return true;
		}
		return false;
	}

	public boolean useQuestItem(QuestEnv env, Item item, int step, int nextStep, boolean reward) {
		return useQuestItem(env, item, step, nextStep, reward, 0, 0, 0);
	}

	public boolean useQuestItem(QuestEnv env, Item item, int step, int nextStep, boolean reward, final int addItemId, final int addItemCount) {
		return useQuestItem(env, item, step, nextStep, reward, addItemId, addItemCount, 0);
	}

	public boolean useQuestItem(QuestEnv env, Item item, int step, int nextStep, boolean reward, int movieId) {
		return useQuestItem(env, item, step, nextStep, reward, 0, 0, movieId);
	}

	public boolean useQuestItem(final QuestEnv env, final Item item, final int step, final int nextStep, final boolean reward, final int addItemId,
		final int addItemCount, final int movieId) {
		return useQuestItem(env, item, step, nextStep, reward, addItemId, addItemCount, movieId, 0);
	}

	/** Handle use item event */
	public boolean useQuestItem(final QuestEnv env, final Item item, final int step, final int nextStep, final boolean reward, final int addItemId,
		final int addItemCount, final int movieId, final int varNum) {
		final Player player = env.getPlayer();
		if (player == null) {
			return false;
		}
		final QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs == null) {
			return false;
		}
		final int itemId = item.getItemId();
		final int objectId = item.getObjectId();

		if (qs.getQuestVarById(varNum) == step) {
			PacketSendUtility.broadcastPacket(player, new SM_ITEM_USAGE_ANIMATION(player.getObjectId(), objectId, itemId, 3000, 0, 0), true);
			ThreadPoolManager.getInstance().schedule(new Runnable() {

				@Override
				public void run() {
					PacketSendUtility.broadcastPacket(player, new SM_ITEM_USAGE_ANIMATION(player.getObjectId(), objectId, itemId, 0, 1, 0), true);
					removeQuestItem(env, itemId, 1);

					if (addItemId != 0 && addItemCount != 0) {
						if (!giveQuestItem(env, addItemId, addItemCount)) {
							return;
						}
					}
					if (movieId != 0) {
						playQuestMovie(env, movieId);
					}
					changeQuestStep(env, step, nextStep, reward, varNum);
				}
			}, 3000);
			return true;
		}
		return false;
	}

	/**
	 * Starts or locks quest on level up (usually used from campaign quest handlers)
	 * 
	 * @param player
	 *          - Player who wants to start the quest
	 * @param preQuests
	 *          - The quests to be completed before starting this one
	 * @return True if successfully started
	 */
	public boolean defaultOnLevelChangedEvent(Player player, int... preQuests) {
		QuestState qs = player.getQuestStateList().getQuestState(questId);

		// Only null or LOCKED quests can be started
		if (qs != null && qs.getStatus() != QuestStatus.LOCKED)
			return false;

		QuestTemplate template = DataManager.QUEST_DATA.getQuestById(questId);
		int minLvlDiff = template.isMission() ? 2 : 0;
		// Check all player requirements (but allowed diff to quest minLevel = 2)
		if (!QuestService.checkStartConditions(player, questId, false, minLvlDiff, false, false, template.isMission()))
			return false;

		boolean missingRequirement = false;
		for (int id : preQuests) {
			QuestState qs2 = player.getQuestStateList().getQuestState(id);
			if (!missingRequirement && (qs2 == null || qs2.getStatus() != QuestStatus.COMPLETE)) {
				if (qs != null || !template.isMission()) // fast return if its already locked or no campaign quest
					return false;
				missingRequirement = true;
			}
			if (missingRequirement && qs2 != null && qs2.getStatus() == QuestStatus.COMPLETE) {
				QuestService.addOrUpdateQuest(player, questId, QuestStatus.LOCKED);
				return false;
			}
		}
		if (missingRequirement)
			return false;

		// Check the quests, that have to be done before starting this one and other start conditions, listed in quest_data
		for (XMLStartCondition cond : template.getXMLStartConditions()) {
			if (!cond.check(player, false)) {
				if (qs == null && template.isMission())
					QuestService.addOrUpdateQuest(player, questId, QuestStatus.LOCKED);
				return false;
			}
		}

		// Send locked quest if the player is <= 2 levels below quest min level (as specified in the check above)
		if (minLvlDiff > 0 && player.getLevel() < template.getMinlevelPermitted()) {
			if (qs == null && template.isMission())
				QuestService.addOrUpdateQuest(player, questId, QuestStatus.LOCKED);
			return false;
		}

		// All conditions are met, start the quest
		QuestService.addOrUpdateQuest(player, questId, QuestStatus.START);
		return true;
	}

	/**
	 * Starts or locks quest after quest completion (usually used from campaign quest handlers).
	 * 
	 * @param env
	 *          - QuestEnv containing the player and quest which he completed
	 * @param preQuests
	 *          - The quests to be completed before starting this one
	 * @return True if successfully started
	 */
	public boolean defaultOnQuestCompletedEvent(QuestEnv env, int... preQuests) {
		Player player = env.getPlayer();
		int finishedQuestId = env.getQuestId();
		QuestStateList qsl = player.getQuestStateList();
		QuestState qs = qsl.getQuestState(questId);

		// Only null or LOCKED quests can be started
		if (qs != null && qs.getStatus() != QuestStatus.LOCKED)
			return false;

		QuestTemplate template = DataManager.QUEST_DATA.getQuestById(questId);
		int minLvlDiff = template.isMission() ? 15 : 0; // this ensures to add all follow-up quests in locked state
		// Check all player requirements first
		if (!QuestService.checkStartConditions(player, questId, false, minLvlDiff, false, false, template.isMission()))
			return false;

		boolean missingRequirement = false;
		boolean hasFinishedPreQuest = false;
		for (int id : preQuests) {
			QuestState qs2 = qsl.getQuestState(id);
			if (!missingRequirement && (qs2 == null || qs2.getStatus() != QuestStatus.COMPLETE)) {
				if (qs != null || !template.isMission()) // fast return if its already locked or no campaign quest
					return false;
				missingRequirement = true;
			}
			if (finishedQuestId == id)
				hasFinishedPreQuest = true;
			if (missingRequirement && (hasFinishedPreQuest || qs2 != null && qs2.getStatus() == QuestStatus.COMPLETE)) { // if any pre quest is finished
				QuestService.addOrUpdateQuest(player, questId, QuestStatus.LOCKED);
				return false;
			}
		}
		if (missingRequirement)
			return false;

		// Check the quests, that have to be done before starting this one and other start conditions, listed in quest_data
		missingRequirement = false;
		for (XMLStartCondition cond : template.getXMLStartConditions()) {
			if (!cond.check(player, false)) {
				if (qs != null || !template.isMission()) // fast return if its already locked or no campaign quest
					return false;
				else if (hasAnyPreQuestFinished(qsl, cond)) { // recursive check
					QuestService.addOrUpdateQuest(player, questId, QuestStatus.LOCKED);
					return false;
				}
				missingRequirement = true;
			}
		}
		if (missingRequirement)
			return false;

		// Send locked quest if the players level is in the minLvlDiff range (1-15)
		if (minLvlDiff > 0 && player.getLevel() < template.getMinlevelPermitted()) {
			if (qs == null && hasFinishedPreQuest)
				QuestService.addOrUpdateQuest(player, questId, QuestStatus.LOCKED);
			return false;
		}

		// All conditions are met, start the quest
		QuestService.addOrUpdateQuest(player, questId, QuestStatus.START);
		return true;
	}

	/**
	 * Checks recursively if any pre-quest that is required, is completed
	 * 
	 * @param qsl
	 *          - Players {@link QuestStateList}
	 * @param startCondition
	 *          - The XML start condition list
	 * @return True, if any pre-quest of this series is finished
	 */
	private static boolean hasAnyPreQuestFinished(QuestStateList qsl, XMLStartCondition startCondition) {
		List<FinishedQuestCond> finishedQuests = startCondition.getFinishedPreconditions();
		if (finishedQuests != null) {
			for (FinishedQuestCond finishedCond : finishedQuests) {
				QuestState qs = qsl.getQuestState(finishedCond.getQuestId());
				if (qs != null && qs.getStatus() == QuestStatus.COMPLETE)
					return true;
				QuestTemplate template = DataManager.QUEST_DATA.getQuestById(finishedCond.getQuestId());
				for (XMLStartCondition cond : template.getXMLStartConditions())
					if (hasAnyPreQuestFinished(qsl, cond))
						return true;
			}
		}
		return false;
	}

	/** Start a mission on enter the questZone */
	public boolean defaultOnEnterZoneEvent(QuestEnv env, ZoneName currentZoneName, ZoneName questZoneName) {
		if (questZoneName == currentZoneName) {
			Player player = env.getPlayer();
			if (player == null)
				return false;
			QuestState qs = player.getQuestStateList().getQuestState(questId);
			if (qs == null) {
				env.setQuestId(questId);
				if (QuestService.startQuest(env))
					return true;
			}
		}
		return false;
	}

	public boolean sendQuestRewardDialog(QuestEnv env, int rewardNpcId, int reportDialogId) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs.getStatus() == QuestStatus.REWARD) {
			if (env.getTargetId() == rewardNpcId) {
				if (env.getDialogActionId() == USE_OBJECT && reportDialogId != 0) {
					return sendQuestDialog(env, reportDialogId);
				} else {
					return sendQuestEndDialog(env);
				}
			}
		}
		return false;
	}

	public boolean sendQuestNoneDialog(QuestEnv env, int startNpcId) {
		QuestTemplate template = DataManager.QUEST_DATA.getQuestById(questId);
		return sendQuestNoneDialog(env, template, startNpcId, 1011);
	}

	public boolean sendQuestNoneDialog(QuestEnv env, int startNpcId, int dialogPageId) {
		QuestTemplate template = DataManager.QUEST_DATA.getQuestById(questId);
		return sendQuestNoneDialog(env, template, startNpcId, dialogPageId);
	}

	public boolean sendQuestNoneDialog(QuestEnv env, QuestTemplate template, int startNpcId, int dialogPageId) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs == null || qs.isStartable()) {
			if (env.getTargetId() == startNpcId) {
				if (env.getDialogActionId() == QUEST_SELECT) {
					return sendQuestDialog(env, dialogPageId);
				} else {
					return sendQuestStartDialog(env);
				}
			}
		}
		return false;
	}

	public boolean sendQuestNoneDialog(QuestEnv env, int startNpcId, int dialogPageId, int itemId, int itemCout) {
		QuestTemplate template = DataManager.QUEST_DATA.getQuestById(questId);
		return sendQuestNoneDialog(env, template, startNpcId, dialogPageId, itemId, itemCout);
	}

	public boolean sendQuestNoneDialog(QuestEnv env, int startNpcId, int itemId, int itemCout) {
		QuestTemplate template = DataManager.QUEST_DATA.getQuestById(questId);
		return sendQuestNoneDialog(env, template, startNpcId, 1011, itemId, itemCout);
	}

	public boolean sendQuestNoneDialog(QuestEnv env, QuestTemplate template, int startNpcId, int dialogPageId, int itemId, int itemCout) {
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		if (qs == null || qs.isStartable()) {
			if (env.getTargetId() == startNpcId) {
				if (env.getDialogActionId() == QUEST_SELECT) {
					return sendQuestDialog(env, dialogPageId);
				}
				if (itemId != 0 && itemCout != 0) {
					if (env.getDialogActionId() == QUEST_ACCEPT_1) {
						if (giveQuestItem(env, itemId, itemCout)) {
							return sendQuestStartDialog(env);
						} else {
							return true;
						}
					} else {
						return sendQuestStartDialog(env);
					}
				} else {
					return sendQuestStartDialog(env);
				}
			}
		}
		return false;
	}

	public boolean sendItemCollectingStartDialog(QuestEnv env) {
		switch (env.getDialogActionId()) {
			case QUEST_ACCEPT_1:
				QuestService.startQuest(env);
				return sendQuestSelectionDialog(env);
			case QUEST_REFUSE_1:
				return sendQuestSelectionDialog(env);
		}
		return false;
	}

	public static VisibleObject spawn(int templateId, VisibleObject objectToGetInstanceFrom, float x, float y, float z, byte heading) {
		return spawn(templateId, objectToGetInstanceFrom.getWorldMapInstance(), x, y, z, heading);
	}

	public static VisibleObject spawn(int templateId, WorldMapInstance worldMapInstance, float x, float y, float z, byte heading) {
		SpawnTemplate template = SpawnEngine.newSingleTimeSpawn(worldMapInstance.getMapId(), templateId, x, y, z, heading);
		return SpawnEngine.spawnObject(template, worldMapInstance.getInstanceId());
	}

	public static VisibleObject spawnInFrontOf(int templateId, VisibleObject referencePositionObject) {
		return spawnInFront(templateId, referencePositionObject.getPosition(), null, 1.5f, 0);
	}

	public static VisibleObject spawnForFiveMinutesInFrontOf(int templateId, VisibleObject referencePositionObject, float distance) {
		return spawnInFront(templateId, referencePositionObject.getPosition(), null, distance, 5);
	}

	public static VisibleObject spawnForFiveMinutesInFront(int templateId, VisibleObject referencePositionObject, byte heading, float distance) {
		return spawnInFront(templateId, referencePositionObject.getPosition(), heading, distance, 5);
	}

	private static VisibleObject spawnInFront(int templateId, WorldPosition referencePosition, Byte heading, float distance, int timeInMin) {
		if (heading == null) // make the spawn face towards referencePosition
			heading = (byte) (referencePosition.getHeading() < 60 ? referencePosition.getHeading() + 60 : referencePosition.getHeading() - 60);
		double radian = Math.toRadians(PositionUtil.convertHeadingToAngle(referencePosition.getHeading()));
		float x = referencePosition.getX() + (float) (Math.cos(radian) * distance);
		float y = referencePosition.getY() + (float) (Math.sin(radian) * distance);
		float z = referencePosition.getZ();
		float geoZ = GeoService.getInstance().getZ(referencePosition.getMapId(), x, y, z + 2, z - 1, referencePosition.getInstanceId());
		if (!Float.isNaN(geoZ))
			z = geoZ;
		return spawnTemporarily(templateId, referencePosition.getWorldMapInstance(), x, y, z, heading, timeInMin);
	}

	public static VisibleObject spawnForFiveMinutes(int templateId, WorldPosition position) {
		return spawnForFiveMinutes(templateId, position, position.getHeading());
	}

	public static VisibleObject spawnForFiveMinutes(int templateId, WorldPosition position, byte heading) {
		return spawnTemporarily(templateId, position.getWorldMapInstance(), position.getX(), position.getY(), position.getZ(), heading, 5);
	}

	public static VisibleObject spawnForFiveMinutes(int templateId, WorldMapInstance worldMapInstance, float x, float y, float z, byte heading) {
		return spawnTemporarily(templateId, worldMapInstance, x, y, z, heading, 5);
	}

	public static VisibleObject spawnTemporarily(int templateId, WorldMapInstance worldMapInstance, float x, float y, float z, byte heading, int timeInMin) {
		VisibleObject object = spawn(templateId, worldMapInstance, x, y, z, heading);
		if (timeInMin > 0)
			ThreadPoolManager.getInstance().schedule(() -> object.getController().deleteIfAliveOrCancelRespawn(), 60000 * timeInMin);
		return object;
	}
}

📎 첨부파일

댓글 작성 권한이 없습니다.
🏆 포인트 랭킹 TOP 10
순위 닉네임 포인트
1 no_profile 타키야겐지쪽지보내기 자기소개 아이디로 검색 전체게시물 102,949
2 no_profile 동가리쪽지보내기 자기소개 아이디로 검색 전체게시물 63,733
3 no_profile 라프텔쪽지보내기 자기소개 아이디로 검색 전체게시물 51,771
4 no_profile 불멸의행복쪽지보내기 자기소개 아이디로 검색 전체게시물 36,923
5 서번트쪽지보내기 자기소개 아이디로 검색 전체게시물 35,011
6 no_profile 닥터스쪽지보내기 자기소개 아이디로 검색 전체게시물 29,470
7 no_profile 검은고양이쪽지보내기 자기소개 아이디로 검색 전체게시물 29,077
8 no_profile Revolution쪽지보내기 자기소개 아이디로 검색 전체게시물 28,199
9 no_profile 보거스쪽지보내기 자기소개 아이디로 검색 전체게시물 26,731
10 no_profile 호롤롤로쪽지보내기 자기소개 아이디로 검색 전체게시물 17,020
알림 0