package pneumaticCraft.common.minigun;
import java.util.List;
import java.util.Random;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import org.lwjgl.opengl.GL11;
import pneumaticCraft.api.item.IPressurizable;
import pneumaticCraft.client.render.RenderProgressingLine;
import pneumaticCraft.client.util.RenderUtils;
import pneumaticCraft.common.config.Config;
import pneumaticCraft.common.item.ItemGunAmmo;
import pneumaticCraft.common.util.PneumaticCraftUtils;
import pneumaticCraft.lib.Sounds;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public abstract class Minigun{
private final boolean requiresTarget;
private final double raytraceRange = 50;
private double minigunSpeed;
private int minigunTriggerTimeOut;
public static final double MAX_GUN_SPEED = 0.4;
private static final double MAX_GUN_YAW_CHANGE = 10;
private static final double MAX_GUN_PITCH_CHANGE = 10;
private int minigunSoundCounter = -1;
private final Random rand = new Random();
private double minigunRotation, oldMinigunRotation;
public double minigunYaw, oldMinigunYaw;
public double minigunPitch, oldMinigunPitch;
private final RenderProgressingLine minigunFire = new RenderProgressingLine().setProgress(1);
private boolean sweeping; //When true, the yaw of the minigun will sweep with a sinus pattern when not targeting.
private double sweepingProgress;
private boolean gunAimedAtTarget;
protected IPressurizable pressurizable;
private int airUsage;
protected ItemStack stack, ammo;
protected EntityPlayer player;
protected World world;
protected EntityLivingBase attackTarget;
public Minigun(boolean requiresTarget){
this.requiresTarget = requiresTarget;
}
public Minigun setPressurizable(IPressurizable pressurizable, int airUsage){
this.pressurizable = pressurizable;
this.airUsage = airUsage;
return this;
}
public Minigun setItemStack(ItemStack stack){
this.stack = stack;
return this;
}
public Minigun setAmmo(ItemStack ammo){
this.ammo = ammo;
return this;
}
public Minigun setPlayer(EntityPlayer player){
this.player = player;
return this;
}
public Minigun setWorld(World world){
this.world = world;
return this;
}
public Minigun setAttackTarget(EntityLivingBase entity){
attackTarget = entity;
return this;
}
public abstract boolean isMinigunActivated();
public abstract void setMinigunActivated(boolean activated);
public abstract void setAmmoColorStack(ItemStack ammo);
public abstract int getAmmoColor();
public abstract void playSound(String soundName, float volume, float pitch);
protected int getAmmoColor(ItemStack stack){
return stack != null ? stack.getItem().getColorFromItemStack(stack, 1) : 0xFF313131;
}
public double getMinigunSpeed(){
return minigunSpeed;
}
public void setMinigunSpeed(double minigunSpeed){
this.minigunSpeed = minigunSpeed;
}
public int getMinigunTriggerTimeOut(){
return minigunTriggerTimeOut;
}
public void setMinigunTriggerTimeOut(int minigunTriggerTimeOut){
this.minigunTriggerTimeOut = minigunTriggerTimeOut;
}
public int getMinigunSoundCounter(){
return minigunSoundCounter;
}
public void setMinigunSoundCounter(int minigunSoundCounter){
this.minigunSoundCounter = minigunSoundCounter;
}
public double getMinigunRotation(){
return minigunRotation;
}
public void setMinigunRotation(double minigunRotation){
this.minigunRotation = minigunRotation;
}
public double getOldMinigunRotation(){
return oldMinigunRotation;
}
public void setOldMinigunRotation(double oldMinigunRotation){
this.oldMinigunRotation = oldMinigunRotation;
}
public EntityLivingBase getAttackTarget(){
return attackTarget;
}
public void setSweeping(boolean sweeping){
this.sweeping = sweeping;
}
public boolean isSweeping(){
return sweeping;
}
public boolean tryFireMinigun(EntityLivingBase target){
boolean lastShotOfAmmo = false;
if(ammo != null && (pressurizable == null || pressurizable.getPressure(stack) > 0)) {
setMinigunTriggerTimeOut(Math.max(10, getMinigunSoundCounter()));
if(getMinigunSpeed() == MAX_GUN_SPEED && (!requiresTarget || gunAimedAtTarget)) {
if(!requiresTarget) target = raytraceTarget();
lastShotOfAmmo = ammo.attemptDamageItem(1, rand);
if(pressurizable != null) pressurizable.addAir(stack, -airUsage);
if(target != null) {
ItemStack potion = ItemGunAmmo.getPotion(ammo);
if(potion != null) {
if(rand.nextInt(20) == 0) {
List<PotionEffect> effects = Items.potionitem.getEffects(potion);
if(effects != null) {
for(PotionEffect effect : effects) {
target.addPotionEffect(new PotionEffect(effect));
}
}
}
} else {
target.attackEntityFrom(DamageSource.causePlayerDamage(player), Config.configMinigunDamage);
}
}
}
}
return lastShotOfAmmo;
}
private EntityLivingBase raytraceTarget(){
MovingObjectPosition mop = PneumaticCraftUtils.getMouseOverServer(player, raytraceRange);
return mop != null && mop.entityHit instanceof EntityLivingBase ? (EntityLivingBase)mop.entityHit : null;
}
public void update(double posX, double posY, double posZ){
setOldMinigunRotation(getMinigunRotation());
oldMinigunYaw = minigunYaw;
oldMinigunPitch = minigunPitch;
if(attackTarget != null && attackTarget.isDead) attackTarget = null;
if(!world.isRemote) {
setMinigunActivated(getMinigunTriggerTimeOut() > 0);
setAmmoColorStack(ammo);
if(getMinigunTriggerTimeOut() > 0) {
setMinigunTriggerTimeOut(getMinigunTriggerTimeOut() - 1);
if(getMinigunSpeed() == 0) {
playSound(Sounds.HUD_INIT, 2, 0.9F);
}
}
if(getMinigunSoundCounter() == 0 && getMinigunTriggerTimeOut() == 0) {
playSound(Sounds.MINIGUN_STOP, 3, 0.5F);
setMinigunSoundCounter(-1);
}
}
if(isMinigunActivated()) {
setMinigunSpeed(Math.min(getMinigunSpeed() + 0.01D, MAX_GUN_SPEED));
} else {
setMinigunSpeed(Math.max(0, getMinigunSpeed() - 0.003D));
}
setMinigunRotation(getMinigunRotation() + getMinigunSpeed());
double targetYaw = 0;
double targetPitch = 0;
if(attackTarget != null) {
double deltaX = posX - attackTarget.posX;
double deltaZ = posZ - attackTarget.posZ;
if(deltaX >= 0 && deltaZ < 0) {
targetYaw = Math.atan(Math.abs(deltaX / deltaZ)) / Math.PI * 180D;
} else if(deltaX >= 0 && deltaZ >= 0) {
targetYaw = Math.atan(Math.abs(deltaZ / deltaX)) / Math.PI * 180D + 90;
} else if(deltaX < 0 && deltaZ >= 0) {
targetYaw = Math.atan(Math.abs(deltaX / deltaZ)) / Math.PI * 180D + 180;
} else {
targetYaw = Math.atan(Math.abs(deltaZ / deltaX)) / Math.PI * 180D + 270;
}
if(targetYaw - minigunYaw > 180) {
targetYaw -= 360;
} else if(minigunYaw - targetYaw > 180) {
targetYaw += 360;
}
targetPitch = Math.toDegrees(Math.atan((posY - attackTarget.posY - attackTarget.height / 2) / PneumaticCraftUtils.distBetween(posX, posZ, attackTarget.posX, attackTarget.posZ)));
if(minigunPitch > targetPitch) {
if(minigunPitch - MAX_GUN_PITCH_CHANGE > targetPitch) {
minigunPitch -= MAX_GUN_PITCH_CHANGE;
} else {
minigunPitch = targetPitch;
}
} else {
if(minigunPitch + MAX_GUN_PITCH_CHANGE < targetPitch) {
minigunPitch += MAX_GUN_PITCH_CHANGE;
} else {
minigunPitch = targetPitch;
}
}
if(minigunPitch < -80 || minigunPitch > 80) {
minigunYaw = targetYaw;
} else {
if(minigunYaw > targetYaw) {
if(minigunYaw - MAX_GUN_YAW_CHANGE > targetYaw) {
minigunYaw -= MAX_GUN_YAW_CHANGE;
} else {
minigunYaw = targetYaw;
}
} else {
if(minigunYaw + MAX_GUN_YAW_CHANGE < targetYaw) {
minigunYaw += MAX_GUN_YAW_CHANGE;
} else {
minigunYaw = targetYaw;
}
}
}
gunAimedAtTarget = minigunYaw == targetYaw && minigunPitch == targetPitch;
} else if(isSweeping()) {
minigunYaw -= Math.cos(sweepingProgress) * 22;
sweepingProgress += 0.05D;
minigunYaw += Math.cos(sweepingProgress) * 22;
if(minigunPitch > targetPitch) {
if(minigunPitch - MAX_GUN_PITCH_CHANGE > targetPitch) {
minigunPitch -= MAX_GUN_PITCH_CHANGE;
} else {
minigunPitch = targetPitch;
}
} else {
if(minigunPitch + MAX_GUN_PITCH_CHANGE < targetPitch) {
minigunPitch += MAX_GUN_PITCH_CHANGE;
} else {
minigunPitch = targetPitch;
}
}
}
if(!world.isRemote && isMinigunActivated() && getMinigunSpeed() == MAX_GUN_SPEED && (!requiresTarget || gunAimedAtTarget && attackTarget != null)) {
if(getMinigunSoundCounter() <= 0) {
playSound(Sounds.MINIGUN, 0.3F, 1);
setMinigunSoundCounter(20);
}
}
if(getMinigunSoundCounter() > 0) setMinigunSoundCounter(getMinigunSoundCounter() - 1);
}
@SideOnly(Side.CLIENT)
public void render(double x, double y, double z, double gunRadius){
if(isMinigunActivated() && getMinigunSpeed() == MAX_GUN_SPEED && gunAimedAtTarget && attackTarget != null) {
GL11.glPushMatrix();
GL11.glScaled(1, 1, 1);
GL11.glTranslated(-x, -y, -z);
GL11.glDisable(GL11.GL_TEXTURE_2D);
//GL11.glDisable(GL11.GL_LIGHTING);
RenderUtils.glColorHex(0xFF000000 | getAmmoColor());
for(int i = 0; i < 5; i++) {
Vec3 vec = Vec3.createVectorHelper(attackTarget.posX - x, attackTarget.posY - y, attackTarget.posZ - z).normalize();
minigunFire.startX = x + vec.xCoord * gunRadius;
minigunFire.startY = y + vec.yCoord * gunRadius;
minigunFire.startZ = z + vec.zCoord * gunRadius;
minigunFire.endX = attackTarget.posX + rand.nextDouble() - 0.5;
minigunFire.endY = attackTarget.posY + attackTarget.height / 2 + rand.nextDouble() - 0.5;
minigunFire.endZ = attackTarget.posZ + rand.nextDouble() - 0.5;
minigunFire.render();
}
GL11.glColor4d(1, 1, 1, 1);
// GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glPopMatrix();
}
}
}