package crazypants.enderio.item.darksteel;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityClientPlayerMP;
import net.minecraft.client.particle.EntityReddustFX;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.IAttributeInstance;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovementInput;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import org.lwjgl.opengl.GL11;
import cofh.api.energy.IEnergyContainerItem;
import com.enderio.core.common.util.Util;
import com.enderio.core.common.vecmath.VecmathUtil;
import com.enderio.core.common.vecmath.Vector3d;
import com.enderio.core.common.vecmath.Vector4d;
import com.mojang.authlib.GameProfile;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import crazypants.enderio.EnderIO;
import crazypants.enderio.config.Config;
import crazypants.enderio.item.darksteel.PacketUpgradeState.Type;
import crazypants.enderio.item.darksteel.upgrade.EnergyUpgrade;
import crazypants.enderio.item.darksteel.upgrade.GliderUpgrade;
import crazypants.enderio.item.darksteel.upgrade.IDarkSteelUpgrade;
import crazypants.enderio.item.darksteel.upgrade.IRenderUpgrade;
import crazypants.enderio.item.darksteel.upgrade.JumpUpgrade;
import crazypants.enderio.item.darksteel.upgrade.NightVisionUpgrade;
import crazypants.enderio.item.darksteel.upgrade.SolarUpgrade;
import crazypants.enderio.item.darksteel.upgrade.SpeedUpgrade;
import crazypants.enderio.item.darksteel.upgrade.SwimUpgrade;
import crazypants.enderio.machine.solar.TileEntitySolarPanel;
import crazypants.enderio.network.PacketHandler;
public class DarkSteelController {
public static final DarkSteelController instance = new DarkSteelController();
private final AttributeModifier[] walkModifiers = new AttributeModifier[] {
new AttributeModifier(new UUID(12879874982l, 320981923), "generic.movementSpeed", SpeedUpgrade.WALK_MULTIPLIERS[0], 1),
new AttributeModifier(new UUID(12879874982l, 320981923), "generic.movementSpeed", SpeedUpgrade.WALK_MULTIPLIERS[1], 1),
new AttributeModifier(new UUID(12879874982l, 320981923), "generic.movementSpeed", SpeedUpgrade.WALK_MULTIPLIERS[2], 1),
};
private final AttributeModifier[] sprintModifiers = new AttributeModifier[] {
new AttributeModifier(new UUID(12879874982l, 320981923), "generic.movementSpeed", SpeedUpgrade.SPRINT_MULTIPLIERS[0], 1),
new AttributeModifier(new UUID(12879874982l, 320981923), "generic.movementSpeed", SpeedUpgrade.SPRINT_MULTIPLIERS[1], 1),
new AttributeModifier(new UUID (12879874982l, 320981923), "generic.movementSpeed", SpeedUpgrade.SPRINT_MULTIPLIERS[2], 1),
};
private final AttributeModifier swordDamageModifierPowered = new AttributeModifier(new UUID(63242325, 320981923), "Weapon modifier",
2, 0);
private boolean wasJumping;
private int jumpCount;
private int ticksSinceLastJump;
private static final EnumSet<Type> DEFAULT_ACTIVE = EnumSet.of(Type.SPEED, Type.STEP_ASSIST, Type.JUMP);
private final Map<UUID, EnumSet<Type>> allActive = new HashMap<UUID, EnumSet<Type>>();
private boolean nightVisionActive = false;
private boolean removeNightvision = false;
private DarkSteelController() {
PacketHandler.INSTANCE.registerMessage(PacketDarkSteelPowerPacket.class, PacketDarkSteelPowerPacket.class, PacketHandler.nextID(), Side.SERVER);
PacketHandler.INSTANCE.registerMessage(PacketUpgradeState.class, PacketUpgradeState.class, PacketHandler.nextID(), Side.SERVER);
PacketHandler.INSTANCE.registerMessage(PacketUpgradeState.class, PacketUpgradeState.class, PacketHandler.nextID(), Side.CLIENT);
}
private EnumSet<Type> getActiveSet(EntityPlayer player) {
EnumSet<Type> active;
GameProfile gameProfile = player.getGameProfile();
UUID id = gameProfile == null ? null : gameProfile.getId();
active = id == null ? null : allActive.get(id);
if(active == null) {
active = DEFAULT_ACTIVE.clone();
if(id != null) {
allActive.put(id, active);
}
}
return active;
}
public boolean isActive(EntityPlayer player, Type type) {
return getActiveSet(player).contains(type);
}
public void setActive(EntityPlayer player, Type type, boolean isActive) {
EnumSet<Type> set = getActiveSet(player);
if(isActive) {
set.add(type);
} else {
set.remove(type);
}
}
public boolean isGlideActive(EntityPlayer player) {
return isActive(player, Type.GLIDE);
}
public boolean isSpeedActive(EntityPlayer player) {
return isActive(player, Type.SPEED);
}
public boolean isStepAssistActive(EntityPlayer player) {
return isActive(player, Type.STEP_ASSIST);
}
public boolean isJumpActive(EntityPlayer player) {
return isActive(player, Type.JUMP);
}
@SubscribeEvent
public void onPlayerTick(TickEvent.PlayerTickEvent event) {
EntityPlayer player = event.player;
if(event.phase == Phase.START) {
//boots
updateStepHeightAndFallDistance(player);
//leggings
updateSpeed(player);
//sword
updateSword(player);
updateGlide(player);
updateSwim(player);
updateSolar(player);
}
}
private void updateSolar(EntityPlayer player) {
// no processing on client
if (player.worldObj.isRemote) {
return;
}
ItemStack helm = player.getEquipmentInSlot(4);
SolarUpgrade upgrade = SolarUpgrade.loadFromItem(helm);
if(upgrade == null) {
return;
}
int RFperSecond = Math.round((float) upgrade.getRFPerSec() * TileEntitySolarPanel.calculateLightRatio(player.worldObj, MathHelper.floor_double(player.posX), MathHelper.floor_double(player.posY + 1), MathHelper.floor_double(player.posZ)));
int leftover = RFperSecond % 20;
boolean addExtraRF = player.worldObj.getTotalWorldTime() % 20 < leftover;
int toAdd = (RFperSecond / 20) + (addExtraRF ? 1 : 0);
if(toAdd != 0) {
int nextIndex = player.getEntityData().getInteger("dsarmor:solar") % 4;
for (int i = 0; i < 4 && toAdd > 0; i++) {
ItemStack stack = player.inventory.armorInventory[nextIndex];
if(stack != null && (EnergyUpgrade.loadFromItem(stack) != null || (Config.darkSteelSolarChargeOthers && stack.getItem() instanceof IEnergyContainerItem))) {
toAdd -= ((IEnergyContainerItem) stack.getItem()).receiveEnergy(stack, toAdd, false);
}
nextIndex = (nextIndex + 1) % 4;
}
player.getEntityData().setInteger("dsarmor:solar", nextIndex);
}
}
private void updateSwim(EntityPlayer player) {
ItemStack boots = player.getEquipmentInSlot(1);
SwimUpgrade upgrade = SwimUpgrade.loadFromItem(boots);
if(upgrade == null) {
return;
}
if(player.isInWater() && !player.capabilities.isFlying) {
player.motionX *= 1.1;
player.motionZ *= 1.1;
}
}
private void updateGlide(EntityPlayer player) {
if(!isGlideActive(player) || !isGliderUpgradeEquipped(player)) {
return;
}
if(!player.onGround && player.motionY < 0 && !player.isSneaking() && !player.isInWater()) {
double horizontalSpeed = Config.darkSteelGliderHorizontalSpeed;
double verticalSpeed = Config.darkSteelGliderVerticalSpeed;
if(player.isSprinting()) {
verticalSpeed = Config.darkSteelGliderVerticalSpeedSprinting;
}
Vector3d look = Util.getLookVecEio(player);
Vector3d side = new Vector3d();
side.cross(new Vector3d(0, 1, 0), look);
Vector3d playerPos = new Vector3d(player.prevPosX, player.prevPosY, player.prevPosZ);
Vector3d b = new Vector3d(playerPos);
b.y += 1;
Vector3d c = new Vector3d(playerPos);
c.add(side);
Vector4d plane = new Vector4d();
VecmathUtil.computePlaneEquation(playerPos, b, c, plane);
double dist = Math.abs(VecmathUtil.distanceFromPointToPlane(plane, new Vector3d(player.posX, player.posY, player.posZ)));
double minDist = 0.15;
if(dist < minDist) {
double dropRate = (minDist * 10) - (dist * 10);
verticalSpeed = verticalSpeed + (verticalSpeed * dropRate * 8);
horizontalSpeed -= (0.02 * dropRate);
}
double x = Math.cos(Math.toRadians(player.rotationYawHead + 90))
* horizontalSpeed;
double z = Math.sin(Math.toRadians(player.rotationYawHead + 90))
* horizontalSpeed;
player.motionX += x;
player.motionZ += z;
player.motionY = verticalSpeed;
player.fallDistance = 0f;
}
}
public boolean isGliderUpgradeEquipped(EntityPlayer player) {
ItemStack chestPlate = player.getEquipmentInSlot(3);
GliderUpgrade glideUpgrade = GliderUpgrade.loadFromItem(chestPlate);
if(glideUpgrade == null) {
return false;
}
return true;
}
private void updateSword(EntityPlayer player) {
if(ItemDarkSteelSword.isEquipped(player)) {
IAttributeInstance attackInst = player.getAttributeMap().getAttributeInstance(SharedMonsterAttributes.attackDamage);
attackInst.removeModifier(swordDamageModifierPowered);
ItemStack sword = player.getCurrentEquippedItem();
if(Config.darkSteelSwordPowerUsePerHit <= 0 || EnergyUpgrade.getEnergyStored(sword) >= Config.darkSteelSwordPowerUsePerHit) {
attackInst.applyModifier(swordDamageModifierPowered);
}
}
}
private void updateSpeed(EntityPlayer player) {
if(player.worldObj.isRemote || !player.onGround) {
return;
}
IAttributeInstance moveInst = player.getAttributeMap().getAttributeInstance(SharedMonsterAttributes.movementSpeed);
if(moveInst.getModifier(walkModifiers[0].getID()) != null) {
moveInst.removeModifier(walkModifiers[0]); //any will so as they all have the same UID
} else if(moveInst.getModifier(sprintModifiers[0].getID()) != null) {
moveInst.removeModifier(sprintModifiers[0]);
}
ItemStack leggings = player.getEquipmentInSlot(2);
SpeedUpgrade speedUpgrade = SpeedUpgrade.loadFromItem(leggings);
if(leggings != null && leggings.getItem() == DarkSteelItems.itemDarkSteelLeggings && speedUpgrade != null && isSpeedActive(player)) {
double horzMovement = Math.abs(player.distanceWalkedModified - player.prevDistanceWalkedModified);
double costModifier = player.isSprinting() ? Config.darkSteelSprintPowerCost : Config.darkSteelWalkPowerCost;
costModifier = costModifier + (costModifier * speedUpgrade.getWalkMultiplier());
int cost = (int) (horzMovement * costModifier);
int totalEnergy = getPlayerEnergy(player, DarkSteelItems.itemDarkSteelLeggings);
if(totalEnergy > 0) {
usePlayerEnergy(player, DarkSteelItems.itemDarkSteelLeggings, cost);
if(player.isSprinting()) {
moveInst.applyModifier(sprintModifiers[speedUpgrade.getLevel() - 1]);
} else {
moveInst.applyModifier(walkModifiers[speedUpgrade.getLevel() - 1]);
}
}
}
}
private void updateStepHeightAndFallDistance(EntityPlayer player) {
ItemStack boots = player.getEquipmentInSlot(1);
if(boots != null && boots.getItem() == DarkSteelItems.itemDarkSteelBoots && !player.capabilities.allowFlying) {
int costedDistance = (int) player.fallDistance;
if(costedDistance > 0) {
int energyCost = costedDistance * Config.darkSteelFallDistanceCost;
int totalEnergy = getPlayerEnergy(player, DarkSteelItems.itemDarkSteelBoots);
if(totalEnergy > 0 && totalEnergy >= energyCost) {
usePlayerEnergy(player, DarkSteelItems.itemDarkSteelBoots, energyCost);
player.fallDistance -= costedDistance;
}
}
}
JumpUpgrade jumpUpgrade = JumpUpgrade.loadFromItem(boots);
if(jumpUpgrade != null && boots != null && boots.getItem() == DarkSteelItems.itemDarkSteelBoots && isStepAssistActive(player)) {
player.stepHeight = 1.0023F;
} else if(player.stepHeight == 1.0023F) {
player.stepHeight = 0.5001F;
}
}
void usePlayerEnergy(EntityPlayer player, ItemDarkSteelArmor armor, int cost) {
if(cost == 0) {
return;
}
int remaining = cost;
if(Config.darkSteelDrainPowerFromInventory) {
for (ItemStack stack : player.inventory.mainInventory) {
if(stack != null && stack.getItem() instanceof IEnergyContainerItem) {
IEnergyContainerItem cont = (IEnergyContainerItem) stack.getItem();
int used = cont.extractEnergy(stack, remaining, false);
remaining -= used;
if(remaining <= 0) {
return;
}
}
}
}
if(armor != null && remaining > 0) {
ItemStack stack = player.inventory.armorInventory[3 - armor.armorType];
if(stack != null) {
armor.extractEnergy(stack, remaining, false);
}
}
}
private int getPlayerEnergy(EntityPlayer player, ItemDarkSteelArmor armor) {
int res = 0;
if(Config.darkSteelDrainPowerFromInventory) {
for (ItemStack stack : player.inventory.mainInventory) {
if(stack != null && stack.getItem() instanceof IEnergyContainerItem) {
IEnergyContainerItem cont = (IEnergyContainerItem) stack.getItem();
res += cont.extractEnergy(stack, Integer.MAX_VALUE, true);
}
}
}
if(armor != null) {
ItemStack stack = player.inventory.armorInventory[3 - armor.armorType];
res = armor.getEnergyStored(stack);
}
return res;
}
@SubscribeEvent
public void onStartTracking(PlayerEvent.StartTracking event) {
if (event.target instanceof EntityPlayerMP) {
for (PacketUpgradeState.Type type : PacketUpgradeState.Type.values()) {
PacketHandler.sendTo(new PacketUpgradeState(type, isActive((EntityPlayer) event.target, type), event.target.getEntityId()), (EntityPlayerMP) event.entityPlayer);
}
}
}
@SideOnly(Side.CLIENT)
@SubscribeEvent
public void onClientTick(TickEvent.ClientTickEvent event) {
if(event.phase == TickEvent.Phase.END) {
EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer;
if (player == null) {
return;
}
updateNightvision(player);
if (player.capabilities.isFlying) {
return;
}
MovementInput input = player.movementInput;
if(input.jump && !wasJumping) {
doJump(player);
} else if(input.jump && jumpCount < 3 && ticksSinceLastJump > 5) {
doJump(player);
}
wasJumping = !player.onGround;
if(!wasJumping) {
jumpCount = 0;
}
ticksSinceLastJump++;
}
}
@SideOnly(Side.CLIENT)
@SubscribeEvent
public void onPlayerRender(RenderPlayerEvent.Specials.Post event) {
if (event.entityLiving.getActivePotionEffect(Potion.invisibility) != null) {
return;
}
EntityPlayer player = event.entityPlayer;
ItemStack[] armors = player.inventory.armorInventory;
dispatchRenders(armors, event, false);
float yaw = player.prevRotationYawHead + (player.rotationYawHead - player.prevRotationYawHead) * event.partialRenderTick;
float yawOffset = player.prevRenderYawOffset + (player.renderYawOffset - player.prevRenderYawOffset) * event.partialRenderTick;
float pitch = player.prevRotationPitch + (player.rotationPitch - player.prevRotationPitch) * event.partialRenderTick;
GL11.glPushMatrix();
if(player.isSneaking()) {
GL11.glTranslatef(0, 0.0625f, 0);
}
GL11.glRotatef(yawOffset, 0, -1, 0);
GL11.glRotatef(yaw - 270, 0, 1, 0);
GL11.glRotatef(pitch, 0, 0, 1);
dispatchRenders(armors, event, true);
GL11.glPopMatrix();
}
private void dispatchRenders(ItemStack[] armors, RenderPlayerEvent event, boolean head) {
for (int i = 0; i < armors.length; i++) {
ItemStack stack = armors[i];
if (stack != null) {
Item item = stack.getItem();
if (item instanceof IDarkSteelItem) {
for (IDarkSteelUpgrade upg : DarkSteelRecipeManager.instance.getUpgrades()) {
if (upg.hasUpgrade(stack)) {
GL11.glPushMatrix();
GL11.glColor4f(1F, 1F, 1F, 1F);
IRenderUpgrade render = upg.getRender();
if (render != null) {
upg.getRender().render(event, stack, head);
}
GL11.glPopMatrix();
}
}
}
}
}
}
@SideOnly(Side.CLIENT)
private void doJump(EntityClientPlayerMP player) {
if (!isJumpActive(player)) {
return;
}
ItemStack boots = player.getEquipmentInSlot(1);
JumpUpgrade jumpUpgrade = JumpUpgrade.loadFromItem(boots);
if(jumpUpgrade == null || boots == null || boots.getItem() != DarkSteelItems.itemDarkSteelBoots) {
return;
}
int requiredPower = Config.darkSteelBootsJumpPowerCost * (int) Math.pow(jumpCount + 1, 2.5);
int availablePower = getPlayerEnergy(player, DarkSteelItems.itemDarkSteelBoots);
if(availablePower > 0 && requiredPower <= availablePower && jumpCount < jumpUpgrade.getLevel()) {
jumpCount++;
player.motionY += 0.15 * Config.darkSteelBootsJumpModifier * jumpCount;
ticksSinceLastJump = 0;
usePlayerEnergy(player, DarkSteelItems.itemDarkSteelBoots, requiredPower);
player.worldObj.playSound(player.posX, player.posY, player.posZ, EnderIO.MODID + ":ds.jump", 1.0f, player.worldObj.rand.nextFloat() * 0.5f + 0.75f, false);
Random rand = player.worldObj.rand;
for (int i = rand.nextInt(10) + 5; i >= 0; i--) {
EntityReddustFX fx = new EntityReddustFX(player.worldObj, player.posX + (rand.nextDouble() * 0.5 - 0.25), player.posY - player.yOffset, player.posZ
+ (rand.nextDouble() * 0.5 - 0.25), 1, 1, 1);
fx.setVelocity(player.motionX + (rand.nextDouble() * 0.5 - 0.25), (player.motionY / 2) + (rand.nextDouble() * -0.05),
player.motionZ + (rand.nextDouble() * 0.5 - 0.25));
Minecraft.getMinecraft().effectRenderer.addEffect(fx);
}
PacketHandler.INSTANCE.sendToServer(new PacketDarkSteelPowerPacket(requiredPower, DarkSteelItems.itemDarkSteelBoots.armorType));
}
}
private void updateNightvision(EntityPlayer player) {
if(isNightVisionUpgradeEquipped(player) && nightVisionActive) {
player.addPotionEffect(new PotionEffect(Potion.nightVision.getId(), 210, 0, true));
}
if(!isNightVisionUpgradeEquipped(player) && nightVisionActive) {
nightVisionActive = false;
removeNightvision = true;
}
if(removeNightvision) {
player.removePotionEffect(Potion.nightVision.getId());
removeNightvision = false;
}
}
public boolean isNightVisionUpgradeEquipped(EntityPlayer player) {
ItemStack helmet = player.getEquipmentInSlot(4);
return NightVisionUpgrade.loadFromItem(helmet) != null;
}
public void setNightVisionActive(boolean isNightVisionActive) {
if(nightVisionActive && !isNightVisionActive) {
removeNightvision = true;
}
this.nightVisionActive = isNightVisionActive;
}
public boolean isNightVisionActive() {
return nightVisionActive;
}
}