package com.flansmod.common.guns;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import com.flansmod.client.FlansModClient;
import com.flansmod.client.FlansModResourceHandler;
import com.flansmod.client.debug.EntityDebugDot;
import com.flansmod.client.debug.EntityDebugVector;
import com.flansmod.client.model.GunAnimations;
import com.flansmod.client.model.InstantBulletRenderer;
import com.flansmod.client.model.GunAnimations.LookAtState;
import com.flansmod.client.model.InstantBulletRenderer.InstantShotTrail;
import com.flansmod.client.model.RenderGun;
import com.flansmod.common.FlansMod;
import com.flansmod.common.PlayerData;
import com.flansmod.common.PlayerHandler;
import com.flansmod.common.RotatedAxes;
import com.flansmod.common.driveables.EntitySeat;
import com.flansmod.common.guns.ShotData.InstantShotData;
import com.flansmod.common.guns.ShotData.SpawnEntityShotData;
import com.flansmod.common.guns.raytracing.EnumHitboxType;
import com.flansmod.common.guns.raytracing.FlansModRaytracer;
import com.flansmod.common.guns.raytracing.PlayerHitbox;
import com.flansmod.common.guns.raytracing.PlayerSnapshot;
import com.flansmod.common.guns.raytracing.FlansModRaytracer.BlockHit;
import com.flansmod.common.guns.raytracing.FlansModRaytracer.BulletHit;
import com.flansmod.common.guns.raytracing.FlansModRaytracer.DriveableHit;
import com.flansmod.common.guns.raytracing.FlansModRaytracer.EntityHit;
import com.flansmod.common.guns.raytracing.FlansModRaytracer.PlayerBulletHit;
import com.flansmod.common.network.PacketGunFire;
import com.flansmod.common.network.PacketPlaySound;
import com.flansmod.common.network.PacketReload;
import com.flansmod.common.network.PacketSelectOffHandGun;
import com.flansmod.common.network.PacketShotData;
import com.flansmod.common.teams.EntityFlag;
import com.flansmod.common.teams.EntityFlagpole;
import com.flansmod.common.teams.EntityGunItem;
import com.flansmod.common.teams.Team;
import com.flansmod.common.types.IFlanItem;
import com.flansmod.common.types.IPaintableItem;
import com.flansmod.common.types.InfoType;
import com.flansmod.common.types.PaintableType;
import com.flansmod.common.vector.Vector3f;
import com.google.common.collect.Multimap;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.EnumAction;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.BlockPos;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.util.Vec3i;
import net.minecraft.util.MovingObjectPosition.MovingObjectType;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.network.NetworkRegistry.TargetPoint;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class ItemGun extends Item implements IPaintableItem
{
private static final int CLIENT_TO_SERVER_UPDATE_INTERVAL = 1;
private static final int SERVER_TO_CLIENT_UPDATE_INTERVAL = 2;
private GunType type;
public GunType GetType() { return type; }
@Override
public InfoType getInfoType() { return type; }
@Override
public PaintableType GetPaintableType() { return type; }
private int soundDelay = 0;
private static boolean rightMouseHeld;
private static boolean lastRightMouseHeld;
private static boolean leftMouseHeld;
private static boolean lastLeftMouseHeld;
private static boolean GetMouseHeld(boolean isOffHand)
{
if(FlansMod.shootOnRightClick)
return isOffHand ? leftMouseHeld : rightMouseHeld;
else return isOffHand ? rightMouseHeld : leftMouseHeld;
}
private static boolean GetLastMouseHeld(boolean isOffHand)
{
if(FlansMod.shootOnRightClick)
return isOffHand ? lastLeftMouseHeld : lastRightMouseHeld;
else return isOffHand ? lastRightMouseHeld : lastLeftMouseHeld;
}
private static List<ShotData> shotsFiredClient = new ArrayList<ShotData>(), shotsFiredServer = new ArrayList<ShotData>();
public ItemGun(GunType type)
{
maxStackSize = 1;
this.type = type;
type.item = this;
setMaxDamage(0);
setCreativeTab(FlansMod.tabFlanGuns);
GameRegistry.registerItem(this, type.shortName, FlansMod.MODID);
}
/** Get the bullet item stack stored in the gun's NBT data (the loaded magazine / bullets) */
public ItemStack getBulletItemStack(ItemStack gun, int id)
{
//If the gun has no tags, give it some
if(!gun.hasTagCompound())
{
gun.setTagCompound(new NBTTagCompound());
return null;
}
//If the gun has no ammo tags, give it some
if(!gun.getTagCompound().hasKey("ammo"))
{
NBTTagList ammoTagsList = new NBTTagList();
for(int i = 0; i < type.numAmmoItemsInGun; i++)
{
ammoTagsList.appendTag(new NBTTagCompound());
}
gun.getTagCompound().setTag("ammo", ammoTagsList);
return null;
}
//Take the list of ammo tags
NBTTagList ammoTagsList = gun.getTagCompound().getTagList("ammo", Constants.NBT.TAG_COMPOUND);
//Get the specific ammo tags required
NBTTagCompound ammoTags = ammoTagsList.getCompoundTagAt(id);
return ItemStack.loadItemStackFromNBT(ammoTags);
}
/** Set the bullet item stack stored in the gun's NBT data (the loaded magazine / bullets) */
public void setBulletItemStack(ItemStack gun, ItemStack bullet, int id)
{
//If the gun has no tags, give it some
if(!gun.hasTagCompound())
{
gun.setTagCompound(new NBTTagCompound());
}
//If the gun has no ammo tags, give it some
if(!gun.getTagCompound().hasKey("ammo"))
{
NBTTagList ammoTagsList = new NBTTagList();
for(int i = 0; i < type.numAmmoItemsInGun; i++)
{
ammoTagsList.appendTag(new NBTTagCompound());
}
gun.getTagCompound().setTag("ammo", ammoTagsList);
}
//Take the list of ammo tags
NBTTagList ammoTagsList = gun.getTagCompound().getTagList("ammo", Constants.NBT.TAG_COMPOUND);
//Get the specific ammo tags required
NBTTagCompound ammoTags = ammoTagsList.getCompoundTagAt(id);
//Represent empty slots by nulltypes
if(bullet == null)
{
ammoTags = new NBTTagCompound();
}
//Set the tags to match the bullet stack
bullet.writeToNBT(ammoTags);
}
/** Method for dropping items on reload and on shoot */
public static void dropItem(World world, Entity entity, String itemName)
{
if (itemName != null)
{
int damage = 0;
if (itemName.contains("."))
{
damage = Integer.parseInt(itemName.split("\\.")[1]);
itemName = itemName.split("\\.")[0];
}
ItemStack dropStack = InfoType.getRecipeElement(itemName, damage);
entity.entityDropItem(dropStack, 0.5F);
}
}
/** Deployable guns only */
@Override
public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer)
{
if (type.deployable)
{
//Raytracing
float cosYaw = MathHelper.cos(-entityplayer.rotationYaw * 0.01745329F - 3.141593F);
float sinYaw = MathHelper.sin(-entityplayer.rotationYaw * 0.01745329F - 3.141593F);
float cosPitch = -MathHelper.cos(-entityplayer.rotationPitch * 0.01745329F);
float sinPitch = MathHelper.sin(-entityplayer.rotationPitch * 0.01745329F);
double length = 5D;
Vec3 posVec = new Vec3(entityplayer.posX, entityplayer.posY + 1.62D - entityplayer.getYOffset(), entityplayer.posZ);
Vec3 lookVec = posVec.addVector(sinYaw * cosPitch * length, sinPitch * length, cosYaw * cosPitch * length);
MovingObjectPosition look = world.rayTraceBlocks(posVec, lookVec, true);
//Result check
if (look != null && look.typeOfHit == MovingObjectType.BLOCK)
{
if (look.sideHit == EnumFacing.UP)
{
int playerDir = MathHelper.floor_double(((entityplayer.rotationYaw * 4F) / 360F) + 0.5D) & 3;
int i = look.getBlockPos().getX();
int j = look.getBlockPos().getY();
int k = look.getBlockPos().getZ();
if (!world.isRemote)
{
if (world.getBlockState(new BlockPos(i, j, k)).getBlock() == Blocks.snow)
{
j--;
}
if (isSolid(world, i, j, k) && (world.getBlockState(new BlockPos(i, j + 1, k)).getBlock() == Blocks.air || world.getBlockState(new BlockPos(i, j + 1, k)).getBlock() == Blocks.snow) && (world.getBlockState(new BlockPos(i + (playerDir == 1 ? 1 : 0) - (playerDir == 3 ? 1 : 0), j + 1, k - (playerDir == 0 ? 1 : 0) + (playerDir == 2 ? 1 : 0))).getBlock() == Blocks.air) && (world.getBlockState(new BlockPos(i + (playerDir == 1 ? 1 : 0) - (playerDir == 3 ? 1 : 0), j, k - (playerDir == 0 ? 1 : 0) + (playerDir == 2 ? 1 : 0))).getBlock() == Blocks.air || world.getBlockState(new BlockPos(i + (playerDir == 1 ? 1 : 0) - (playerDir == 3 ? 1 : 0), j, k - (playerDir == 0 ? 1 : 0) + (playerDir == 2 ? 1 : 0))).getBlock() == Blocks.snow))
{
for (EntityMG mg : EntityMG.mgs)
{
if (mg.blockX == i && mg.blockY == j + 1 && mg.blockZ == k && !mg.isDead)
return itemstack;
}
if(!world.isRemote)
{
EntityMG mg = new EntityMG(world, i, j + 1, k, playerDir, type);
if(getBulletItemStack(itemstack, 0) != null)
{
mg.ammo = getBulletItemStack(itemstack, 0);
}
world.spawnEntityInWorld(mg);
}
if (!entityplayer.capabilities.isCreativeMode)
itemstack.stackSize = 0;
}
}
}
}
}
//Stop the gun bobbing up and down when holding shoot and looking at a block
if(world.isRemote)
{
for(int i = 0; i < 3; i++)
Minecraft.getMinecraft().entityRenderer.itemRenderer.updateEquippedItem();
}
return itemstack;
}
// _____________________________________________________________________________
//
// Shooting code
// _____________________________________________________________________________
@SideOnly(Side.CLIENT)
public void onUpdateClient(ItemStack gunstack, int gunSlot, World world, Entity entity, boolean isOffHand, boolean hasOffHand)
{
if(!(entity instanceof EntityPlayer))
{
return;
}
// Get useful objects
Minecraft mc = Minecraft.getMinecraft();
EntityPlayer player = (EntityPlayer)entity;
PlayerData data = PlayerHandler.getPlayerData(player, Side.CLIENT);
// Play idle sounds
if (soundDelay <= 0 && type.idleSound != null)
{
PacketPlaySound.sendSoundPacket(entity.posX, entity.posY, entity.posZ, FlansMod.soundRange, entity.dimension, type.idleSound, false);
soundDelay = type.idleSoundLength;
}
// This code is not for deployables
if (type.deployable)
return;
// Do not shoot ammo bags, flags or dropped gun items
if(mc.objectMouseOver != null && (mc.objectMouseOver.entityHit instanceof EntityFlagpole || mc.objectMouseOver.entityHit instanceof EntityFlag || mc.objectMouseOver.entityHit instanceof EntityGunItem || (mc.objectMouseOver.entityHit instanceof EntityGrenade && ((EntityGrenade)mc.objectMouseOver.entityHit).type.isDeployableBag)))
return;
// If we have an off hand item, then disable our secondary functions
boolean secondaryFunctionsEnabled = true;
// Update off hand cycling. Controlled by the main gun, since it is always around.
if(!isOffHand && type.oneHanded)
{
//Cycle selection
int dWheel = Mouse.getDWheel();
if(Keyboard.isKeyDown(mc.gameSettings.keyBindSneak.getKeyCode()) && dWheel != 0)
{
data.cycleOffHandItem(player, dWheel);
}
}
if(type.usableByPlayers)
{
boolean needsToReload = needsToReload(gunstack);
boolean shouldShootThisTick = false;
switch(type.getFireMode(gunstack))
{
case BURST:
{
if(data.GetBurstRoundsRemaining(isOffHand) > 0)
{
shouldShootThisTick = true;
}
// Fallthrough to semi auto
}
case SEMIAUTO:
{
if(GetMouseHeld(isOffHand) && !GetLastMouseHeld(isOffHand))
{
shouldShootThisTick = true;
}
else needsToReload = false;
break;
}
case MINIGUN:
{
if(needsToReload)
{
needsToReload = GetMouseHeld(isOffHand);
break;
}
if(GetMouseHeld(isOffHand))
{
data.minigunSpeed += 2.0f;
data.minigunSpeed *= 0.9f;
// TODO : Re-add looping sounds
if(data.minigunSpeed < type.minigunStartSpeed)
{
if(type.useLoopingSounds)
{
data.shouldPlayWarmupSound = true;
}
break;
}
}
else if(data.minigunSpeed > 0.0f)
{
data.shouldPlayCooldownSound = true;
}
//else fallthrough to full auto
}
case FULLAUTO:
{
shouldShootThisTick = GetMouseHeld(isOffHand);
if(!shouldShootThisTick)
{
needsToReload = false;
}
break;
}
default:
needsToReload = false;
break;
}
// Do reload if we pressed fire.
if(needsToReload)
{
if(Reload(gunstack, world, player, player.inventory, isOffHand, hasOffHand, false, player.capabilities.isCreativeMode))
{
//Set player shoot delay to be the reload delay
//Set both gun delays to avoid reloading two guns at once
data.shootTimeRight = data.shootTimeLeft = (int)type.getReloadTime(gunstack);
GunAnimations animations = FlansModClient.getGunAnimations(player, isOffHand);
int pumpDelay = type.model == null ? 0 : type.model.pumpDelayAfterReload;
int pumpTime = type.model == null ? 1 : type.model.pumpTime;
animations.doReload(type.reloadTime, pumpDelay, pumpTime);
if(isOffHand)
{
data.reloadingLeft = true;
data.burstRoundsRemainingLeft = 0;
}
else
{
data.reloadingRight = true;
data.burstRoundsRemainingRight = 0;
}
//Send reload packet to server
FlansMod.getPacketHandler().sendToServer(new PacketReload(isOffHand, false));
}
}
// Fire!
else if(shouldShootThisTick)
{
GunAnimations animations = FlansModClient.getGunAnimations(player, isOffHand);
animations.lookAt = LookAtState.NONE;
float shootTime = data.GetShootTime(isOffHand);
// For each
while(shootTime <= 0.0f)
{
// Add the delay for this shot and shoot it!
shootTime += type.GetShootDelay(gunstack);
ItemStack shootableStack = getBestNonEmptyShootableStack(gunstack);
if(shootableStack == null)
{
continue;
}
ItemShootable shootableItem = (ItemShootable)shootableStack.getItem();
ShootableType shootableType = shootableItem.type;
// Instant bullets. Do a raytrace
if(type.bulletSpeed == 0.0f)
{
for(int i = 0; i < type.numBullets * shootableType.numBullets; i++)
{
Vector3f rayTraceOrigin = new Vector3f(player.getPositionEyes(0.0f));
Vector3f rayTraceDirection = new Vector3f(player.getLookVec());
float spread = 0.0025f * type.getSpread(gunstack) * shootableType.bulletSpread;
rayTraceDirection.x += (float)world.rand.nextGaussian() * spread;
rayTraceDirection.y += (float)world.rand.nextGaussian() * spread;
rayTraceDirection.z += (float)world.rand.nextGaussian() * spread;
rayTraceDirection.scale(500.0f);
List<BulletHit> hits = FlansModRaytracer.Raytrace(world, player, false, null, rayTraceOrigin, rayTraceDirection, 0);
Entity victim = null;
Vector3f hitPos = Vector3f.add(rayTraceOrigin, rayTraceDirection, null);
BulletHit firstHit = null;
if(!hits.isEmpty())
{
firstHit = hits.get(0);
hitPos = Vector3f.add(rayTraceOrigin, (Vector3f)rayTraceDirection.scale(firstHit.intersectTime), null);
victim = firstHit.GetEntity();
}
Vector3f gunOrigin = FlansModRaytracer.GetPlayerMuzzlePosition(player, isOffHand);
if(FlansMod.DEBUG)
{
world.spawnEntityInWorld(new EntityDebugDot(world, gunOrigin, 100, 1.0f, 1.0f, 1.0f));
}
boolean silenced = type.getBarrel(gunstack) != null && type.getBarrel(gunstack).silencer;
ShotData shotData = new InstantShotData(gunSlot, type, shootableType, player, gunOrigin, firstHit, hitPos, type.getDamage(gunstack), i < type.numBullets * shootableType.numBullets - 1, silenced);
shotsFiredClient.add(shotData);
}
}
// Else, spawn an entity
else
{
ShotData shotData = new SpawnEntityShotData(gunSlot, type, shootableType, player, new Vector3f(player.getLookVec()));
shotsFiredClient.add(shotData);
}
// Now do client side things
int pumpDelay = type.model == null ? 0 : type.model.pumpDelay;
int pumpTime = type.model == null ? 1 : type.model.pumpTime;
animations.doShoot(pumpDelay, pumpTime);
FlansModClient.playerRecoil += type.getRecoil(gunstack);
animations.recoil += type.getRecoil(gunstack);
if(type.consumeGunUponUse)
player.inventory.setInventorySlotContents(gunSlot, null);
// Update burst fire
if(type.getFireMode(gunstack) == EnumFireMode.BURST)
{
int burstRoundsRemaining = data.GetBurstRoundsRemaining(isOffHand);
if(burstRoundsRemaining > 0)
burstRoundsRemaining--;
else burstRoundsRemaining = type.numBurstRounds;
data.SetBurstRoundsRemaining(isOffHand, burstRoundsRemaining);
}
}
data.SetShootTime(isOffHand, shootTime);
}
Vector3f gunOrigin = FlansModRaytracer.GetPlayerMuzzlePosition(player, isOffHand);
if(FlansMod.DEBUG)
{
world.spawnEntityInWorld(new EntityDebugDot(world, gunOrigin, 100, 1.0f, 1.0f, 1.0f));
}
// Now send shooting data to the server
if(!shotsFiredClient.isEmpty() && player.ticksExisted % CLIENT_TO_SERVER_UPDATE_INTERVAL == 0)
{
FlansMod.getPacketHandler().sendToServer(new PacketShotData(shotsFiredClient));
shotsFiredClient.clear();
}
// Check for scoping in / out
IScope currentScope = type.getCurrentScope(gunstack);
if(!isOffHand && !hasOffHand && GetMouseHeld(true) && !GetLastMouseHeld(true)
&& (type.secondaryFunction == EnumSecondaryFunction.ADS_ZOOM || type.secondaryFunction == EnumSecondaryFunction.ZOOM) )
{
FlansModClient.SetScope(currentScope);
}
}
// And finally do sounds
if (soundDelay > 0)
{
soundDelay--;
}
}
public void ServerHandleShotData(ItemStack gunstack, int gunSlot, World world, Entity entity, boolean isOffHand, ShotData shotData)
{
// Get useful things
if(!(entity instanceof EntityPlayerMP))
{
return;
}
EntityPlayerMP player = (EntityPlayerMP)entity;
PlayerData data = PlayerHandler.getPlayerData(player, Side.SERVER);
if(data == null)
{
return;
}
boolean isExtraBullet = shotData instanceof InstantShotData ? ((InstantShotData)shotData).isExtraBullet : false;
//Go through the bullet stacks in the gun and see if any of them are not null
int bulletID = 0;
ItemStack bulletStack = null;
for(; bulletID < type.numAmmoItemsInGun; bulletID++)
{
ItemStack checkingStack = getBulletItemStack(gunstack, bulletID);
if(checkingStack != null && checkingStack.getItem() != null && checkingStack.getItemDamage() < checkingStack.getMaxDamage())
{
bulletStack = checkingStack;
break;
}
}
// We have no bullet stack. So we need to reload. The player will send us a message requesting we do a reload
if(bulletStack == null)
{
return;
}
if(bulletStack.getItem() instanceof ItemShootable)
{
ShootableType bullet = ((ItemShootable)bulletStack.getItem()).type;
if(!isExtraBullet)
{
// Drop item on shooting if bullet requires it
if(bullet.dropItemOnShoot != null && !player.capabilities.isCreativeMode)
dropItem(world, player, bullet.dropItemOnShoot);
// Drop item on shooting if gun requires it
if(type.dropItemOnShoot != null)// && !entityplayer.capabilities.isCreativeMode)
dropItem(world, player, type.dropItemOnShoot);
if(type.knockback > 0)
{
//TODO : Apply knockback
}
//Damage the bullet item
bulletStack.setItemDamage(bulletStack.getItemDamage() + 1);
//Update the stack in the gun
setBulletItemStack(gunstack, bulletStack, bulletID);
if(type.consumeGunUponUse && gunSlot != -1)
player.inventory.setInventorySlotContents(gunSlot, null);
}
// Spawn an entity, classic style
if(shotData instanceof SpawnEntityShotData)
{
// Play a sound if the previous sound has finished
if (soundDelay <= 0 && type.shootSound != null)
{
AttachmentType barrel = type.getBarrel(gunstack);
boolean silenced = barrel != null && barrel.silencer;
//world.playSoundAtEntity(entityplayer, type.shootSound, 10F, type.distortSound ? 1.0F / (world.rand.nextFloat() * 0.4F + 0.8F) : 1.0F);
PacketPlaySound.sendSoundPacket(player.posX, player.posY, player.posZ, FlansMod.soundRange, player.dimension, type.shootSound, type.distortSound, silenced);
soundDelay = type.shootSoundLength;
}
//Shoot
// Spawn the bullet entities
for (int k = 0; k < type.numBullets * bullet.numBullets; k++)
{
// Actually shoot the bullet
((ItemShootable)bulletStack.getItem()).Shoot(world,
new Vector3f(player.posX, player.posY + player.getEyeHeight(), player.posZ),
new Vector3f(player.getLookVec()),
type.getDamage(gunstack),
(player.isSneaking() ? 0.7F : 1F) * type.getSpread(gunstack) * bullet.bulletSpread,
type.getBulletSpeed(gunstack),
type,
player);
}
}
// Do a raytrace check on what they've sent us.
else if(shotData instanceof InstantShotData)
{
InstantShotData instantData = (InstantShotData) shotData;
//if(stuff)
//{
// calculate our own raytrace to verify they're not cheating
//}
// else
{
// Take a point halfway along. Then make the radius encapsulate both ends and then some
//Vector3f targetPoint = Vector3f.add(instantData.origin, instantData.hitPos, null);
//targetPoint.scale(0.5f);
//float radius = Vector3f.sub(instantData.origin, instantData.hitPos, null).length();
//radius += 50.0f;
AttachmentType barrel = type.getBarrel(gunstack);
boolean silenced = barrel != null && barrel.silencer;
DoInstantShot(world, player, type, (BulletType)bullet, instantData.origin, instantData.hitPos, instantData.hitData, type.getDamage(gunstack), isExtraBullet, silenced);
shotsFiredServer.add(shotData);
}
}
}
}
@SideOnly(Side.CLIENT)
private void PlayShotSound(World world, boolean silenced, float x, float y, float z)
{
FMLClientHandler.instance().getClient().getSoundHandler().playSound(
new PositionedSoundRecord(FlansModResourceHandler.getSound(type.shootSound),
silenced ? 5F : 10F,
(type.distortSound ? 1.0F / (world.rand.nextFloat() * 0.4F + 0.8F) : 1.0F) * (silenced ? 2F : 1F),
x, y, z));
}
public void DoInstantShot(World world, Entity shooter, InfoType shotFrom, BulletType shotType, Vector3f origin, Vector3f hit, BulletHit hitData, float damage, boolean isExtraBullet, boolean silenced)
{
if(EntityBullet.OnHit(world, origin, hit, shooter, shotFrom, shotType, null, damage, hitData))
{
EntityBullet.OnDetonate(world, hit, shooter, null, shotFrom, shotType);
}
if(world.isRemote)
{
// Play a sound if the previous sound has finished
if (!isExtraBullet && soundDelay <= 0 && type.shootSound != null && shooter != null)
{
PlayShotSound(world, silenced, (float)shooter.posX, (float)shooter.posY, (float)shooter.posZ);
soundDelay = type.shootSoundLength;
}
if(FlansMod.DEBUG)
{
world.spawnEntityInWorld(new EntityDebugVector(world, origin, Vector3f.sub(hit, origin, null), 100, 0.5f, 0.5f, 1.0f));
}
InstantBulletRenderer.AddTrail(new InstantShotTrail(origin, hit, (BulletType)shotType));
if(hitData instanceof BlockHit)
{
BlockHit blockHit = (BlockHit)hitData;
BlockPos blockPos = blockHit.raytraceResult.getBlockPos();
IBlockState blockState = world.getBlockState(blockHit.raytraceResult.getBlockPos());
Vec3i normal = blockHit.raytraceResult.sideHit.getDirectionVec();
Vector3f bulletDir = Vector3f.sub(hit, origin, null);
bulletDir.normalise();
bulletDir.scale(0.5f);
if(blockState != null)
{
for(int i = 0; i < 2; i++)
{
EntityFX fx = Minecraft.getMinecraft().effectRenderer.spawnEffectParticle(
EnumParticleTypes.BLOCK_CRACK.getParticleID(), hit.x, hit.y, hit.z, 0.0f, 0.0f, 0.0f,
Block.getIdFromBlock(blockState.getBlock()));
double scale = world.rand.nextGaussian() * 0.1d + 0.5d;
fx.motionX = (double)normal.getX() * scale + world.rand.nextGaussian() * 0.025d;
fx.motionY = (double)normal.getY() * scale + world.rand.nextGaussian() * 0.025d;
fx.motionZ = (double)normal.getZ() * scale + world.rand.nextGaussian() * 0.025d;
fx.motionX += bulletDir.x;
fx.motionY += bulletDir.y;
fx.motionZ += bulletDir.z;
if(Minecraft.getMinecraft().gameSettings.fancyGraphics)
fx.renderDistanceWeight = 100D;
}
}
EntityFX fx = Minecraft.getMinecraft().effectRenderer.spawnEffectParticle(EnumParticleTypes.CLOUD.getParticleID(), hit.x, hit.y, hit.z, 0.0f, 0.0f, 0.0f);
double scale = world.rand.nextGaussian() * 0.05d + 0.05d;
fx.motionX = (double)normal.getX() * scale + world.rand.nextGaussian() * 0.025d;
fx.motionY = (double)normal.getY() * scale + world.rand.nextGaussian() * 0.025d;
fx.motionZ = (double)normal.getZ() * scale + world.rand.nextGaussian() * 0.025d;
}
if(world.isRemote)
{
if(shooter == Minecraft.getMinecraft().thePlayer)
{
if(hitData instanceof EntityHit || hitData instanceof DriveableHit)
{
// Add a hit marker
FlansModClient.AddHitMarker();
}
else if(hitData instanceof PlayerBulletHit)
{
// Check teams
if(FlansModClient.teamInfo != null)
{
Team shooterTeam = FlansModClient.teamInfo.getTeam((EntityPlayer)shooter);
Team victimTeam = FlansModClient.teamInfo.getTeam(((PlayerBulletHit) hitData).hitbox.player);
if(shooterTeam == null || shooterTeam != victimTeam)
{
FlansModClient.AddHitMarker();
}
}
else // No teams mod, just add marker
{
FlansModClient.AddHitMarker();
}
}
}
}
}
else
{
}
}
public void onUpdateServer(ItemStack itemstack, int gunSlot, World world, Entity entity, boolean isOffHand, boolean hasOffHand)
{
if(!(entity instanceof EntityPlayerMP))
{
return;
}
EntityPlayerMP player = (EntityPlayerMP)entity;
PlayerData data = PlayerHandler.getPlayerData(player);
if(data == null)
return;
if(player.inventory.getCurrentItem() != itemstack)
{
//If the player is no longer holding a gun, emulate a release of the shoot button
if(player.inventory.getCurrentItem() == null || player.inventory.getCurrentItem().getItem() == null || !(player.inventory.getCurrentItem().getItem() instanceof ItemGun))
{
data.isShootingRight = data.isShootingLeft = false;
data.offHandGunSlot = 0;
(new PacketSelectOffHandGun(0)).handleServerSide(player);
}
return;
}
if(!shotsFiredServer.isEmpty())// && entity.ticksExisted % SERVER_TO_CLIENT_UPDATE_INTERVAL == 0)
{
FlansMod.getPacketHandler().sendToDimension(new PacketShotData(shotsFiredServer), player.dimension );
shotsFiredServer.clear();
}
}
/** Generic update method. If we have an off hand weapon, it will also make calls for that
* Passes on to onUpdateEach */
@Override
public void onUpdate(ItemStack itemstack, World world, Entity entity, int i, boolean flag)
{
if(entity instanceof EntityPlayer && ((EntityPlayer)entity).inventory.getCurrentItem() == itemstack)
{
if(world.isRemote)
{
// Get button presses. Do this before splitting into each hand. Prevents second pass wiping the data
lastRightMouseHeld = rightMouseHeld;
lastLeftMouseHeld = leftMouseHeld;
rightMouseHeld = Mouse.isButtonDown(1);
leftMouseHeld = Mouse.isButtonDown(0);
}
boolean hasOffHand = false;
EntityPlayer player = (EntityPlayer)entity;
PlayerData data = PlayerHandler.getPlayerData(player, Side.CLIENT);
if(type.oneHanded)
{
// If the offhand item is this item, select none
if(data.offHandGunSlot == player.inventory.currentItem + 1)
data.offHandGunSlot = 0;
if(data.offHandGunSlot != 0)
{
hasOffHand = true;
ItemStack offHandGunStack = player.inventory.getStackInSlot(data.offHandGunSlot - 1);
if(offHandGunStack != null && offHandGunStack.getItem() instanceof ItemGun)
{
GunType offHandGunType = ((ItemGun)offHandGunStack.getItem()).type;
((ItemGun)offHandGunStack.getItem()).onUpdateEach(offHandGunStack, data.offHandGunSlot - 1, world, entity, true, hasOffHand);
}
}
}
onUpdateEach(itemstack, player.inventory.currentItem, world, entity, false, hasOffHand);
}
}
/** Called once for each weapon we are weilding */
private void onUpdateEach(ItemStack itemstack, int gunSlot, World world, Entity entity, boolean isOffHand, boolean hasOffHand)
{
if(world.isRemote)
onUpdateClient(itemstack, gunSlot, world, entity, isOffHand, hasOffHand);
else onUpdateServer(itemstack, gunSlot, world, entity, isOffHand, hasOffHand);
}
public boolean Reload(ItemStack gunstack, World world, Entity entity, IInventory inventory, boolean isOffHand, boolean hasOffHand, boolean forceReload, boolean isCreative)
{
//Deployable guns cannot be reloaded in the inventory
if(type.deployable)
return false;
//If you cannot reload half way through a clip, reject the player for trying to do so
if(forceReload && !type.canForceReload)
return false;
//For playing sounds afterwards
boolean reloadedSomething = false;
//Check each ammo slot, one at a time
for(int i = 0; i < type.numAmmoItemsInGun; i++)
{
//Get the stack in the slot
ItemStack bulletStack = getBulletItemStack(gunstack, i);
//If there is no magazine, if the magazine is empty or if this is a forced reload
if(bulletStack == null || bulletStack.getItemDamage() == bulletStack.getMaxDamage() || forceReload)
{
//Iterate over all inventory slots and find the magazine / bullet item with the most bullets
int bestSlot = -1;
int bulletsInBestSlot = 0;
for (int j = 0; j < inventory.getSizeInventory(); j++)
{
ItemStack item = inventory.getStackInSlot(j);
if (item != null && item.getItem() instanceof ItemShootable && type.isAmmo(((ItemShootable)(item.getItem())).type))
{
int bulletsInThisSlot = item.getMaxDamage() - item.getItemDamage();
if(bulletsInThisSlot > bulletsInBestSlot)
{
bestSlot = j;
bulletsInBestSlot = bulletsInThisSlot;
}
}
}
//If there was a valid non-empty magazine / bullet item somewhere in the inventory, load it
if(bestSlot != -1)
{
ItemStack newBulletStack = inventory.getStackInSlot(bestSlot);
ShootableType newBulletType = ((ItemShootable)newBulletStack.getItem()).type;
//Unload the old magazine (Drop an item if it is required and the player is not in creative mode)
if(bulletStack != null && bulletStack.getItem() instanceof ItemShootable && ((ItemShootable)bulletStack.getItem()).type.dropItemOnReload != null && !isCreative && bulletStack.getItemDamage() == bulletStack.getMaxDamage())
{
if(!world.isRemote)
dropItem(world, entity, ((ItemShootable)bulletStack.getItem()).type.dropItemOnReload);
}
//The magazine was not finished, pull it out and give it back to the player or, failing that, drop it
if(bulletStack != null && bulletStack.getItemDamage() < bulletStack.getMaxDamage())
{
if(!InventoryHelper.addItemStackToInventory(inventory, bulletStack, isCreative))
{
if(!world.isRemote)
entity.entityDropItem(bulletStack, 0.5F);
}
}
//Load the new magazine
ItemStack stackToLoad = newBulletStack.copy();
stackToLoad.stackSize = 1;
setBulletItemStack(gunstack, stackToLoad, i);
//Remove the magazine from the inventory
if(!isCreative)
newBulletStack.stackSize--;
if(newBulletStack.stackSize <= 0)
newBulletStack = null;
inventory.setInventorySlotContents(bestSlot, newBulletStack);
//Tell the sound player that we reloaded something
reloadedSomething = true;
}
}
}
return reloadedSomething;
}
// TODO : All this bunk
/* Melee MESS
* @Override
public void onUpdate(ItemStack itemstack, World world, Entity pEnt, int i, boolean flag)
{
if(world.isRemote)
onUpdateClient(itemstack, world, pEnt, i, flag);
else onUpdateServer(itemstack, world, pEnt, i, flag);
if(pEnt instanceof EntityPlayer)
{
EntityPlayer player = (EntityPlayer)pEnt;
PlayerData data = PlayerHandler.getPlayerData(player);
if(data == null)
return;
//if(data.lastMeleePositions == null || data.lastMeleePositions.length != type.meleeDamagePoints.size())
//{
// data.lastMeleePositions = new Vector3f[type.meleeDamagePoints.size()];
// for(int j = 0; j < type.meleeDamagePoints.size(); j++)
// data.lastMeleePositions[j] = new Vector3f(player.posX, player.posY, player.posZ);
//}
//Melee weapon
if(data.meleeLength > 0 && type.meleePath.size() > 0 && player.inventory.getCurrentItem() == itemstack)
{
for(int k = 0; k < type.meleeDamagePoints.size(); k++)
{
Vector3f meleeDamagePoint = type.meleeDamagePoints.get(k);
//Do a raytrace from the prev pos to the current pos and attack anything in the way
Vector3f nextPos = type.meleePath.get((data.meleeProgress + 1) % type.meleePath.size());
Vector3f nextAngles = type.meleePathAngles.get((data.meleeProgress + 1) % type.meleePathAngles.size());
RotatedAxes nextAxes = new RotatedAxes().rotateGlobalRoll(-nextAngles.x).rotateGlobalPitch(-nextAngles.z).rotateGlobalYaw(-nextAngles.y);
Vector3f nextPosInGunCoords = nextAxes.findLocalVectorGlobally(meleeDamagePoint);
Vector3f.add(nextPos, nextPosInGunCoords, nextPosInGunCoords);
Vector3f.add(new Vector3f(0F, 0F, 0F), nextPosInGunCoords, nextPosInGunCoords);
Vector3f nextPosInPlayerCoords = new RotatedAxes(player.rotationYaw + 90F, player.rotationPitch, 0F).findLocalVectorGlobally(nextPosInGunCoords);
if(!FlansMod.proxy.isThePlayer(player))
nextPosInPlayerCoords.y += 1.6F;
Vector3f nextPosInWorldCoords = new Vector3f(player.posX + nextPosInPlayerCoords.x, player.posY + nextPosInPlayerCoords.y, player.posZ + nextPosInPlayerCoords.z);
Vector3f dPos = data.lastMeleePositions[k] == null ? new Vector3f() : Vector3f.sub(nextPosInWorldCoords, data.lastMeleePositions[k], null);
if(player.worldObj.isRemote && FlansMod.DEBUG)
player.worldObj.spawnEntityInWorld(new EntityDebugVector(player.worldObj, data.lastMeleePositions[k], dPos, 200, 1F, 0F, 0F));
//Do the raytrace
{
//Create a list for all bullet hits
ArrayList<BulletHit> hits = new ArrayList<BulletHit>();
//Iterate over all entities
for(int j = 0; j < world.loadedEntityList.size(); j++)
{
Object obj = world.loadedEntityList.get(j);
//Get players
if(obj instanceof EntityPlayer)
{
EntityPlayer otherPlayer = (EntityPlayer)obj;
PlayerData otherData = PlayerHandler.getPlayerData(otherPlayer);
boolean shouldDoNormalHitDetect = false;
if(otherPlayer == player)
continue;
if(otherData != null)
{
if(otherPlayer.isDead || otherData.team == Team.spectators)
{
continue;
}
int snapshotToTry = player instanceof EntityPlayerMP ? ((EntityPlayerMP)player).ping / 50 : 0;
if(snapshotToTry >= otherData.snapshots.length)
snapshotToTry = otherData.snapshots.length - 1;
PlayerSnapshot snapshot = otherData.snapshots[snapshotToTry];
if(snapshot == null)
snapshot = otherData.snapshots[0];
//DEBUG
//snapshot = new PlayerSnapshot(player);
//Check one last time for a null snapshot. If this is the case, fall back to normal hit detection
if(snapshot == null)
shouldDoNormalHitDetect = true;
else
{
//Raytrace
ArrayList<BulletHit> playerHits = snapshot.raytrace(data.lastMeleePositions[k] == null ? nextPosInWorldCoords : data.lastMeleePositions[k], dPos);
hits.addAll(playerHits);
}
}
//If we couldn't get a snapshot, use normal entity hitbox calculations
if(otherData == null || shouldDoNormalHitDetect)
{
MovingObjectPosition mop = data.lastMeleePositions[k] == null ? player.getEntityBoundingBox().calculateIntercept(nextPosInWorldCoords.toVec3(), new Vec3(0F, 0F, 0F)) : player.getBoundingBox().calculateIntercept(data.lastMeleePositions[k].toVec3(), nextPosInWorldCoords.toVec3());
if(mop != null)
{
Vector3f hitPoint = new Vector3f(mop.hitVec.xCoord - data.lastMeleePositions[k].x, mop.hitVec.yCoord - data.lastMeleePositions[k].y, mop.hitVec.zCoord - data.lastMeleePositions[k].z);
float hitLambda = 1F;
if(dPos.x != 0F)
hitLambda = hitPoint.x / dPos.x;
else if(dPos.y != 0F)
hitLambda = hitPoint.y / dPos.y;
else if(dPos.z != 0F)
hitLambda = hitPoint.z / dPos.z;
if(hitLambda < 0)
hitLambda = -hitLambda;
hits.add(new PlayerBulletHit(new PlayerHitbox(otherPlayer, new RotatedAxes(), new Vector3f(), new Vector3f(), new Vector3f(), EnumHitboxType.BODY), hitLambda));
}
}
}
else
{
Entity entity = (Entity)obj;
if(entity != player && !entity.isDead && (entity instanceof EntityLivingBase || entity instanceof EntityAAGun))
{
MovingObjectPosition mop = entity.getEntityBoundingBox().calculateIntercept(data.lastMeleePositions[k].toVec3(), nextPosInWorldCoords.toVec3());
if(mop != null)
{
Vector3f hitPoint = new Vector3f(mop.hitVec.xCoord - data.lastMeleePositions[k].x, mop.hitVec.yCoord - data.lastMeleePositions[k].y, mop.hitVec.zCoord - data.lastMeleePositions[k].z);
float hitLambda = 1F;
if(dPos.x != 0F)
hitLambda = hitPoint.x / dPos.x;
else if(dPos.y != 0F)
hitLambda = hitPoint.y / dPos.y;
else if(dPos.z != 0F)
hitLambda = hitPoint.z / dPos.z;
if(hitLambda < 0)
hitLambda = -hitLambda;
hits.add(new EntityHit(entity, hitLambda));
}
}
}
}
//We hit something
if(!hits.isEmpty())
{
//Sort the hits according to the intercept position
Collections.sort(hits);
float swingDistance = dPos.length();
for(BulletHit bulletHit : hits)
{
if(bulletHit instanceof PlayerBulletHit)
{
PlayerBulletHit playerHit = (PlayerBulletHit)bulletHit;
float damageMultiplier = 1F;
switch(playerHit.hitbox.type)
{
case LEFTITEM : case RIGHTITEM : //Hit a shield. Stop the swing.
{
data.meleeProgress = data.meleeLength = 0;
return;
}
case HEAD : damageMultiplier = 2F; break;
case RIGHTARM : case LEFTARM : damageMultiplier = 0.6F; break;
default :
}
if(playerHit.hitbox.player.attackEntityFrom(getMeleeDamage(player), swingDistance * type.meleeDamage))
{
//If the attack was allowed, we should remove their immortality cooldown so we can shoot them again. Without this, any rapid fire gun become useless
playerHit.hitbox.player.arrowHitTimer++;
playerHit.hitbox.player.hurtResistantTime = playerHit.hitbox.player.maxHurtResistantTime / 2;
}
if(FlansMod.DEBUG)
world.spawnEntityInWorld(new EntityDebugDot(world, new Vector3f(data.lastMeleePositions[k].x + dPos.x * playerHit.intersectTime, data.lastMeleePositions[k].y + dPos.y * playerHit.intersectTime, data.lastMeleePositions[k].z + dPos.z * playerHit.intersectTime), 1000, 1F, 0F, 0F));
}
else if(bulletHit instanceof EntityHit)
{
EntityHit entityHit = (EntityHit)bulletHit;
if(entityHit.entity.attackEntityFrom(DamageSource.causePlayerDamage(player), swingDistance * type.meleeDamage) && entityHit.entity instanceof EntityLivingBase)
{
EntityLivingBase living = (EntityLivingBase)entityHit.entity;
//If the attack was allowed, we should remove their immortality cooldown so we can shoot them again. Without this, any rapid fire gun become useless
living.arrowHitTimer++;
living.hurtResistantTime = living.maxHurtResistantTime / 2;
}
if(FlansMod.DEBUG)
world.spawnEntityInWorld(new EntityDebugDot(world, new Vector3f(data.lastMeleePositions[k].x + dPos.x * entityHit.intersectTime, data.lastMeleePositions[k].y + dPos.y * entityHit.intersectTime, data.lastMeleePositions[k].z + dPos.z * entityHit.intersectTime), 1000, 1F, 0F, 0F));
}
}
}
}
//End raytrace
data.lastMeleePositions[k] = nextPosInWorldCoords;
}
//Increment the progress meter
data.meleeProgress++;
//If we are done, reset the counters
if(data.meleeProgress == data.meleeLength)
data.meleeProgress = data.meleeLength = 0;
}
}
}
*
*/
private boolean needsToReload(ItemStack stack)
{
for(int i = 0; i < type.numAmmoItemsInGun; i++)
{
ItemStack bulletStack = getBulletItemStack(stack, i);
if(bulletStack != null && bulletStack.getItem() != null && bulletStack.getItemDamage() < bulletStack.getMaxDamage())
{
return false;
}
}
return true;
}
public boolean CanReload(ItemStack gunstack, IInventory inventory)
{
for(int i = 0; i < inventory.getSizeInventory(); i++)
{
ItemStack stack = inventory.getStackInSlot(i);
if(type.isAmmo(stack))
{
return true;
}
}
return false;
}
private ItemStack getBestNonEmptyShootableStack(ItemStack stack)
{
for(int i = 0; i < type.numAmmoItemsInGun; i++)
{
ItemStack shootableStack = getBulletItemStack(stack, i);
if(shootableStack != null && shootableStack.getItem() != null && shootableStack.getItemDamage() < shootableStack.getMaxDamage())
{
return shootableStack;
}
}
return null;
}
// _____________________________________________________________________________
//
// Minecraft base item overrides
// _____________________________________________________________________________
@Override
public void addInformation(ItemStack stack, EntityPlayer player, List lines, boolean advancedTooltips)
{
if(type.description != null)
{
Collections.addAll(lines, type.description.split("_"));
}
if(type.showDamage)
lines.add("\u00a79Damage" + "\u00a77: " + type.getDamage(stack));
if(type.showRecoil)
lines.add("\u00a79Recoil" + "\u00a77: " + type.getRecoil(stack));
if(type.showSpread)
lines.add("\u00a79Accuracy" + "\u00a77: " + type.getSpread(stack));
if(type.showReloadTime)
lines.add("\u00a79Reload Time" + "\u00a77: " + type.getReloadTime(stack) / 20 + "s");
for(AttachmentType attachment : type.getCurrentAttachments(stack))
{
if(type.showAttachments)
{
String line = attachment.name;
lines.add(line);
}
}
for(int i = 0; i < type.numAmmoItemsInGun; i++)
{
ItemStack bulletStack = getBulletItemStack(stack, i);
if(bulletStack != null && bulletStack.getItem() instanceof ItemBullet)
{
BulletType bulletType = ((ItemBullet)bulletStack.getItem()).type;
//String line = bulletType.name + (bulletStack.getMaxDamage() == 1 ? "" : " " + (bulletStack.getMaxDamage() - bulletStack.getItemDamage()) + "/" + bulletStack.getMaxDamage());
String line = bulletType.name + " " + (bulletStack.getMaxDamage() - bulletStack.getItemDamage()) + "/" + bulletStack.getMaxDamage();
lines.add(line);
}
}
}
@Override
/** Make sure client and server side NBTtags update */
public boolean getShareTag()
{
return true;
}
public DamageSource getMeleeDamage(EntityPlayer attacker)
{
return new EntityDamageSourceGun(type.shortName, attacker, attacker, type, false);
}
private boolean isSolid(World world, int i, int j, int k)
{
Block block = world.getBlockState(new BlockPos(i, j, k)).getBlock();
if (block == null)
return false;
return block.getMaterial().isSolid() && block.isOpaqueCube();
}
//Stop damage being done to entities when scoping etc.
@Override
public boolean onLeftClickEntity(ItemStack stack, EntityPlayer player, Entity entity)
{
return type.secondaryFunction != EnumSecondaryFunction.MELEE;
}
@Override
public boolean isFull3D()
{
return true;
}
@Override
public boolean onEntitySwing(EntityLivingBase entityLiving, ItemStack stack)
{
if (type.meleeSound != null)
PacketPlaySound.sendSoundPacket(entityLiving.posX, entityLiving.posY, entityLiving.posZ, FlansMod.soundRange, entityLiving.dimension, type.meleeSound, true);
//Do custom melee code here
if(type.secondaryFunction == EnumSecondaryFunction.CUSTOM_MELEE)
{
//Do animation
if(entityLiving.worldObj.isRemote)
{
GunAnimations animations = FlansModClient.getGunAnimations(entityLiving, false);
animations.doMelee(type.meleeTime);
}
//Do custom melee hit detection
if(entityLiving instanceof EntityPlayer)
{
PlayerData data = PlayerHandler.getPlayerData((EntityPlayer)entityLiving);
data.doMelee((EntityPlayer)entityLiving, type.meleeTime, type);
}
}
return type.secondaryFunction != EnumSecondaryFunction.MELEE;
}
@Override
public boolean onBlockStartBreak(ItemStack itemstack, BlockPos pos, EntityPlayer player)
{
return true;
}
@Override
public boolean canHarvestBlock(Block p_150897_1_)
{
return false;
}
@Override
@SideOnly(Side.CLIENT)
public int getColorFromItemStack(ItemStack par1ItemStack, int par2)
{
return type.colour;
}
public boolean isItemStackDamageable()
{
return true;
}
// ----------------- Paintjobs -----------------
@Override
public void getSubItems(Item item, CreativeTabs tabs, List list)
{
GunType type = ((ItemGun)item).type;
if(FlansMod.addAllPaintjobsToCreative)
{
for(Paintjob paintjob : type.paintjobs)
addPaintjobToList(item, type, paintjob, list);
}
else addPaintjobToList(item, type, type.defaultPaintjob, list);
}
private void addPaintjobToList(Item item, GunType type, Paintjob paintjob, List list)
{
ItemStack gunStack = new ItemStack(item, 1, paintjob.ID);
NBTTagCompound tags = new NBTTagCompound();
/*
NBTTagCompound customPaintTags = new NBTTagCompound();
customPaintTags.setInteger("Hash", type.hashCode());
customPaintTags.setByteArray("Skin", new byte[] { (byte) 0x40, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0x61, (byte) 0x74 });
customPaintTags.setInteger("SkinWidth", 2);
customPaintTags.setInteger("SkinHeight", 1);
customPaintTags.setByteArray("Icon", new byte[] { (byte) 0xff, (byte) 0x00, (byte) 0xff });
customPaintTags.setInteger("IconWidth", 1);
customPaintTags.setInteger("IconHeight", 1);
tags.setTag("CustomPaint", customPaintTags);
*/
gunStack.setTagCompound(tags);
list.add(gunStack);
}
// ---------------------------------------------
@Override
public int getMaxItemUseDuration(ItemStack par1ItemStack)
{
return 100;
}
@Override
public EnumAction getItemUseAction(ItemStack par1ItemStack)
{
return EnumAction.BOW;
}
@Override
public Multimap getAttributeModifiers(ItemStack stack)
{
Multimap map = super.getAttributeModifiers(stack);
if(type.knockbackModifier != 0F)
map.put(SharedMonsterAttributes.knockbackResistance.getAttributeUnlocalizedName(), new AttributeModifier(itemModifierUUID, "KnockbackResist", type.knockbackModifier, 0));
if(type.moveSpeedModifier != 1F)
map.put(SharedMonsterAttributes.movementSpeed.getAttributeUnlocalizedName(), new AttributeModifier(itemModifierUUID, "MovementSpeed", type.moveSpeedModifier - 1F, 2));
if(type.secondaryFunction == EnumSecondaryFunction.MELEE)
map.put(SharedMonsterAttributes.attackDamage.getAttributeUnlocalizedName(), new AttributeModifier(itemModifierUUID, "Weapon modifier", type.meleeDamage, 0));
return map;
}
@Override
public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged)
{
return slotChanged;
}
// For when we have custom paintjob names
//@Override
//public String getUnlocalizedName(ItemStack stack)
//{
// return getUnlocalizedName();//stack.getTagCompound().getString("Paint");
//}
@Override
public boolean canItemEditBlocks()
{
return false;
}
}