package joshie.harvest.api.quests;
import joshie.harvest.api.HFApi;
import joshie.harvest.api.knowledge.Note;
import joshie.harvest.api.npc.NPC;
import joshie.harvest.api.npc.NPCEntity;
import joshie.harvest.api.town.Town;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.registry.IForgeRegistry;
import net.minecraftforge.fml.common.registry.IForgeRegistryEntry;
import net.minecraftforge.fml.common.registry.RegistryBuilder;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public abstract class Quest extends IForgeRegistryEntry.Impl<Quest> {
/** DO NOT MODIFY THE ENTRIES IN THE OLD_REGISTRY, ALWAYS MAKE A COPY OF THE QUESTS **/
public static final IForgeRegistry<Quest> REGISTRY = new RegistryBuilder<Quest>().setName(new ResourceLocation("harvestfestival", "quests")).setType(Quest.class).setIDRange(0, 32000).create();
private Set<NPC> npcs = new HashSet<>();
protected ItemStack primary;
protected int quest_stage;
private TargetType type;
public Quest() {
this.type = TargetType.PLAYER;
}
/** Called when this quest is registered initially **/
public void onRegistered() {}
/** Return the priority of the quest,
* Ideally you should leave this as normal
* Except for quests such as festivals.
* This way festivals will take priority. */
public EventPriority getPriority() {
return EventPriority.NORMAL;
}
/** Returns a list of npcs that this quest lines uses */
protected Set<NPC> getNPCs() {
return npcs;
}
public final TargetType getQuestType() {
return type;
}
/** Called to check if this quest is able to be started, after all other checks are performed
*
* @param active the quests the player currently has active
* @param finished the quests the player has completed currently
* @return true if they can start this quest, false otherwise
*/
public boolean canStartQuest(Set<Quest> active, Set<Quest> finished) {
return true;
}
/** Whether or not this quest is repeatable **/
public boolean isRepeatable() {
return false;
}
/** Real quests are quests that take over a npcs chat,
* as in there is no chance of them ever saying anything else other than the quest,
* @return false for quests like greetings, recipes, traders etc where there is a condition for chatting */
public boolean isRealQuest() {
return true;
}
/** If this quest counts as a daily quest, and if it can currently be started
* @param town the town trying to start the quest in
* @param world the world
* @param pos the position
* @return false for quests that can only be started via the quest board at a random chance **/
public boolean canStartDailyQuest(Town town, World world, BlockPos pos) {
return false;
}
/** Called when this quest is selected as a daily quest
* in order to setup the context for this day
* @param town the town trying to start the quest in
* @param world the world
* @param pos the position*/
public void onSelectedAsDailyQuest(Town town, World world, BlockPos pos) {}
/** This is only called for daily quests, if they are repeatable
* This is how many days need to have passed before this quest can be repeated **/
public int getDaysBetween() {
return 0;
}
/** Call this to set the npcs that handle this quest
* @param npcs the npcs **/
public Quest setNPCs(NPC... npcs) {
primary = HFApi.npc.getStackForNPC(npcs[0]);
Collections.addAll(this.npcs, npcs);
return this;
}
/** Called to check if this npc is used
* @param npc the npc **/
public boolean isNPCUsed(EntityPlayer player, NPCEntity npc) {
return getNPCs().contains(npc.getNPC());
}
/** Set this quest as a town based quest**/
protected final Quest setTownQuest() {
this.type = TargetType.TOWN;
return this;
}
/** Returns the stage of this quest **/
public int getStage() {
return quest_stage;
}
/**
* Will only work when called on the SERVER side
* Use this to increase the stage, best place to call it is in onChatClosed
* @param player the player we're increasing the stage for
**/
public final void increaseStage(EntityPlayer player) {
HFApi.quests.increaseStage(this, player);
}
/** Syncs the data to the player from server to client **/
public final void syncData(EntityPlayer player) {
HFApi.quests.syncData(this, player);
}
/** Try not to ever call this internally, ALWAYS use increaseStage
* @param quest_stage the stage of the quests **/
public final Quest setStage(int quest_stage) {
this.quest_stage = quest_stage;
return this;
}
protected String getPrefix() {
return getRegistryName().getResourceDomain() + ".quest." + getRegistryName().getResourcePath();
}
/** The name of this quest line **/
@SuppressWarnings("deprecation")
public String getTitle() {
return I18n.translateToLocal(getPrefix() + ".title");
}
/** A very short description, of what the player is supposed to be doing at this stage
* If the player is null, then we are looking for the description that appears on the notice board, instead of in the book
* @param world the world
* @param player the player**/
@SideOnly(Side.CLIENT)
public String getDescription(World world, @Nullable EntityPlayer player) {
return null;
}
/** Which npc the player is supposed to be interacting with at this point **/
@SideOnly(Side.CLIENT)
public ItemStack getCurrentIcon(World world, EntityPlayer player) {
return primary;
}
/** Use this helper in conjunction with getLocalizedScript
* @param quest short form name **/
@SuppressWarnings("deprecation")
@SideOnly(Side.CLIENT)
public String getLocalized(String quest, Object... format) {
if (format.length == 0) return I18n.translateToLocal(getPrefix() + "." + quest.replace("_", ""));
else return I18n.translateToLocalFormatted(getPrefix() + "." + quest.replace("_", ""), format);
}
/** Called when this quest is selected to be displayed/used by an npc
* Use this method to setup context data for the quest that you need access to **/
public void onQuestSelectedForDisplay(EntityPlayer player, NPCEntity npc) {}
/** Return the script, in a simple unlocalised form
* This will get run through getLocalized, this is
* so you can return shorter, simple strings by default
* @param player the player who is talking
* @param npc the npc they're interacting with
* @return the script*/
@Nullable
@SideOnly(Side.CLIENT)
public String getLocalizedScript(EntityPlayer player, NPCEntity npc) {
return null;
}
/** This is used when you want the quest to have options to select from
* You can return this based on the stage */
@Nullable
public Selection getSelection(EntityPlayer player, NPCEntity npc) {
return null;
}
/** Called when chat closes
* @param player the player
* @param npc the npc**/
public void onChatClosed(EntityPlayer player, NPCEntity npc, boolean wasSneaking) {}
/** Called when a quest is started **/
public void onQuestActivated() {}
/** Called when the quest is completed
* @param player the player that completed the quest **/
public void onQuestCompleted(EntityPlayer player) {}
/** Called to gather the notes this quest fulfills, if it has been completed **/
public Set<Note> getNotes() {
return new HashSet<>();
}
/** Call to complete a quest, only calls the serverside
* @param player the player to complete the quest for **/
public final void complete(EntityPlayer player) {
HFApi.quests.completeQuest(this, player);
}
/** Call this to reward the player with an item **/
protected final void takeHeldStack(EntityPlayer player, int amount) {
player.inventory.decrStackSize(player.inventory.currentItem, amount);
}
/** Call this to reward the player with an item **/
public final void rewardItem(EntityPlayer player, ItemStack stack) {
HFApi.quests.rewardItem(this, player, stack);
}
/** Call this to reward the player with gold **/
public final void rewardGold(EntityPlayer player, long gold) {
HFApi.quests.rewardGold(player, gold);
}
/** Spawns an entity **/
protected final void rewardEntity(EntityPlayer player, String entity) {
HFApi.quests.rewardEntity(this, player, entity);
}
/** Called to load data about this quest
* @param nbt the nbt tag **/
public void readFromNBT(NBTTagCompound nbt) {
quest_stage = nbt.getShort("Stage");
}
/** Called to write data about this quest
* @param nbt the nbt tag to write to
* @return the nbt tag**/
public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
nbt.setShort("Stage", (short) quest_stage);
return nbt;
}
@Override
public boolean equals(Object o) {
return o instanceof Quest && getRegistryName() != null && getRegistryName().equals(((Quest) o).getRegistryName());
}
@Override
public int hashCode() {
return getRegistryName() == null? 0 : getRegistryName().hashCode();
}
/****
* EVENTS - Called automatically from vanilla events or npc specific ones
****/
public boolean onEntityInteract(EntityPlayer player, @Nullable ItemStack held, EnumHand hand, Entity target) { return false; }
public boolean onRightClickBlock(EntityPlayer player, BlockPos pos, EnumFacing face) { return false; }
}