package joshie.harvest.api.npc;
import com.google.common.collect.Maps;
import joshie.harvest.api.buildings.BuildingLocation;
import joshie.harvest.api.calendar.CalendarDate;
import joshie.harvest.api.calendar.CalendarEntry;
import joshie.harvest.api.calendar.Season;
import joshie.harvest.api.core.HFRegistry;
import joshie.harvest.api.npc.INPCHelper.Age;
import joshie.harvest.api.npc.INPCHelper.Gender;
import joshie.harvest.api.npc.gift.IGiftHandler;
import joshie.harvest.api.npc.gift.IGiftHandler.Quality;
import joshie.harvest.api.npc.greeting.GreetingShop;
import joshie.harvest.api.npc.greeting.IConditionalGreeting;
import joshie.harvest.api.shops.Shop;
import joshie.harvest.npcs.HFNPCs;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.entity.EntityAgeable;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
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.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nullable;
import java.util.*;
import static joshie.harvest.api.HFApi.npc;
import static joshie.harvest.api.npc.INPCHelper.Age.ADULT;
import static joshie.harvest.core.lib.HFModInfo.MODID;
//TODO: Remove forge registry in 0.7+
//Do not call setRegistryName or anything
//This is only extending the old forge registry for 0.5 > 0.6 compatability reason
public class NPC extends HFRegistry<NPC> implements CalendarEntry {
public static final Map<ResourceLocation, NPC> REGISTRY = Maps.newHashMap();
private final Set<NPC> family = new HashSet<>();
private final List<IConditionalGreeting> conditionals = new ArrayList<>(256);
private final String multipleLocalizationKey;
private final String generalLocalizationKey;
private final String localizationKey;
private final ResourceLocation skin;
private final UUID uuid;
private final Age age;
private final Gender gender;
private final CalendarDate birthday;
private final int insideColor;
private final int outsideColor;
protected Shop shop;
private BuildingLocation home;
private float height;
private float offset;
private IGiftHandler gifts;
private ISchedule schedule;
private boolean doesRespawn;
private boolean alex;
private IInfoButton info;
private boolean canInvite;
private NPC() {
this(new ResourceLocation(MODID, "null"), INPCHelper.Gender.MALE, INPCHelper.Age.ADULT, new CalendarDate(1, Season.SPRING, 1), 0, 0);
}
/** Register a default npc
* @param resource the registry name, e.g. harvestfestival:jim
* @param gender the gender of the npc, this is only used for specialised greetings
* @param age the age group of the npc
* @param birthday the date of birth for this npc,
* take note that by default there are 30 days in a season,
* if you use a higher number, this npc will never have
* a birthday unless users change the config value
* @param insideColor this is the internal border colour of the npcs chat box
* @param outsideColor this is the outer border colour of the npcs chat box **/
public NPC(ResourceLocation resource, Gender gender, Age age, CalendarDate birthday, int insideColor, int outsideColor) {
super(resource);
String MODID = resource.getResourceDomain();
String name = resource.getResourcePath();
this.age = age;
this.canInvite = true;
this.gender = gender;
this.height = 1F;
this.birthday = birthday;
this.doesRespawn = true;
this.insideColor = insideColor;
this.outsideColor = outsideColor;
this.localizationKey = MODID + ".npc." + name + ".";
this.generalLocalizationKey = MODID + ".npc.generic." + age.name().toLowerCase(Locale.ENGLISH) + ".";
this.skin = new ResourceLocation(MODID, "textures/entity/" + name + ".png");
this.multipleLocalizationKey = MODID + ".npc." + name + ".greeting";
this.uuid = UUID.nameUUIDFromBytes(resource.toString().getBytes());
}
@Override
public final Map<ResourceLocation, NPC> getRegistry() {
return REGISTRY;
}
public NPC setHeight(float height, float offset) {
this.height = height;
this.offset = offset;
return this;
}
public NPC setShop(Shop shop) {
this.shop = shop;
setHasInfo(new GreetingShop(getResource()));
return this;
}
@SuppressWarnings("unused")
public NPC setAlexSkin() {
this.alex = true;
return this;
}
@SuppressWarnings("unused")
public NPC setNoRespawn() {
this.doesRespawn = false;
return this;
}
public NPC setGiftHandler(IGiftHandler handler) {
gifts = handler;
return this;
}
public NPC setScheduleHandler(ISchedule handler) {
schedule = handler;
return this;
}
public NPC addGreeting(IConditionalGreeting greeting) {
this.conditionals.add(greeting);
return this;
}
public NPC setHasInfo(IInfoButton info) {
this.info = info;
return this;
}
public NPC setHome(BuildingLocation location) {
this.home = location;
return this;
}
public NPC setUninvitable() {
this.canInvite = false;
return this;
}
/** Mark the following npc as a family member of this npc
* This is mostly used for the starry night festival,
* Friends are also added, doesn't have to be direct npcs**/
public NPC addFamily(NPC... npcs) {
Collections.addAll(family, npcs);
return this;
}
public Age getAge() {
return age;
}
@Deprecated
//TODO: Remove in 0.7+
@SuppressWarnings("unused")
public Gender getGender() {
return gender;
}
@Nullable
public BuildingLocation getHome() {
return home;
}
public boolean canInvite() {
return getAge() == Age.ADULT && canInvite;
}
public boolean isMarriageCandidate() {
return age == ADULT;
}
@Deprecated
//TODO: Remove in 0.7+
public UUID getUUID() {
return uuid;
}
public float getHeight() {
return height;
}
public float getOffset() {
return offset;
}
@SuppressWarnings("deprecation")
public boolean isBuilder() {
return this == HFNPCs.CARPENTER;
}
public Shop getShop(World world, BlockPos pos, @Nullable EntityPlayer player) {
return shop;
}
public boolean isShopkeeper() {
return shop != null;
}
public CalendarDate getBirthday() {
return birthday;
}
@SuppressWarnings("deprecation")
public String getLocalizedName() {
return I18n.translateToLocal(getResource().getResourceDomain() + ".npc." + getResource().getResourcePath() + ".name");
}
public IInfoButton getInfoButton() {
return info;
}
public boolean onClickedInfoButton(EntityPlayer player) {
return info != null && info.onClicked(this, player);
}
public ResourceLocation getSkin() {
return skin;
}
public String getLocalizationKey() {
return localizationKey;
}
public String getGeneralLocalizationKey() {
return generalLocalizationKey;
}
//Returns the script that this character should say at this point
@SuppressWarnings("unchecked")
public String getGreeting(EntityPlayer player, EntityAgeable entity) {
Collections.shuffle(conditionals);
for (IConditionalGreeting greeting : conditionals) {
if (greeting.canDisplay(player, entity, this) && player.worldObj.rand.nextDouble() * 100D < greeting.getDisplayChance()) {
return greeting.getLocalizedText(player, entity, this);
}
}
return npc.getRandomSpeech(this, multipleLocalizationKey, 100);
}
public Quality getGiftValue(ItemStack stack) {
return gifts == null ? Quality.DECENT : gifts.getQuality(stack);
}
public String getInfoTooltip() {
return info.getTooltip();
}
public Set<NPC> getFamily() {
return family;
}
@SideOnly(Side.CLIENT)
public void drawInfo(GuiScreen screen, int x, int y) {
info.drawIcon(screen, x, y);
}
public ISchedule getScheduler() {
return schedule;
}
public int getInsideColor() {
return insideColor;
}
public int getOutsideColor() {
return outsideColor;
}
public boolean isAlexSkin() {
return alex;
}
public boolean respawns() {
return doesRespawn;
}
@Override
public ItemStack getStackRepresentation() {
return npc.getStackForNPC(this);
}
@SuppressWarnings("deprecation")
@Override
public void addTooltipForCalendarEntry(List<String> tooltip) {
tooltip.add(I18n.translateToLocalFormatted("harvestfestival.npc.tooltip.birthday", getLocalizedName()));
}
@Override
public boolean equals(Object o) {
return o instanceof NPC && getResource() != null && getResource().equals(((NPC) o).getResource());
}
@Override
public int hashCode() {
return getResource() == null? 0 : getResource().hashCode();
}
}