/**
* This class was created by <Vazkii>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [May 26, 2014, 4:05:50 PM (GMT)]
*/
package vazkii.botania.common.item.equipment.bauble;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import net.minecraft.util.NonNullList;
import org.lwjgl.opengl.GL11;
import baubles.api.BaubleType;
import baubles.api.BaublesApi;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.resources.I18n;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.stats.Achievement;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import vazkii.botania.api.BotaniaAPI;
import vazkii.botania.api.item.IBaubleRender;
import vazkii.botania.api.mana.IManaUsingItem;
import vazkii.botania.api.mana.ManaItemHandler;
import vazkii.botania.api.sound.BotaniaSoundEvents;
import vazkii.botania.client.core.handler.MiscellaneousIcons;
import vazkii.botania.client.core.handler.ModelHandler;
import vazkii.botania.client.core.helper.IconHelper;
import vazkii.botania.client.core.helper.RenderHelper;
import vazkii.botania.client.core.helper.ShaderHelper;
import vazkii.botania.client.lib.LibResources;
import vazkii.botania.common.Botania;
import vazkii.botania.common.achievement.ICraftAchievement;
import vazkii.botania.common.achievement.ModAchievements;
import vazkii.botania.common.core.handler.ConfigHandler;
import vazkii.botania.common.core.helper.ItemNBTHelper;
import vazkii.botania.common.core.helper.StringObfuscator;
import vazkii.botania.common.core.helper.Vector3;
import vazkii.botania.common.item.ModItems;
import vazkii.botania.common.lib.LibItemNames;
public class ItemFlightTiara extends ItemBauble implements IManaUsingItem, IBaubleRender, ICraftAchievement {
private static final ResourceLocation textureHud = new ResourceLocation(LibResources.GUI_HUD_ICONS);
private static final ResourceLocation textureHalo = new ResourceLocation(LibResources.MISC_HALO);
private static final String TAG_FLYING = "flying";
private static final String TAG_TIME_LEFT = "timeLeft";
private static final String TAG_INFINITE_FLIGHT = "infiniteFlight";
private static final String TAG_DASH_COOLDOWN = "dashCooldown";
private static final String TAG_IS_SPRINTING = "isSprinting";
public static final List<String> playersWithFlight = new ArrayList();
private static final int COST = 35;
private static final int COST_OVERKILL = COST * 3;
private static final int MAX_FLY_TIME = 1200;
private static final int SUBTYPES = 8;
public static final int WING_TYPES = 9;
public static final String SUPER_AWESOME_HASH = "82F1EAD6A9B815E56C4F94C03C4BFE3E92CAA52AA79A40D753924BEF720FF868";
public ItemFlightTiara() {
super(LibItemNames.FLIGHT_TIARA);
MinecraftForge.EVENT_BUS.register(this);
setHasSubtypes(true);
}
@Override
public BaubleType getBaubleType(ItemStack arg0) {
return BaubleType.HEAD;
}
@Override
@SideOnly(Side.CLIENT)
public void getSubItems(@Nonnull Item item, CreativeTabs tab, NonNullList<ItemStack> list) {
for(int i = 0; i < SUBTYPES + 1; i++)
list.add(new ItemStack(item, 1, i));
}
@SideOnly(Side.CLIENT)
@Override
public void addHiddenTooltip(ItemStack par1ItemStack, EntityPlayer player, List<String> stacks, boolean par4) {
super.addHiddenTooltip(par1ItemStack, player, stacks, par4);
stacks.add(I18n.format("botania.wings" + par1ItemStack.getItemDamage()));
}
@Override
public void onEquipped(ItemStack stack, EntityLivingBase player) {
super.onEquipped(stack, player);
if(stack.getItemDamage() != WING_TYPES && StringObfuscator.matchesHash(stack.getDisplayName(), SUPER_AWESOME_HASH)) {
stack.setItemDamage(WING_TYPES);
stack.getTagCompound().removeTag("display");
}
}
@Override
public void onWornTick(ItemStack stack, EntityLivingBase player) {
super.onWornTick(stack, player);
if(player instanceof EntityPlayer) {
EntityPlayer p = (EntityPlayer) player;
boolean flying = p.capabilities.isFlying;
boolean wasSprting = ItemNBTHelper.getBoolean(stack, TAG_IS_SPRINTING, false);
boolean isSprinting = p.isSprinting();
if(isSprinting != wasSprting)
ItemNBTHelper.setBoolean(stack, TAG_IS_SPRINTING, isSprinting);
int time = ItemNBTHelper.getInt(stack, TAG_TIME_LEFT, MAX_FLY_TIME);
int newTime = time;
Vector3 look = new Vector3(p.getLookVec()).multiply(1, 0, 1).normalize();
if(flying) {
if(time > 0 && !ItemNBTHelper.getBoolean(stack, TAG_INFINITE_FLIGHT, false))
newTime--;
final int maxCd = 80;
int cooldown = ItemNBTHelper.getInt(stack, TAG_DASH_COOLDOWN, 0);
if(!wasSprting && isSprinting && cooldown == 0) {
p.motionX += look.x;
p.motionZ += look.z;
p.world.playSound(null, p.posX, p.posY, p.posZ, BotaniaSoundEvents.dash, SoundCategory.PLAYERS, 1F, 1F);
ItemNBTHelper.setInt(stack, TAG_DASH_COOLDOWN, maxCd);
} else if(cooldown > 0) {
if(maxCd - cooldown < 2)
player.moveRelative(0F, 1F, 5F);
else if(maxCd - cooldown < 10)
player.setSprinting(false);
ItemNBTHelper.setInt(stack, TAG_DASH_COOLDOWN, cooldown - 2);
if(player instanceof EntityPlayerMP)
BotaniaAPI.internalHandler.sendBaubleUpdatePacket((EntityPlayerMP) player, 4);
}
} else if(!flying) {
boolean doGlide = player.isSneaking() && !player.onGround && player.fallDistance >= 2F;
if(time < MAX_FLY_TIME && player.ticksExisted % (doGlide ? 6 : 2) == 0)
newTime++;
if(doGlide) {
player.motionY = Math.max(-0.15F, player.motionY);
float mul = 0.6F;
player.motionX = look.x * mul;
player.motionZ = look.z * mul;
player.fallDistance = 2F;
}
}
ItemNBTHelper.setBoolean(stack, TAG_FLYING, flying);
if(newTime != time)
ItemNBTHelper.setInt(stack, TAG_TIME_LEFT, newTime);
}
}
@SubscribeEvent
public void updatePlayerFlyStatus(LivingUpdateEvent event) {
if(event.getEntityLiving() instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) event.getEntityLiving();
ItemStack tiara = BaublesApi.getBaublesHandler(player).getStackInSlot(4);
int left = ItemNBTHelper.getInt(tiara, TAG_TIME_LEFT, MAX_FLY_TIME);
if(playersWithFlight.contains(playerStr(player))) {
if(shouldPlayerHaveFlight(player)) {
player.capabilities.allowFlying = true;
if(player.capabilities.isFlying) {
if(!player.world.isRemote)
ManaItemHandler.requestManaExact(tiara, player, getCost(tiara, left), true);
else if(Math.abs(player.motionX) > 0.1 || Math.abs(player.motionZ) > 0.1) {
double x = event.getEntityLiving().posX - 0.5;
double y = event.getEntityLiving().posY - 0.5;
double z = event.getEntityLiving().posZ - 0.5;
player.getGameProfile().getName();
float r = 1F;
float g = 1F;
float b = 1F;
switch(tiara.getItemDamage()) {
case 2 : {
r = 0.1F;
g = 0.1F;
b = 0.1F;
break;
}
case 3 : {
r = 0F;
g = 0.6F;
break;
}
case 4 : {
g = 0.3F;
b = 0.3F;
break;
}
case 5 : {
r = 0.6F;
g = 0F;
b = 0.6F;
break;
}
case 6 : {
r = 0.4F;
g = 0F;
b = 0F;
break;
}
case 7 : {
r = 0.2F;
g = 0.6F;
b = 0.2F;
break;
}
case 8 : {
r = 0.85F;
g = 0.85F;
b = 0F;
break;
}
case 9 : {
r = 0F;
b = 0F;
break;
}
}
for(int i = 0; i < 2; i++)
Botania.proxy.sparkleFX(x + Math.random() * event.getEntityLiving().width, y + Math.random() * 0.4, z + Math.random() * event.getEntityLiving().width, r, g, b, 2F * (float) Math.random(), 20);
}
}
} else {
if(!player.isSpectator() && !player.capabilities.isCreativeMode) {
player.capabilities.allowFlying = false;
player.capabilities.isFlying = false;
player.capabilities.disableDamage = false;
}
playersWithFlight.remove(playerStr(player));
}
} else if(shouldPlayerHaveFlight(player)) {
playersWithFlight.add(playerStr(player));
player.capabilities.allowFlying = true;
}
}
}
@SubscribeEvent
public void playerLoggedOut(PlayerEvent.PlayerLoggedOutEvent event) {
String username = event.player.getGameProfile().getName();
playersWithFlight.remove(username + ":false");
playersWithFlight.remove(username + ":true");
}
public static String playerStr(EntityPlayer player) {
return player.getGameProfile().getName() + ":" + player.world.isRemote;
}
private boolean shouldPlayerHaveFlight(EntityPlayer player) {
ItemStack armor = BaublesApi.getBaublesHandler(player).getStackInSlot(4);
if(!armor.isEmpty() && armor.getItem() == this) {
int left = ItemNBTHelper.getInt(armor, TAG_TIME_LEFT, MAX_FLY_TIME);
boolean flying = ItemNBTHelper.getBoolean(armor, TAG_FLYING, false);
return (left > (flying ? 0 : MAX_FLY_TIME / 10) || player.inventory.hasItemStack(new ItemStack(ModItems.flugelEye))) && ManaItemHandler.requestManaExact(armor, player, getCost(armor, left), false);
}
return false;
}
public int getCost(ItemStack stack, int timeLeft) {
return timeLeft <= 0 ? COST_OVERKILL : COST;
}
@Override
public boolean usesMana(ItemStack stack) {
return true;
}
@Override
@SideOnly(Side.CLIENT)
public void onPlayerBaubleRender(ItemStack stack, EntityPlayer player, RenderType type, float partialTicks) {
int meta = stack.getItemDamage();
if(type == RenderType.BODY) {
if(meta > 0 && meta <= MiscellaneousIcons.INSTANCE.tiaraWingIcons.length) {
TextureAtlasSprite icon = MiscellaneousIcons.INSTANCE.tiaraWingIcons[meta - 1];
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
boolean flying = player.capabilities.isFlying;
float rz = 120F;
float rx = 20F + (float) ((Math.sin((double) (player.ticksExisted + partialTicks) * (flying ? 0.4F : 0.2F)) + 0.5F) * (flying ? 30F : 5F));
float ry = 0F;
float h = 0.2F;
float i = 0.15F;
float s = 1F;
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.color(1F, 1F, 1F, 1F);
int light = 15728880;
int lightmapX = light % 65536;
int lightmapY = light / 65536;
float lbx = OpenGlHelper.lastBrightnessX;
float lby = OpenGlHelper.lastBrightnessY;
switch(meta) {
case 1 : { // Jibril
h = 0.4F;
break;
}
case 2 : { // Sephiroth
s = 1.3F;
break;
}
case 3 : { // Cirno
h = -0.1F;
rz = 0F;
rx = 0F;
i = 0.3F;
break;
}
case 4 : { // Phoenix
rz = 180F;
h = 0.5F;
rx = 20F;
ry = -(float) ((Math.sin((double) (player.ticksExisted + partialTicks) * (flying ? 0.4F : 0.2F)) + 0.6F) * (flying ? 30F : 5F));
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, lightmapX, lightmapY);
break;
}
case 5 : { // Kuroyukihime
h = 0.8F;
rz = 180F;
ry = -rx;
rx = 0F;
s = 2F;
break;
}
case 6 : { // Random Devil
rz = 150F;
break;
}
case 7 : { // Lyfa
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, lightmapX, lightmapY);
h = -0.1F;
rz = 0F;
ry = -rx;
rx = 0F;
GlStateManager.color(1F, 1F, 1F, 0.5F + (float) Math.cos((double) (player.ticksExisted + partialTicks) * 0.3F) * 0.2F);
break;
}
case 8 : { // Mega Ultra Chicken
h = 0.1F;
break;
}
case 9 : { // The One
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, lightmapX, lightmapY);
rz = 180F;
rx = 0F;
s = 1.5F;
h = 1.2F;
GlStateManager.color(1F, 1F, 1F, 0.5F + (flying ? (float) Math.cos((double) (player.ticksExisted + partialTicks) * 0.3F) * 0.25F + 0.25F : 0F));
}
}
// account for padding in the texture
float mul = 32F / 20F;
s *= mul;
float f = icon.getMinU();
float f1 = icon.getMaxU();
float f2 = icon.getMinV();
float f3 = icon.getMaxV();
float sr = 1F / s;
Helper.rotateIfSneaking(player);
GlStateManager.translate(0F, h, i);
GlStateManager.rotate(rz, 0F, 0F, 1F);
GlStateManager.rotate(rx, 1F, 0F, 0F);
GlStateManager.rotate(ry, 0F, 1F, 0F);
GlStateManager.scale(s, s, s);
IconHelper.renderIconIn3D(Tessellator.getInstance(), f1, f2, f, f3, icon.getIconWidth(), icon.getIconHeight(), 1F / 32F);
GlStateManager.scale(sr, sr, sr);
GlStateManager.rotate(-ry, 0F, 1F, 0F);
GlStateManager.rotate(-rx, 1F, 0F, 0F);
GlStateManager.rotate(-rz, 0F, 0F, 1F);
if(meta != 2) { // Sephiroth
GlStateManager.scale(-1F, 1F, 1F);
GlStateManager.rotate(rz, 0F, 0F, 1F);
GlStateManager.rotate(rx, 1F, 0F, 0F);
GlStateManager.rotate(ry, 0F, 1F, 0F);
GlStateManager.scale(s, s, s);
IconHelper.renderIconIn3D(Tessellator.getInstance(), f1, f2, f, f3, icon.getIconWidth(), icon.getIconHeight(), 1F / 32F);
GlStateManager.scale(sr, sr, sr);
GlStateManager.rotate(-ry, 1F, 0F, 0F);
GlStateManager.rotate(-rx, 1F, 0F, 0F);
GlStateManager.rotate(-rz, 0F, 0F, 1F);
}
GlStateManager.color(1F, 1F, 1F);
GlStateManager.popMatrix();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, lbx, lby);
}
} else if(meta == 1) // Jibril's Halo
renderHalo(player, partialTicks);
}
@SideOnly(Side.CLIENT)
public static void renderHalo(EntityPlayer player, float partialTicks) {
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.disableLighting();
GlStateManager.disableCull();
GlStateManager.color(1F, 1F, 1F, 1F);
Minecraft.getMinecraft().renderEngine.bindTexture(textureHalo);
if(player != null)
Helper.translateToHeadLevel(player);
GlStateManager.translate(0, 1.5F, 0);
GlStateManager.rotate(30, 1, 0, -1);
GlStateManager.translate(-0.1F, -0.5F, -0.1F);
if(player != null)
GlStateManager.rotate(player.ticksExisted + partialTicks, 0, 1, 0);
else GlStateManager.rotate(Botania.proxy.getWorldElapsedTicks(), 0, 1, 0);
Tessellator tes = Tessellator.getInstance();
ShaderHelper.useShader(ShaderHelper.halo);
tes.getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
tes.getBuffer().pos(-0.75, 0, -0.75).tex(0, 0).endVertex();
tes.getBuffer().pos(-0.75, 0, 0.75).tex(0, 1).endVertex();
tes.getBuffer().pos(0.75, 0, 0.75).tex(1, 1).endVertex();
tes.getBuffer().pos(0.75, 0, -0.75).tex(1, 0).endVertex();
tes.draw();
ShaderHelper.releaseShader();
GlStateManager.enableLighting();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableCull();
}
@SideOnly(Side.CLIENT)
public static void renderHUD(ScaledResolution resolution, EntityPlayer player, ItemStack stack) {
int u = Math.max(1, stack.getItemDamage()) * 9 - 9;
int v = 0;
Minecraft mc = Minecraft.getMinecraft();
mc.renderEngine.bindTexture(textureHud);
int xo = resolution.getScaledWidth() / 2 + 10;
int x = xo;
int y = resolution.getScaledHeight() - ConfigHandler.flightBarHeight;
if(player.getAir() < 300)
y = resolution.getScaledHeight() - ConfigHandler.flightBarBreathHeight;
int left = ItemNBTHelper.getInt(stack, TAG_TIME_LEFT, MAX_FLY_TIME);
int segTime = MAX_FLY_TIME / 10;
int segs = left / segTime + 1;
int last = left % segTime;
for(int i = 0; i < segs; i++) {
float trans = 1F;
if(i == segs - 1) {
trans = (float) last / (float) segTime;
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.disableAlpha();
}
GlStateManager.color(1F, 1F, 1F, trans);
RenderHelper.drawTexturedModalRect(x, y, 0, u, v, 9, 9);
x += 8;
}
if(player.capabilities.isFlying) {
int width = ItemNBTHelper.getInt(stack, TAG_DASH_COOLDOWN, 0);
GlStateManager.color(1F, 1F, 1F, 1F);
if(width > 0)
Gui.drawRect(xo, y - 2, xo + 80, y - 1, 0x88000000);
Gui.drawRect(xo, y - 2, xo + width, y - 1, 0xFFFFFFFF);
}
GlStateManager.enableAlpha();
GlStateManager.color(1F, 1F, 1F, 1F);
mc.renderEngine.bindTexture(Gui.ICONS);
}
@Override
public Achievement getAchievementOnCraft(ItemStack stack, EntityPlayer player, IInventory matrix) {
return stack.getItemDamage() == 1 ? ModAchievements.tiaraWings : null;
}
@SideOnly(Side.CLIENT)
@Override
public void registerModels() {
ModelHandler.registerItemAllMeta(this, WING_TYPES);
}
}