package com.flansmod.common.guns;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.netty.buffer.ByteBuf;
import org.lwjgl.input.Mouse;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.BlockPos;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import com.flansmod.common.FlansMod;
import com.flansmod.common.PlayerHandler;
import com.flansmod.common.network.PacketMGFire;
import com.flansmod.common.network.PacketMGMount;
import com.flansmod.common.network.PacketPlaySound;
import com.flansmod.common.teams.EntityGunItem;
import com.flansmod.common.teams.Team;
import com.flansmod.common.teams.TeamsManager;
public class EntityMG extends Entity implements IEntityAdditionalSpawnData
{
public int blockX, blockY, blockZ;
public int direction;
public GunType type;
public ItemStack ammo;
public int reloadTimer;
public int soundDelay;
public float shootDelay;
public static List<EntityMG> mgs = new ArrayList<EntityMG>();
public EntityPlayer gunner;
//Server side
public boolean isShooting;
//Client side
public boolean wasShooting = false;
public int ticksSinceUsed = 0;
public EntityMG(World world)
{
super(world);
setSize(1.0F, 1.0F);
ignoreFrustumCheck = true;
}
public EntityMG(World world, int x, int y, int z, int dir, GunType gunType)
{
super(world);
setSize(1.0F, 1.0F);
blockX = x;
blockY = y;
blockZ = z;
prevPosX = x + 0.5D;
prevPosY = y;
prevPosZ = z + 0.5D;
setPosition(x + 0.5D, y, z + 0.5D);
direction = dir;
rotationYaw = 0;
rotationPitch = -60;
type = gunType;
ignoreFrustumCheck = true;
mgs.add(this);
}
@Override
public boolean canBeCollidedWith()
{
return !isDead;
}
@Override
public void onUpdate()
{
super.onUpdate();
prevPosX = posX = blockX + 0.5f;
prevPosY = posY = blockY;
prevPosZ = posZ = blockZ + 0.5f;
ticksSinceUsed++;
if(TeamsManager.mgLife > 0 && ticksSinceUsed > TeamsManager.mgLife * 20)
{
setDead();
}
if (worldObj.getBlockState(new BlockPos(blockX, blockY - 1, blockZ)).getBlock() == Blocks.air)
{
if(!worldObj.isRemote)
{
setDead();
}
}
prevRotationYaw = rotationYaw;
prevRotationPitch = rotationPitch;
if (gunner != null)
{
ticksSinceUsed = 0;
rotationYaw = gunner.rotationYaw - direction * 90;
for (; rotationYaw < -180; rotationYaw += 360)
{
}
for (; rotationYaw > 180; rotationYaw -= 360)
{
}
rotationPitch = gunner.rotationPitch;
// Keep it within reasonable angles
if (rotationYaw > type.sideViewLimit)
prevRotationYaw = rotationYaw = type.sideViewLimit;
if (rotationYaw < -type.sideViewLimit)
prevRotationYaw = rotationYaw = -type.sideViewLimit;
// Keep user standing behind the gun
float angle = direction * 90F + rotationYaw;
double dX = (type.standBackDist * Math.sin(angle * 3.1415926535F / 180F));
double dZ = -(type.standBackDist * Math.cos(angle * 3.1415926535F / 180F));
gunner.setPosition((blockX + 0.5D + dX), blockY + gunner.getYOffset() - 0.5D, (blockZ + 0.5D + dZ));
// gunner.setPosition((double)(blockX + (direction == 1 ? 1 : 0) -
// (direction == 3 ? 1 : 0)) + 0.5D, blockY + gunner.getYOffset() -
// 0.5D, (double)(blockZ - (direction == 0 ? 1 : 0) + (direction ==
// 2 ? 1 : 0)) + 0.5D);
} else
{
rotationPitch--;
}
if (rotationPitch < type.topViewLimit)
rotationPitch = type.topViewLimit;
if (rotationPitch > type.bottomViewLimit)
rotationPitch = type.bottomViewLimit;
if(shootDelay > 0)
shootDelay--;
// Decrement the reload timer and reload
if (reloadTimer > 0)
reloadTimer--;
if (ammo != null && ammo.getItemDamage() == ammo.getMaxDamage())
{
ammo = null;
// Scrap metal output?
}
if (ammo == null && gunner != null)
{
int slot = findAmmo(gunner);
if (slot >= 0)
{
ammo = gunner.inventory.getStackInSlot(slot);
if (!gunner.capabilities.isCreativeMode)
gunner.inventory.setInventorySlotContents(slot, null);
reloadTimer = type.reloadTime;
PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.reloadSound, false);
}
}
if (worldObj.isRemote && gunner != null && gunner == FMLClientHandler.instance().getClient().thePlayer && type.mode == EnumFireMode.FULLAUTO)
{
//Send a packet!
checkForShooting();
}
if(!worldObj.isRemote && isShooting)
{
if(gunner == null || gunner.isDead)
isShooting = false;
// Check for ammo / reloading
if (ammo == null || reloadTimer > 0 || shootDelay > 0)
{
return;
}
// Fire
BulletType bullet = BulletType.getBullet(ammo.getItem());
if (gunner != null && !gunner.capabilities.isCreativeMode)
ammo.damageItem(1, gunner);
shootDelay = type.shootDelay;
worldObj.spawnEntityInWorld(((ItemBullet)ammo.getItem()).getEntity(worldObj,
new Vec3(blockX + 0.5D, blockY + type.pivotHeight, blockZ + 0.5D),
(direction * 90F + rotationYaw),
rotationPitch,
gunner,
bullet.bulletSpread * type.bulletSpread,
type.damage,
type));
if (soundDelay <= 0)
{
soundDelay = type.shootSoundLength;
PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound, type.distortSound);
}
}
if (soundDelay > 0)
soundDelay--;
}
@SideOnly(Side.CLIENT)
private void checkForShooting()
{
if(Mouse.isButtonDown(0) && !wasShooting && !FlansMod.proxy.isScreenOpen())
{
FlansMod.getPacketHandler().sendToServer(new PacketMGFire(true));
wasShooting = true;
}
else if(!Mouse.isButtonDown(0) && wasShooting)
{
FlansMod.getPacketHandler().sendToServer(new PacketMGFire(false));
wasShooting = false;
}
}
//Server side setter to be called upon receiving a packet
public void mouseHeld(boolean held)
{
isShooting = held;
}
@Override
public boolean attackEntityFrom(DamageSource damagesource, float i)
{
if (damagesource.damageType.equals("player"))
{
Entity player = damagesource.getEntity();
if (player == gunner)
{
// Player left clicked on the gun
if (type.mode == EnumFireMode.FULLAUTO)
return true;
// Check for ammo / reloading
if (ammo == null || reloadTimer > 0 || shootDelay > 0)
{
return true;
}
// Fire
BulletType bullet = BulletType.getBullet(ammo.getItem());
if (gunner != null && !gunner.capabilities.isCreativeMode)
ammo.damageItem(1, (EntityLiving) player);
shootDelay = type.shootDelay;
if (!worldObj.isRemote)
{
worldObj.spawnEntityInWorld(((ItemBullet)ammo.getItem()).getEntity(worldObj,
(EntityLivingBase) player,
bullet.bulletSpread * type.bulletSpread,
type.damage,
type.bulletSpeed,
false,
type));
}
if (soundDelay <= 0)
{
float distortion = type.distortSound ? 1.0F / (rand.nextFloat() * 0.4F + 0.8F) : 1F;
//worldObj.playSoundAtEntity(this, type.shootSound, 1.0F, distortion);
PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound, type.distortSound);
soundDelay = type.shootSoundLength;
}
} else if(gunner != null)
{
return gunner.attackEntityFrom(damagesource, i);
} else if(TeamsManager.canBreakGuns)
{
setDead();
}
}
return true;
}
@Override
public boolean interactFirst(EntityPlayer player) //interact : change back when Forge updates
{
// Player right clicked on gun
// Mount gun
if (gunner != null && (gunner instanceof EntityPlayer) && gunner != player)
{
return true;
}
if (!worldObj.isRemote)
{
//If this is the player currently using this MG, dismount
if(gunner == player)
{
mountGun(player, false);
FlansMod.getPacketHandler().sendToAllAround(new PacketMGMount(player, this, false), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension);
return true;
}
//If this person is already mounting a gun, dismount it first
if(PlayerHandler.getPlayerData(player).mountingGun != null && !PlayerHandler.getPlayerData(player).mountingGun.isDead)
{
PlayerHandler.getPlayerData(player).mountingGun.mountGun(player, false);
return true;
}
//Spectators can't mount guns
if(TeamsManager.instance.currentRound != null && PlayerHandler.getPlayerData(player).team == Team.spectators)
return true;
//None of the above applied, so mount the gun
mountGun(player, true);
FlansMod.getPacketHandler().sendToAllAround(new PacketMGMount(player, this, true), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension);
if (ammo == null)
{
int slot = findAmmo(player);
if (slot >= 0)
{
ammo = player.inventory.getStackInSlot(slot);
player.inventory.setInventorySlotContents(slot, null);
reloadTimer = type.reloadTime;
worldObj.playSoundAtEntity(this, type.reloadSound, 1.0F, 1.0F / (rand.nextFloat() * 0.4F + 0.8F));
}
}
}
return true;
}
public void mountGun(EntityPlayer player, boolean mounting)
{
if(player == null)
return;
Side side = worldObj.isRemote ? Side.CLIENT : Side.SERVER;
if(PlayerHandler.getPlayerData(player, side) == null)
return;
if(mounting)
{
gunner = player;
PlayerHandler.getPlayerData(player, side).mountingGun = this;
}
else
{
PlayerHandler.getPlayerData(player, side).mountingGun = null;
gunner = null;
}
}
public int findAmmo(EntityPlayer player)
{
for (int i = 0; i < player.inventory.getSizeInventory(); i++)
{
ItemStack stack = player.inventory.getStackInSlot(i);
if (type.isAmmo(stack))
{
return i;
}
}
return -1;
}
@Override
public void setDead()
{
// Drop gun
if(!worldObj.isRemote)
{
if(TeamsManager.weaponDrops == 2)
{
EntityGunItem gunEntity = new EntityGunItem(worldObj, posX, posY, posZ, new ItemStack(type.getItem()), Arrays.asList(ammo));
worldObj.spawnEntityInWorld(gunEntity);
}
else if(TeamsManager.weaponDrops == 1)
{
dropItem(type.getItem(), 1);
// Drop ammo box
if (ammo != null)
entityDropItem(ammo, 0.5F);
}
}
if (gunner != null && PlayerHandler.getPlayerData(gunner) != null)
PlayerHandler.getPlayerData(gunner).mountingGun = null;
super.setDead();
}
@Override
protected void writeEntityToNBT(NBTTagCompound nbttagcompound)
{
nbttagcompound.setString("Type", type.shortName);
if (ammo != null)
{
nbttagcompound.setTag("Ammo", ammo.writeToNBT(new NBTTagCompound()));
}
nbttagcompound.setInteger("BlockX", blockX);
nbttagcompound.setInteger("BlockY", blockY);
nbttagcompound.setInteger("BlockZ", blockZ);
nbttagcompound.setByte("Dir", (byte) direction);
}
@Override
protected void readEntityFromNBT(NBTTagCompound nbttagcompound)
{
type = GunType.getGun(nbttagcompound.getString("Type"));
blockX = nbttagcompound.getInteger("BlockX");
blockY = nbttagcompound.getInteger("BlockY");
blockZ = nbttagcompound.getInteger("BlockZ");
direction = nbttagcompound.getByte("Dir");
ammo = ItemStack.loadItemStackFromNBT(nbttagcompound.getCompoundTag("Ammo"));
}
@Override
protected void entityInit()
{
}
@Override
public void writeSpawnData(ByteBuf data)
{
ByteBufUtils.writeUTF8String(data, type.shortName);
data.writeInt(direction);
data.writeInt(blockX);
data.writeInt(blockY);
data.writeInt(blockZ);
ByteBufUtils.writeItemStack(data, ammo);
}
@Override
public void readSpawnData(ByteBuf data)
{
try
{
type = GunType.getGun(ByteBufUtils.readUTF8String(data));
direction = data.readInt();
blockX = data.readInt();
blockY = data.readInt();
blockZ = data.readInt();
ammo = ByteBufUtils.readItemStack(data);
}
catch(Exception e)
{
FlansMod.log("Failed to retreive gun type from server.");
super.setDead();
e.printStackTrace();
}
}
@Override
public ItemStack getPickedResult(MovingObjectPosition target)
{
ItemStack stack = new ItemStack(type.item, 1, 0);
return stack;
}
}