package mhfc.net.common.quests.goals; import java.util.EnumSet; import java.util.Objects; import mhfc.net.common.quests.QuestStatus; import mhfc.net.common.quests.api.QuestGoal; import mhfc.net.common.quests.api.QuestGoalSocket; /** * * This is the super type for quest goals that do depend on multiple others where you have to fulfill them in a specific * order. */ public class ChainQuestGoal extends QuestGoal implements QuestGoalSocket { protected QuestGoal thisGoal; protected QuestGoal next; private boolean finalFailed; /** * Creates a new quest chain with a goal that has to be completed now and a quest chain that is next. The current * goal should not be null otherwise an {@link IllegalArgumentException} is thrown. * * @param socket * See {@link QuestGoal} * @param thisGoal * The goal of this step of the chain * @param next * The next chain element, null if the chain is over */ public ChainQuestGoal(QuestGoalSocket socket, QuestGoal thisGoal, QuestGoal next) { super(socket); Objects.requireNonNull(thisGoal, "The goal of this step may not be null"); Objects.requireNonNull(next, "The following goal may not be null"); thisGoal.setSocket(this); this.thisGoal = thisGoal; this.next = next; finalFailed = false; } public ChainQuestGoal(QuestGoal thisGoal, QuestGoal next) { this(null, thisGoal, next); } @Override public boolean isFulfilled() { if (thisGoal == null) { return true; } return false; } @Override public boolean isFailed() { if (thisGoal == null) { return finalFailed; } return thisGoal.isFailed(); } @Override public void questGoalStatusNotification(QuestGoal caller, EnumSet<QuestStatus> newStatus) { if (caller == thisGoal) { if (newStatus.contains(QuestStatus.Fulfilled)) { advanceGoal(newStatus.contains(QuestStatus.Failed)); } if (newStatus.contains(QuestStatus.Failed)) { onFailed(newStatus.contains(QuestStatus.Fulfilled)); } } else if (caller == next) { onNextNotified(newStatus); } else { onUnknownStatusNotification(caller, newStatus); } } @Override public void questGoalFinalize() { if (thisGoal != null) { thisGoal.questGoalFinalize(); } if (next != null) { next.questGoalFinalize(); } } /** * This gets called whenever this QuestGoal has notified us that it is finished. */ protected void advanceGoal(boolean newFailed) { thisGoal = next; if (thisGoal == null) { notifyOfStatus(EnumSet.<QuestStatus>of(QuestStatus.Fulfilled)); return; } thisGoal.setSocket(this); thisGoal.reset(); thisGoal.setActive(true); next = null; if (thisGoal instanceof ChainQuestGoal) { next = ((ChainQuestGoal) thisGoal).getNext(); thisGoal = ((ChainQuestGoal) thisGoal).thisGoal; } if (next == null) { finalFailed = newFailed; notifyOfStatus(true, newFailed); } else { next.setSocket(this); } } /** * This gets called whenever this QuestGoal has notified us that it is failed. */ protected void onFailed(boolean newFulfilled) { EnumSet<QuestStatus> e = EnumSet.<QuestStatus>of(QuestStatus.Failed); if (newFulfilled) { e.add(QuestStatus.Fulfilled); } notifyOfStatus(e); } protected void onNextNotified(EnumSet<QuestStatus> newStatus) { } /** * This gets called whenever some {@link QuestGoal} has notified us that is not the next goal. */ protected void onUnknownStatusNotification(QuestGoal caller, EnumSet<QuestStatus> newStatus) { throw new IllegalArgumentException( "ChainQuestGoal: A QuestGoal that is not our next goal should not notify us"); } public QuestGoal getNext() { return next; } public void setNext(QuestGoal goal) { this.next = goal; } @Override public void reset() { thisGoal.reset(); next.reset(); EnumSet<QuestStatus> e = EnumSet.<QuestStatus>of(QuestStatus.Failed); if (isFulfilled()) { e.add(QuestStatus.Fulfilled); } if (isFailed()) { e.add(QuestStatus.Failed); } notifyOfStatus(e); } @Override public void setActive(boolean newActive) { if (thisGoal != null) { thisGoal.setActive(newActive); } } }