package admincommands; import java.util.Arrays; import java.util.List; import com.aionemu.gameserver.configs.administration.AdminConfig; import com.aionemu.gameserver.dataholders.DataManager; import com.aionemu.gameserver.model.gameobjects.player.Player; import com.aionemu.gameserver.model.gameobjects.player.npcFaction.ENpcFactionQuestState; import com.aionemu.gameserver.model.gameobjects.player.npcFaction.NpcFaction; import com.aionemu.gameserver.model.templates.QuestTemplate; import com.aionemu.gameserver.model.templates.quest.FinishedQuestCond; import com.aionemu.gameserver.model.templates.quest.XMLStartCondition; import com.aionemu.gameserver.network.aion.serverpackets.SM_DIALOG_WINDOW; import com.aionemu.gameserver.network.aion.serverpackets.SM_QUEST_ACTION; import com.aionemu.gameserver.network.aion.serverpackets.SM_QUEST_ACTION.ActionType; import com.aionemu.gameserver.network.aion.serverpackets.SM_QUEST_COMPLETED_LIST; import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE; import com.aionemu.gameserver.questEngine.QuestEngine; 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.services.QuestService; import com.aionemu.gameserver.utils.ChatUtil; import com.aionemu.gameserver.utils.PacketSendUtility; import com.aionemu.gameserver.utils.Util; import com.aionemu.gameserver.utils.chathandlers.AdminCommand; import com.aionemu.gameserver.world.World; /** * @author MrPoke, Neon, Pad */ public class Quest extends AdminCommand { public Quest() { super("quest", "Handles quest states of your target."); // @formatter:off setSyntaxInfo( "[player] - Resets/starts/deletes the specified quest.", "[player] - Shows the quest status of the specified quest.", "[player] [varNum] - Sets the specified quest state (default: apply var to all varNums, optional: set var to varNum [0-5]).", "[player] - Sets the specified quest flags.", "[player] - Sends the dialog page with the given page ID.", "Note: If no player parameter is given, your current target will be taken (defaults to your character, if no player is targeted)." ); // @formatter:on } @Override public void execute(Player admin, String... params) { if (params.length == 0) { sendInfo(admin); return; } byte index = 0; Player target; int questId = ChatUtil.getQuestId(params[index]); if (questId == 0) { target = World.getInstance().getPlayer(Util.convertName(params[index])); if (target == null || !target.isOnline()) { PacketSendUtility.sendPacket(admin, SM_SYSTEM_MESSAGE.STR_MSG_ASK_PCINFO_LOGOFF()); return; } if (++index >= params.length) { sendInfo(admin); return; } questId = ChatUtil.getQuestId(params[index]); } else { target = admin.getTarget() instanceof Player p ? p : admin; } if (questId == 0 || DataManager.QUEST_DATA.getQuestById(questId) == null) { sendInfo(admin, "Invalid quest."); return; } if (++index >= params.length) { sendInfo(admin); return; } // quest and target are both valid at this point if (params[index].equalsIgnoreCase("reset")) { resetQuest(admin, target, questId); } else if (params[index].equalsIgnoreCase("start")) { startQuest(admin, target, questId); } else if (params[index].equalsIgnoreCase("delete")) { deleteQuest(admin, target, questId); } else if (params[index].equalsIgnoreCase("status")) { showQuestStatus(admin, target, questId); } else if (params[index].equalsIgnoreCase("set")) { QuestStatus status; int var; int varNum = -1; try { status = QuestStatus.valueOf(params[++index].toUpperCase()); } catch (IllegalArgumentException e) { sendInfo(admin, " is one of " + Arrays.toString(QuestStatus.values())); return; } catch (IndexOutOfBoundsException e) { sendInfo(admin); return; } try { var = Integer.valueOf(params[++index]); } catch (NumberFormatException e) { sendInfo(admin, " must be an int value."); return; } catch (IndexOutOfBoundsException e) { sendInfo(admin); return; } if (++index < params.length) { // optional try { varNum = Integer.valueOf(params[index]); if (varNum < 0 || varNum > 5) throw new IllegalArgumentException(); } catch (IllegalArgumentException e) { // also catches NumberFormatException sendInfo(admin, "[varNum] must be an int value from 0 to 5."); return; } } setQuestStatus(admin, target, questId, status, var, varNum); } else if (params[index].equalsIgnoreCase("setflags")) { int flags; try { flags = Integer.valueOf(params[++index]); } catch (IndexOutOfBoundsException | NumberFormatException e) { sendInfo(admin, " must be an int value."); return; } setQuestFlags(admin, target, questId, flags); } else if (params[index].equalsIgnoreCase("dialog")) { int dialogPageId; try { dialogPageId = Integer.valueOf(params[++index]); } catch (IndexOutOfBoundsException | NumberFormatException e) { sendInfo(admin, " must be an int value."); return; } sendQuestDialog(admin, questId, dialogPageId); } else { sendInfo(admin); } } private void resetQuest(Player admin, Player target, int questId) { QuestState qs = target.getQuestStateList().getQuestState(questId); if (qs == null || qs.getStatus() != QuestStatus.START) { sendInfo(admin, "Only currently active quests can be reset."); return; } if (qs.getQuestVars().getQuestVars() == 0 && qs.getRewardGroup() == null) { sendInfo(admin, "Player " + target.getName() + "'s quest is already at the beginning."); return; } qs.setStatus(QuestStatus.START); qs.setQuestVar(0); qs.setRewardGroup(null); PacketSendUtility.sendPacket(target, new SM_QUEST_ACTION(ActionType.UPDATE, qs)); sendInfo(admin, "Reset " + ChatUtil.quest(questId) + " for player " + target.getName() + "."); } private void startQuest(Player admin, Player target, int questId) { QuestTemplate template = DataManager.QUEST_DATA.getQuestById(questId); if (template.getNpcFactionId() > 0) { startNpcFactionQuest(admin, target, questId, template.getNpcFactionId()); return; } else if (QuestService.startQuest(new QuestEnv(null, target, questId))) { sendInfo(admin, "Started " + ChatUtil.quest(questId) + " for player " + target.getName() + "."); return; } QuestState qs = target.getQuestStateList().getQuestState(questId); if (qs != null && (qs.getStatus() == QuestStatus.START || qs.getStatus() == QuestStatus.REWARD)) { sendInfo(admin, "Quest is already started."); } else if (qs != null && qs.getStatus() == QuestStatus.COMPLETE && !qs.canRepeat()) { sendInfo(admin, "Quest is already completed."); } else { StringBuilder sb = new StringBuilder(); List preconditions = template.getXMLStartConditions(); if (preconditions != null) { for (XMLStartCondition condition : preconditions) { List finisheds = condition.getFinishedPreconditions(); if (finisheds != null) { for (FinishedQuestCond fcondition : finisheds) { QuestState qs1 = target.getQuestStateList().getQuestState(fcondition.getQuestId()); if (qs1 == null || qs1.getStatus() != QuestStatus.COMPLETE) { sb.append("\n\t" + ChatUtil.quest(fcondition.getQuestId())); } } } } } sendInfo(admin, "Quest not started. " + (sb.length() > 0 ? "These quest(s) must be completed first:" + sb.toString() : "Some preconditions failed.")); } } private void startNpcFactionQuest(Player admin, Player target, int questId, int factionId) { NpcFaction faction = target.getNpcFactions().getActiveNpcFaction(false); if (faction == null || faction.getId() != factionId) { sendInfo(admin, "Player " + target.getName() + " is not registered to the organization for this quest."); return; } for (QuestTemplate template : DataManager.QUEST_DATA.getQuestsByNpcFaction(faction.getId(), target)) { if (template.getId() == questId) { // simulate daily reset faction.setActive(false); faction.setTime(-1); target.getNpcFactions().addNpcFaction(faction); faction.setActive(true); // set daily quest Id and time to avoid random quest faction.setState(ENpcFactionQuestState.NOTING); faction.setQuestId(questId); faction.setTime(faction.getTime() + 100); // send the daily quest to player target.getNpcFactions().sendDailyQuest(); sendInfo(admin, "Started npc faction quest " + ChatUtil.quest(questId) + " for player " + target.getName() + "."); return; } } sendInfo(admin, "Quest not implemented or player level doesn't match."); } private void deleteQuest(Player admin, Player target, int questId) { if (!admin.hasAccess(AdminConfig.CMD_QUEST_ADV_PARAMS)) { sendInfo(admin, ""); return; } QuestState qs = target.getQuestStateList().deleteQuest(questId); if (qs == null) { sendInfo(admin, "Player " + target.getName() + " does not have that quest."); return; } if (qs.getStatus() == QuestStatus.COMPLETE) QuestEngine.getInstance().sendCompletedQuests(target); // rewrite completed quest list else PacketSendUtility.sendPacket(target, new SM_QUEST_ACTION(ActionType.ABANDON, qs)); target.getController().updateNearbyQuests(); sendInfo(admin, "Deleted " + ChatUtil.quest(questId) + " for player " + target.getName() + "."); } private void showQuestStatus(Player admin, Player target, int questId) { if (!admin.hasAccess(AdminConfig.CMD_QUEST_ADV_PARAMS)) { sendInfo(admin, ""); return; } QuestState qs = target.getQuestStateList().getQuestState(questId); StringBuilder sb = new StringBuilder("Player: " + target.getName() + ", quest: " + ChatUtil.quest(questId) + "\n\tQuest status: "); if (qs == null) { sb.append("NULL"); } else { sb.append(qs.getStatus().toString()); sb.append("\n\tQuest vars:"); for (int i = 0; i <= 5; i++) sb.append(" " + qs.getQuestVarById(i)); sb.append(", encoded [" + qs.getQuestVars().getQuestVars() + "]"); sb.append("\n\tQuest flags: " + (qs.getFlags() & 0x3F) + " " + qs.getStepGroup()); // needs rework when flags are implemented like vars sb.append(", encoded [" + qs.getFlags() + "]"); } sendInfo(admin, sb.toString()); } private void setQuestStatus(Player admin, Player target, int questId, QuestStatus status, int var, int varNum) { if (!admin.hasAccess(AdminConfig.CMD_QUEST_ADV_PARAMS)) { sendInfo(admin, ""); return; } QuestState qs = target.getQuestStateList().getQuestState(questId); ActionType actionType; if (qs == null) { // player doesn't have that quest actionType = ActionType.ADD; qs = new QuestState(questId, status); target.getQuestStateList().addQuest(questId, qs); } else { actionType = qs.getStatus() == QuestStatus.COMPLETE ? ActionType.ADD : ActionType.UPDATE; qs.setStatus(status); } if (status == QuestStatus.COMPLETE) { qs.setQuestVar(0); // completed quests vars are always 0 if (!DataManager.QUEST_DATA.getQuestById(qs.getQuestId()).getRewards().isEmpty()) qs.setRewardGroup(0); // follow quests could require reward group > 0 to be unlocked (see quest_data.xml) QuestEngine.getInstance().onQuestCompleted(target, questId); } else { if (varNum == -1) qs.setQuestVar(var); else qs.setQuestVarById(varNum, var); } if (actionType == ActionType.ADD && status == QuestStatus.COMPLETE) PacketSendUtility.sendPacket(target, new SM_QUEST_COMPLETED_LIST(1, Arrays.asList(qs))); else PacketSendUtility.sendPacket(target, new SM_QUEST_ACTION(actionType, qs)); target.getController().updateNearbyQuests(); sendInfo(admin, "Set quest status of " + ChatUtil.quest(questId) + " for player " + target.getName() + "."); } private void setQuestFlags(Player admin, Player target, int questId, int flags) { // needs rework when flags are implemented like vars if (!admin.hasAccess(AdminConfig.CMD_QUEST_ADV_PARAMS)) { sendInfo(admin, ""); return; } QuestState qs = target.getQuestStateList().getQuestState(questId); if (qs == null || qs.getStatus() != QuestStatus.START) { sendInfo(admin, "Flags can only be set for active quests."); return; } qs.setFlags(flags); PacketSendUtility.sendPacket(target, new SM_QUEST_ACTION(ActionType.UPDATE, qs)); sendInfo(admin, "Set " + target.getName() + "'s quest flags to " + flags + "."); } private void sendQuestDialog(Player admin, int questId, int dialogPageId) { if (!admin.hasAccess(AdminConfig.CMD_QUEST_ADV_PARAMS)) { sendInfo(admin, ""); return; } PacketSendUtility.sendPacket(admin, new SM_DIALOG_WINDOW(0, dialogPageId, questId)); sendInfo(admin, "Sent dialog page " + dialogPageId + " of Q" + questId + "."); } }