package ttftcuts.physis.common.artifact;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBed;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemBoat;
import net.minecraft.item.ItemBucket;
import net.minecraft.item.ItemBucketMilk;
import net.minecraft.item.ItemDoor;
import net.minecraft.item.ItemEnchantedBook;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemMinecart;
import net.minecraft.item.ItemPotion;
import net.minecraft.item.ItemReed;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemWritableBook;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.Potion;
import net.minecraft.util.IIcon;
import net.minecraft.util.WeightedRandom;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.common.MinecraftForge;
import ttftcuts.physis.Physis;
import ttftcuts.physis.api.artifact.IArtifactEffect;
import ttftcuts.physis.api.artifact.IArtifactTrigger;
import ttftcuts.physis.api.internal.IArtifactHandler.CooldownCategory;
import ttftcuts.physis.common.PhysisItems;
import ttftcuts.physis.common.artifact.effect.EffectAir;
import ttftcuts.physis.common.artifact.effect.EffectExplosion;
import ttftcuts.physis.common.artifact.effect.EffectFire;
import ttftcuts.physis.common.artifact.effect.EffectForce;
import ttftcuts.physis.common.artifact.effect.EffectPotion;
import ttftcuts.physis.common.artifact.trigger.TriggerOnDealDamage;
import ttftcuts.physis.common.artifact.trigger.TriggerOnEquippedUpdate;
import ttftcuts.physis.common.artifact.trigger.TriggerOnTakeDamage;
import ttftcuts.physis.common.artifact.trigger.TriggerOnUpdate;
import ttftcuts.physis.common.artifact.trigger.UpdateCondition;
import ttftcuts.physis.common.file.ServerData;
import ttftcuts.physis.common.network.PhysisPacketHandler;
import ttftcuts.physis.common.network.packet.PacketPlayerUpdate;
public final class PhysisArtifacts {
private static PhysisArtifacts instance;
public static Random triggerColourRand = new Random(23456);
public static Random effectColourRand = new Random(12345);
public static final String PREFIX = Physis.MOD_ID+".artifact.";
public static final String ARTIFACTTAG = "physisArtifact";
public static final String TRIGGERTAG = "trigger";
public static final String EFFECTTAG = "effect";
public static final String COOLDOWNTAG = "cooldown";
public static final String SOCKETEDTAG = "physisSocketed";
public static final String SOCKETTAG = "socket";
public static final String SOCKETCOUNTTAG = "count";
public static final String SOCKETFIXED = "socketFixed";
public static Map<String, WeightedTrigger> triggers = new HashMap<String, WeightedTrigger>();
public static Map<String, WeightedEffect> effects = new HashMap<String, WeightedEffect>();
public static Map<IArtifactTrigger, IIcon> triggerIcons = new HashMap<IArtifactTrigger, IIcon>();
public static Map<IArtifactEffect, IIcon> effectIcons = new HashMap<IArtifactEffect, IIcon>();
public static IIcon defaultIcon;
public static void init() {
instance = new PhysisArtifacts();
// register triggers
//registerPhysisTrigger(new TriggerOnUpdate("OnUpdate"), 50);
for(UpdateCondition condition : UpdateCondition.values()) {
registerPhysisTrigger(new TriggerOnUpdate("OnUpdate", condition), (int)Math.floor(50 * condition.relativeRarity));
}
//registerPhysisTrigger(new TriggerOnEquippedUpdate("OnEquippedUpdate"), 100);
for(UpdateCondition condition : UpdateCondition.values()) {
registerPhysisTrigger(new TriggerOnEquippedUpdate("OnEquippedUpdate", condition), (int)Math.floor(100 * condition.relativeRarity));
}
registerPhysisTrigger(new TriggerOnDealDamage("OnDealDamage", false), 100);
registerPhysisTrigger(new TriggerOnDealDamage("OnDealDamageSelf", true), 50);
registerPhysisTrigger(new TriggerOnTakeDamage("OnTakeDamage", false), 100);
registerPhysisTrigger(new TriggerOnTakeDamage("OnTakeDamageSelf", true), 50);
// register effects
// potions
registerPhysisEffect(new EffectPotion("Poison", Potion.poison)
.setCooldowns(2, 2.5, 3, 4, 6, 9, 12)
.setDurations(4, 5, 5, 5, 6, 6, 6), 100);
registerPhysisEffect(new EffectPotion("Wither", Potion.wither)
.setCooldowns(3, 4, 6, 9, 12, 15, 25)
.setDurations(4, 5, 5, 5, 6, 6, 6), 20);
registerPhysisEffect(new EffectPotion("Hunger", Potion.hunger)
.setCooldowns(1, 1.5, 2, 2.5, 5, 7.5, 10)
.setDurations(4, 4, 5, 5, 6, 7, 8), 100);
registerPhysisEffect(new EffectPotion("Slowness", Potion.moveSlowdown)
.setCooldowns(1, 1.5, 2, 2.5, 5, 7.5, 10)
.setDurations(1, 1.5, 2, 2.5, 3.5, 5, 7.5), 60);
registerPhysisEffect(new EffectPotion("Speed", Potion.moveSpeed)
.setCooldowns(2, 3, 4, 5, 10, 15, 20)
.setDurations(1, 1, 1.5, 1.5, 2, 2, 2.5), 60);
registerPhysisEffect(new EffectPotion("Fatigue", Potion.digSlowdown)
.setCooldowns(1, 1.5, 2, 2.5, 5, 7.5, 10)
.setDurations(2, 3, 4, 5, 6, 7, 8), 60);
registerPhysisEffect(new EffectPotion("Haste", Potion.digSpeed)
.setCooldowns(2, 3, 4, 5, 10, 15, 20)
.setDurations(2, 2.5, 3, 3.5, 4, 4.5, 5), 80);
registerPhysisEffect(new EffectPotion("Strength", Potion.damageBoost)
.setCooldowns(2, 3, 4, 5, 10, 15, 20)
.setDurations(1, 1, 1.5, 1.5, 2, 2, 2.5), 60);
registerPhysisEffect(new EffectPotion("Weakness", Potion.weakness)
.setCooldowns(1, 1.5, 2, 2.5, 5, 7.5, 10)
.setDurations(4, 5, 6, 7, 8, 9, 10), 80);
registerPhysisEffect(new EffectPotion("Blindness", Potion.blindness)
.setCooldowns(2, 2.5, 3, 4, 6, 9, 12)
.setDurations(4, 5, 5, 5, 6, 6, 6), 60);
registerPhysisEffect(new EffectPotion("Regeneration", Potion.regeneration)
.setCooldowns(10, 15, 20, 25, 30, 45, 60)
.setDurations(6, 6, 7, 7, 8, 8, 10), 10);
registerPhysisEffect(new EffectPotion("Resistance", Potion.resistance)
.setCooldowns(1, 2, 3, 4, 6, 15, 25)
.setDurations(4, 5, 6, 7, 8, 9, 10), 50);
registerPhysisEffect(new EffectPotion("FireResistance", Potion.fireResistance)
.setCooldowns(10, 15, 20, 25, 30, 45, 60)
.setDurations(6, 6, 7, 7, 8, 8, 10), 10);
// explosions
registerPhysisEffect(new EffectExplosion("SmallExplosion", 4)
.setCooldowns(2, 3, 4, 5, 7, 9, 11), 20);
// fire
registerPhysisEffect(new EffectFire("Fire")
.setCooldowns(1,2,3,5,7,10,12)
.setDurations(2,3,4,5,6,8,10), 100);
// force
registerPhysisEffect(new EffectForce("ForceUp", 1.25)
.setCooldowns(3, 5, 8, 10, 13, 17, 20), 10);
registerPhysisEffect(new EffectForce("ForceDown", -1.5)
.setCooldowns(3, 5, 8, 10, 13, 17, 20), 5);
// air
registerPhysisEffect(new EffectAir("AirUp", 30)
.setCooldowns(0.5, 1, 2, 3, 4, 6, 8), 10);
registerPhysisEffect(new EffectAir("AirDown", -30)
.setCooldowns(0.5, 1, 2, 3, 4, 6, 8), 5);
}
// registering the icon event handler
public static void clientInit() {
MinecraftForge.EVENT_BUS.register(instance.new IconHandler());
}
// ################### registration ###################
public static boolean registerTrigger(IArtifactTrigger trigger, int weight) {
String name = trigger.getName();
if (!triggers.containsKey(name)) {
triggers.put(name, instance.new WeightedTrigger(weight, trigger));
return true;
}
return false;
}
public static boolean registerEffect(IArtifactEffect effect, int weight) {
String name = effect.getName();
if (!effects.containsKey(name)) {
effects.put(name, instance.new WeightedEffect(weight, effect));
return true;
}
return false;
}
private static IArtifactTrigger registerPhysisTrigger(IArtifactTrigger trigger, int weight) {
registerTrigger(trigger, weight);
return trigger;
}
private static IArtifactEffect registerPhysisEffect(IArtifactEffect effect, int weight) {
registerEffect(effect, weight);
return effect;
}
// ################### getters ###################
public static IArtifactTrigger getTrigger(String name) {
if (triggers.containsKey(name)) {
return triggers.get(name).theTrigger;
}
return null;
}
public static IArtifactEffect getEffect(String name) {
if (effects.containsKey(name)) {
return effects.get(name).theEffect;
}
return null;
}
public static IArtifactTrigger getRandomTrigger(Random rand) {
return ((WeightedTrigger)(WeightedRandom.getRandomItem(rand, triggers.entrySet()))).theTrigger;
}
public static IArtifactEffect getRandomEffect(Random rand) {
return ((WeightedEffect)(WeightedRandom.getRandomItem(rand, effects.entrySet()))).theEffect;
}
// ################### ItemStack methods ###################
public static NBTTagCompound[] getSocketablesFromStack(ItemStack stack) {
if (stack.stackTagCompound != null) {
if (stack.stackTagCompound.hasKey(SOCKETEDTAG)) {
NBTTagCompound data = stack.stackTagCompound.getCompoundTag(SOCKETEDTAG);
if (data.hasKey(SOCKETCOUNTTAG)) {
int count = data.getInteger(SOCKETCOUNTTAG);
NBTTagCompound[] socketables = new NBTTagCompound[count];
for (int i=0; i<count; i++) {
if (data.hasKey(SOCKETTAG+i)) {
socketables[i] = data.getCompoundTag(SOCKETTAG+i);
}
}
return socketables;
}
}
}
return null;
}
public static void writeSocketablesToStack(ItemStack stack, NBTTagCompound[] socketables) {
if (stack.stackTagCompound == null) {
stack.stackTagCompound = new NBTTagCompound();
}
NBTTagCompound data = new NBTTagCompound();
data.setInteger(SOCKETCOUNTTAG, socketables.length);
for (int i=0; i<socketables.length; i++) {
if (socketables[i] != null) {
data.setTag(SOCKETTAG+i, socketables[i]);
}
}
stack.stackTagCompound.setTag(SOCKETEDTAG, data);
}
public static void writeSocketablesToStack(ItemStack stack, ItemStack[] socketables) {
NBTTagCompound[] tags = new NBTTagCompound[socketables.length];
for(int i=0; i<socketables.length; i++) {
if (socketables[i] != null) {
NBTTagCompound tag = new NBTTagCompound();
socketables[i].writeToNBT(tag);
tags[i] = tag;
}
}
writeSocketablesToStack(stack, tags);
}
public static int getSocketCount(ItemStack stack) {
if (stack.stackTagCompound != null) {
if (stack.stackTagCompound.hasKey(SOCKETEDTAG)) {
NBTTagCompound data = stack.stackTagCompound.getCompoundTag(SOCKETEDTAG);
if (data.hasKey(SOCKETCOUNTTAG)) {
return data.getInteger(SOCKETCOUNTTAG);
}
}
}
return 0;
}
public static IArtifactTrigger getTriggerFromSocketable(NBTTagCompound tag) {
if (tag.hasKey("tag")) {
return getTriggerFromNBT(tag.getCompoundTag("tag"));
}
return null;
}
public static IArtifactTrigger getTriggerFromSocketable(ItemStack stack) {
if (stack.stackTagCompound != null) {
return getTriggerFromNBT(stack.stackTagCompound);
}
return null;
}
private static IArtifactTrigger getTriggerFromNBT(NBTTagCompound tag) {
if (tag.hasKey(ARTIFACTTAG)) {
tag = tag.getCompoundTag(ARTIFACTTAG);
if (tag.hasKey(TRIGGERTAG) && tag.hasKey(EFFECTTAG)) {
String name = tag.getString(TRIGGERTAG);
if (triggers.containsKey(name)) {
IArtifactTrigger trigger = triggers.get(name).theTrigger;
return trigger;
}
}
}
return null;
}
public static IArtifactEffect getEffectFromSocketable(NBTTagCompound tag) {
if (tag.hasKey("tag")) {
return getEffectFromNBT(tag.getCompoundTag("tag"));
}
return null;
}
public static IArtifactEffect getEffectFromSocketable(ItemStack stack) {
if (stack.stackTagCompound != null) {
return getEffectFromNBT(stack.stackTagCompound);
}
return null;
}
private static IArtifactEffect getEffectFromNBT(NBTTagCompound tag) {
if (tag.hasKey(ARTIFACTTAG)) {
tag = tag.getCompoundTag(ARTIFACTTAG);
if (tag.hasKey(TRIGGERTAG) && tag.hasKey(EFFECTTAG)) {
String name = tag.getString(EFFECTTAG);
if (effects.containsKey(name)) {
return effects.get(name).theEffect;
}
}
}
return null;
}
public static void doEffectCooldownTick(NBTTagCompound tag) {
if (tag.hasKey("tag")) {
doEffectCooldownTick(tag.getCompoundTag("tag"));
return;
}
if (tag.hasKey(ARTIFACTTAG)) {
tag = tag.getCompoundTag(ARTIFACTTAG);
if (tag.hasKey(TRIGGERTAG) && tag.hasKey(EFFECTTAG)) {
int cooldown = tag.getInteger(COOLDOWNTAG);
if (cooldown > 0) {
tag.setInteger(COOLDOWNTAG, cooldown - 1);
}
}
}
}
public static long getEffectCooldown(NBTTagCompound tag, boolean client) {
if (tag.hasKey("tag")) {
return getEffectCooldown(tag.getCompoundTag("tag"), client);
}
if (tag.hasKey(ARTIFACTTAG)) {
tag = tag.getCompoundTag(ARTIFACTTAG);
if (tag.hasKey(TRIGGERTAG) && tag.hasKey(EFFECTTAG)) {
return Math.max(0, tag.getLong(COOLDOWNTAG) - ServerData.instance(client).serverTick);
}
}
return 0;
}
public static long getEffectCooldown(ItemStack stack, boolean client) {
if (stack.stackTagCompound != null) {
return getEffectCooldown(stack.stackTagCompound, client);
}
return 0;
}
public static long getEffectMaxCooldown(NBTTagCompound tag) {
if (tag.hasKey("tag")) {
return getEffectMaxCooldown(tag.getCompoundTag("tag"));
}
if (tag.hasKey(ARTIFACTTAG)) {
tag = tag.getCompoundTag(ARTIFACTTAG);
if (tag.hasKey(TRIGGERTAG) && tag.hasKey(EFFECTTAG)) {
//return Math.max(0, tag.getLong(COOLDOWNTAG) - ServerData.instance.serverTick);
String ename = tag.getString(EFFECTTAG);
String tname = tag.getString(TRIGGERTAG);
if (effects.containsKey(ename) && triggers.containsKey(tname)) {
CooldownCategory cd = triggers.get(tname).theTrigger.getCooldownCategory();
effects.get(ename).theEffect.getCooldown(cd);
}
}
}
return 0;
}
public static void setEffectCooldown(NBTTagCompound tag, int cooldown) {
if (tag.hasKey("tag")) {
setEffectCooldown(tag.getCompoundTag("tag"), cooldown);
return;
}
if (tag.hasKey(ARTIFACTTAG)) {
tag = tag.getCompoundTag(ARTIFACTTAG);
if (tag.hasKey(TRIGGERTAG) && tag.hasKey(EFFECTTAG)) {
if (cooldown >= 0 && ServerData.instance(false) != null) {
tag.setLong(COOLDOWNTAG, cooldown + ServerData.instance(false).serverTick);
}
}
}
}
public static void addSocketToItem(ItemStack stack) {
if (stack.stackSize == 1) {
if (stack.stackTagCompound == null) {
stack.stackTagCompound = new NBTTagCompound();
}
NBTTagCompound tag = stack.stackTagCompound;
if (!tag.hasKey(SOCKETEDTAG)) {
tag.setTag(SOCKETEDTAG, new NBTTagCompound());
}
tag = tag.getCompoundTag(SOCKETEDTAG);
if (tag.hasKey(SOCKETCOUNTTAG)) {
tag.setInteger(SOCKETCOUNTTAG, tag.getInteger(SOCKETCOUNTTAG) +1);
} else {
tag.setInteger(SOCKETCOUNTTAG, 1);
}
}
}
public static void addItemToSocket(ItemStack stack, ItemStack socketable, int socket) {
if (stack.stackSize != 1
|| stack.stackTagCompound == null
|| !stack.stackTagCompound.hasKey(SOCKETEDTAG)) {
return;
}
NBTTagCompound data = stack.stackTagCompound.getCompoundTag(SOCKETEDTAG);
if (data.hasKey(SOCKETCOUNTTAG)) {
int sockets = data.getInteger(SOCKETCOUNTTAG);
if (socket >= sockets) {
return;
}
NBTTagCompound itemnbt = new NBTTagCompound();
socketable.writeToNBT(itemnbt);
data.setTag(SOCKETTAG + socket, itemnbt);
}
}
public static void removeItemFromSocket(ItemStack stack, int socket) {
NBTTagCompound data = stack.stackTagCompound.getCompoundTag(SOCKETEDTAG);
if (data.hasKey(SOCKETCOUNTTAG)) {
int sockets = data.getInteger(SOCKETCOUNTTAG);
if (socket >= sockets) {
return;
}
data.removeTag(SOCKETTAG + socket);
}
}
public static void addTriggerAndEffectToItem(ItemStack stack, IArtifactTrigger trigger, IArtifactEffect effect) {
if (stack.stackSize == 1) {
if (stack.stackTagCompound == null) {
stack.stackTagCompound = new NBTTagCompound();
}
NBTTagCompound tag = stack.stackTagCompound;
if (!tag.hasKey(ARTIFACTTAG)) {
tag.setTag(ARTIFACTTAG, new NBTTagCompound());
}
tag = tag.getCompoundTag(ARTIFACTTAG);
tag.setString(TRIGGERTAG, trigger.getName());
tag.setString(EFFECTTAG, effect.getName());
}
}
public static void addRandomTriggerAndEffectToItem(ItemStack stack, Random rand) {
addTriggerAndEffectToItem(stack, getRandomTrigger(rand), getRandomEffect(rand));
}
public static boolean canItemAcceptSockets(ItemStack stack) {
Item item = stack.getItem();
if (item == PhysisItems.socketable) {
return false;
}
if (item instanceof ItemBlock
|| item instanceof ItemReed
|| item instanceof ItemBed
|| item instanceof ItemFood
|| item instanceof ItemPotion
|| item instanceof ItemMinecart
|| item instanceof ItemBoat
|| item instanceof ItemEnchantedBook
|| item instanceof ItemWritableBook
|| item instanceof ItemBucket
|| item instanceof ItemBucketMilk
|| item instanceof ItemDoor) {
return false;
}
if (item.getItemStackLimit(stack) > 1) {
return false;
}
if (item.hasContainerItem(stack)){
ItemStack container = item.getContainerItem(stack);
if (container != null && container.getItem() instanceof ItemBucket) {
return false;
}
}
if (item.getUnlocalizedName(stack).toLowerCase().contains("bucket")) {
return false;
}
return true;
}
// ################### internal classes ###################
public class WeightedTrigger extends WeightedRandom.Item {
public IArtifactTrigger theTrigger;
public IIcon icon;
public WeightedTrigger(int weight, IArtifactTrigger trigger) {
super(weight);
this.theTrigger = trigger;
}
}
public class WeightedEffect extends WeightedRandom.Item {
public IArtifactEffect theEffect;
public IIcon icon;
public WeightedEffect(int weight, IArtifactEffect effect) {
super(weight);
this.theEffect = effect;
}
}
public static List<DelayedPunt> entitiesToPunt = new ArrayList<DelayedPunt>();
public class DelayedPunt {
public int delay = 0;
public final EntityLivingBase entity;
public final double force;
public DelayedPunt(EntityLivingBase entity, double force, int delay) {
this.entity = entity;
this.force = force;
this.delay = delay;
}
}
public static void puntEntity(EntityLivingBase entity, double force, int delay) {
entitiesToPunt.add(instance.new DelayedPunt(entity, force, delay));
}
public static void doPuntEntities() {
for(int i=entitiesToPunt.size()-1; i>=0; i--) {
DelayedPunt punt = entitiesToPunt.get(i);
if (punt.delay > 0) {
punt.delay--;
} else {
punt.entity.motionY += punt.force;
if (punt.entity instanceof EntityPlayerMP) {
EntityPlayerMP p = (EntityPlayerMP)(punt.entity);
PhysisPacketHandler.bus.sendTo(PacketPlayerUpdate.createPuntPacket(0, punt.force, 0), p);
}
entitiesToPunt.remove(i);
}
}
}
@SideOnly(Side.CLIENT)
public class IconHandler {
@SubscribeEvent
public void OnTextureStitch(TextureStitchEvent event) {
// if item sheet
if (event.map.getTextureType() == 1) {
//Physis.logger.info("STITCHING THE THINGS");
//Physis.logger.info("Default icon");
PhysisArtifacts.defaultIcon = event.map.registerIcon(Physis.MOD_ID+":trigger_effect/default");
for(WeightedTrigger trigger : PhysisArtifacts.triggers.values()) {
//Physis.logger.info("Trigger: "+trigger.theTrigger.getName());
IIcon icon = trigger.theTrigger.registerIcon(event.map);
PhysisArtifacts.triggerIcons.put(trigger.theTrigger, icon);
}
for(WeightedEffect effect : PhysisArtifacts.effects.values()) {
//Physis.logger.info("Effect: "+effect.theEffect.getName());
IIcon icon = effect.theEffect.registerIcon(event.map);
PhysisArtifacts.effectIcons.put(effect.theEffect, icon);
}
//Physis.logger.info("FINISHED STITCHING");
}
}
}
@SideOnly(Side.CLIENT)
public static IIcon getTriggerIcon(String name) {
IArtifactTrigger trigger = getTrigger(name);
return getTriggerIcon(trigger);
}
@SideOnly(Side.CLIENT)
public static IIcon getTriggerIcon(IArtifactTrigger trigger) {
if (trigger != null && triggerIcons.containsKey(trigger)) {
IIcon icon = triggerIcons.get(trigger);
if (icon != null ) {
return icon;
}
}
return defaultIcon;
}
@SideOnly(Side.CLIENT)
public static IIcon getEffectIcon(String name) {
IArtifactEffect effect = getEffect(name);
return getEffectIcon(effect);
}
@SideOnly(Side.CLIENT)
public static IIcon getEffectIcon(IArtifactEffect effect) {
if (effect != null && effectIcons.containsKey(effect)) {
IIcon icon = effectIcons.get(effect);
if (icon != null) {
return icon;
}
}
return defaultIcon;
}
}