package com.arkcraft.module.weapon.common.item.ranged; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.HashSet; import java.util.Random; import java.util.Set; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.EnumAction; import net.minecraft.item.Item; import net.minecraft.item.ItemBow; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.arkcraft.module.core.ARKCraft; import com.arkcraft.module.weapon.client.event.ClientEventHandler; import com.arkcraft.module.weapon.common.container.inventory.InventoryAttachment; import com.arkcraft.module.weapon.common.data.WeaponModAttributes; import com.arkcraft.module.weapon.common.entity.EntityProjectile; import com.arkcraft.module.weapon.common.entity.ProjectileType; import com.arkcraft.module.weapon.common.item.ammo.ItemProjectile; import com.arkcraft.module.weapon.common.tileentity.TileFlashlight; import com.arkcraft.module.weapon.init.Blocks; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; /** * @author Lewis_McReu * @author BubbleTrouble */ public abstract class ItemRangedWeapon extends ItemBow { protected static final int MAX_DELAY = 72000; private Set<ItemProjectile> projectiles; private final int maxAmmo; private final int ammoConsumption; private final String defaultAmmoType; private final long shotInterval; private final float speed; private final float inaccuracy; private long nextShotMillis = 0; public ItemRangedWeapon(String name, int durability, int maxAmmo, String defaultAmmoType, int ammoConsumption, double shotInterval, float speed, float inaccuracy) { super(); this.speed = speed; this.inaccuracy = inaccuracy; this.shotInterval = (long) shotInterval * 1000; this.ammoConsumption = ammoConsumption; this.defaultAmmoType = defaultAmmoType; this.maxAmmo = maxAmmo; this.setMaxDamage(durability); this.setMaxStackSize(1); this.projectiles = new HashSet<ItemProjectile>(); this.setUnlocalizedName(name); } @Override public String getUnlocalizedName() { String s = super.getUnlocalizedName(); return s.substring(s.indexOf('.') + 1); } public int getMaxAmmo() { return this.maxAmmo; } public long getShotInterval() { return this.shotInterval; } public int getAmmoConsumption() { return this.ammoConsumption; } public boolean registerProjectile(ItemProjectile projectile) { return this.projectiles.add(projectile); } public boolean isValidProjectile(Item item) { return this.projectiles.contains(item); } @Override public ModelResourceLocation getModel(ItemStack stack, EntityPlayer player, int useRemaining) { String jsonPath = ARKCraft.MODID + ":weapons/" + this.getUnlocalizedName(); InventoryAttachment att = InventoryAttachment.create(stack); if (att != null) { if (att.isScopePresent()) { jsonPath = jsonPath + "_scope"; } else if (att.isFlashPresent()) { jsonPath = jsonPath + "_flashlight"; } else if (att.isLaserPresent()) { jsonPath = jsonPath + "_laser"; } else if (att.isSilencerPresent()) { jsonPath = jsonPath + "_silencer"; } else if (att.isHoloScopePresent()) { jsonPath = jsonPath + "_holo_scope"; } } if (isReloading(stack)) { jsonPath = jsonPath + "_reload"; } return new ModelResourceLocation(jsonPath, "inventory"); } public Random getItemRand() { return new Random(); } @Override public int getMaxItemUseDuration(ItemStack stack) { return MAX_DELAY; } // @Override // public void onUpdate(ItemStack stack, World worldIn, Entity entityIn, int // itemSlot, boolean isSelected) // { // if (FMLCommonHandler.instance().getSide().isClient()) // { // if // (FMLClientHandler.instance().getClient().gameSettings.keyBindAttack.isPressed()) // { // // } // } // } // // private boolean onItemLeftClick(EntityPlayer player, ItemStack stack) // { // World world = player.worldObj; // if (stack.stackSize <= 0 || player.isUsingItem()) { return false; } // LogHelper.info("Leftclick"); // if (canFire(stack, player)) // { // LogHelper.info("Fire"); // if (this.nextShotMillis < System.currentTimeMillis()) // // Start aiming weapon to fire // player.setItemInUse(stack, getMaxItemUseDuration(stack)); // } // // Check can reload // else if (hasAmmoInInventory(player)) // { // LogHelper.info("Reload"); // // Begin reloading // for (int x = 1; x < 1; x++) // { // soundCharge(stack, world, player); // } // player.setItemInUse(stack, getMaxItemUseDuration(stack)); // } // else // { // // Can't reload; no ammo // soundEmpty(stack, world, player); // } // return true; // } // // private void setPlayerItemInUse(EntityPlayer player, ItemStack stack, int // duration) // { // if (stack != player.getItemInUse()) // { // player.itemInUse = stack; // player.itemInUseCount = duration; // // if (!player.worldObj.isRemote) // { // player.setEating(true); // } // } // } public void setReloading(ItemStack stack, EntityPlayer player, boolean reloading) { stack.getTagCompound().setBoolean("reloading", reloading); } public boolean isReloading(ItemStack stack) { checkNBT(stack); return stack.getTagCompound().getBoolean("reloading"); } public int getReloadTicks(ItemStack stack) { return stack.getTagCompound().getInteger("reloadTicks"); } private void setReloadTicks(ItemStack stack, int reloadTicks) { stack.getTagCompound().setInteger("reloadTicks", reloadTicks); } private void checkNBT(ItemStack stack) { if (!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound()); } @Override public void onUpdate(ItemStack stack, World worldIn, Entity entityIn, int itemSlot, boolean isSelected) { if (entityIn instanceof EntityPlayer) { if (isSelected) { InventoryAttachment inv = InventoryAttachment.create(stack); if (inv != null && inv.isFlashPresent()) { updateFlashlight(entityIn); } } else if (isReloading(stack)) { resetReload(stack, (EntityPlayer) entityIn); } } } private void resetReload(ItemStack stack, EntityPlayer player) { setReloading(stack, player, false); setReloadTicks(stack, 0); } private void updateFlashlight(Entity entityIn) { MovingObjectPosition mop = rayTrace(entityIn, 20, 1.0F); if (mop != null) { if (!(mop.typeOfHit == MovingObjectPosition.MovingObjectType.MISS)) { BlockPos pos; if (mop.typeOfHit == MovingObjectPosition.MovingObjectType.ENTITY) { pos = mop.entityHit.getPosition(); } else { pos = mop.getBlockPos(); pos = pos.offset(mop.sideHit); } if (entityIn.worldObj.getBlockState(pos).getBlock() == Blocks.block_flashlight) { TileFlashlight tileLight = (TileFlashlight) entityIn.worldObj .getTileEntity(pos); tileLight.ticks = 0; } else if (entityIn.worldObj.isAirBlock(pos)) { entityIn.worldObj.setBlockState(pos, Blocks.block_flashlight.getDefaultState()); } } } } public Vec3 getPositionEyes(Entity player, float partialTick) { if (partialTick == 1.0F) { return new Vec3(player.posX, player.posY + (double) player.getEyeHeight(), player.posZ); } else { double d0 = player.prevPosX + (player.posX - player.prevPosX) * (double) partialTick; double d1 = player.prevPosY + (player.posY - player.prevPosY) * (double) partialTick + (double) player .getEyeHeight(); double d2 = player.prevPosZ + (player.posZ - player.prevPosZ) * (double) partialTick; return new Vec3(d0, d1, d2); } } public MovingObjectPosition rayTrace(Entity player, double distance, float partialTick) { Vec3 vec3 = getPositionEyes(player, partialTick); Vec3 vec31 = player.getLook(partialTick); Vec3 vec32 = vec3.addVector(vec31.xCoord * distance, vec31.yCoord * distance, vec31.zCoord * distance); return player.worldObj.rayTraceBlocks(vec3, vec32, false, false, true); } @Override public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { if (stack.stackSize <= 0 || player.isUsingItem()) { return stack; } if (canFire(stack, player)) { if (this.nextShotMillis < System.currentTimeMillis()) // Start aiming weapon to fire player.setItemInUse(stack, getMaxItemUseDuration(stack)); } else { // Can't reload; no ammo if (!this.isReloading(stack)) { soundEmpty(stack, world, player); } } return stack; } @Override public EnumAction getItemUseAction(ItemStack stack) { return EnumAction.NONE; } public void hasAmmoAndConsume(ItemStack stack, EntityPlayer player) { int ammoFinal = getAmmoQuantity(stack); String type = ""; ItemStack[] inventory = player.inventory.mainInventory; for (int i = 0; i < inventory.length; i++) { ItemStack invStack = inventory[i]; if (invStack != null) if (isValidProjectile(invStack.getItem())) { int stackSize = invStack.stackSize; type = invStack.getItem().getUnlocalizedName(); int ammo = stackSize < this.getMaxAmmo() - ammoFinal ? stackSize : this .getMaxAmmo() - ammoFinal; ammoFinal += ammo; invStack.stackSize = stackSize - ammo; if (invStack.stackSize < 1) inventory[i] = null; if (ammoFinal == this.getMaxAmmo()) break; } } if (ammoFinal > 0) { setAmmoType(stack, type); setAmmoQuantity(stack, ammoFinal); } } @Override public void onPlayerStoppedUsing(ItemStack stack, World world, EntityPlayer player, int timeLeft) { if (canFire(stack, player)) { { fire(stack, world, player, timeLeft); return; } } } public boolean canReload(ItemStack stack, EntityPlayer player) { return getAmmoQuantity(stack) < getMaxAmmo() && !player.capabilities.isCreativeMode; } public boolean canFire(ItemStack stack, EntityPlayer player) { return (player.capabilities.isCreativeMode || isLoaded(stack, player)); } public boolean hasAmmoInInventory(EntityPlayer player) { return findAvailableAmmo(player) != null; } public ItemProjectile findAvailableAmmo(EntityPlayer player) { for (ItemProjectile projectile : projectiles) { if (player.inventory.hasItem(projectile)) return projectile; } return null; } public int getAmmoQuantityInInventory(ItemStack stack, EntityPlayer player) { InventoryPlayer inventory = player.inventory; String type = getAmmoType(stack); Item item = GameRegistry.findItem(ARKCraft.MODID, type); int out = 0; if (type != null && inventory.hasItem(item)) { for (ItemStack s : inventory.mainInventory) { if (s != null && s.getItem().equals(item)) { out += s.stackSize; } } } return out; } public int getAmmoQuantity(ItemStack stack) { if (stack.hasTagCompound()) return stack.getTagCompound().getInteger("ammo"); else return 0; } public void setAmmoQuantity(ItemStack stack, int ammo) { if (!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound()); stack.getTagCompound().setInteger("ammo", ammo); } public String getAmmoType(ItemStack stack) { String type = null; if (stack.hasTagCompound() && stack.getTagCompound().hasKey("ammotype")) type = stack .getTagCompound().getString("ammotype"); if (type == null || type.equals("")) type = this.getDefaultAmmoType(); return type.toLowerCase(); } public void setAmmoType(ItemStack stack, String type) { if (!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound()); stack.getTagCompound().setString("ammotype", type); } public String getDefaultAmmoType() { return this.defaultAmmoType; } public boolean isLoaded(ItemStack stack, EntityPlayer player) { return getAmmoQuantity(stack) > 0 || player.capabilities.isCreativeMode; } public void soundEmpty(ItemStack itemstack, World world, EntityPlayer entityplayer) { world.playSoundAtEntity(entityplayer, "random.click", 1.0F, 1.0F / 0.8F); } public void soundCharge(ItemStack stack, World world, EntityPlayer player) { String name = ARKCraft.MODID + ":" + this.getUnlocalizedName() + "_reload"; world.playSoundAtEntity(player, name, 0.7F, 0.9F / (getItemRand().nextFloat() * 0.2F + 0.0F)); } public abstract int getReloadDuration(); public void applyProjectileEnchantments(EntityProjectile entity, ItemStack itemstack) { int damage = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, itemstack); if (damage > 0) { entity.setDamage(damage); } int knockback = EnchantmentHelper .getEnchantmentLevel(Enchantment.punch.effectId, itemstack); if (knockback > 0) { entity.setKnockbackStrength(knockback); } if (EnchantmentHelper.getEnchantmentLevel(Enchantment.flame.effectId, itemstack) > 0) { entity.setFire(100); } } public final void postShootingEffects(ItemStack itemstack, EntityPlayer entityplayer, World world) { effectPlayer(itemstack, entityplayer, world); effectShoot(itemstack, world, entityplayer.posX, entityplayer.posY, entityplayer.posZ, entityplayer.rotationYaw, entityplayer.rotationPitch); } public abstract void effectPlayer(ItemStack itemstack, EntityPlayer entityplayer, World world); public void effectShoot(ItemStack stack, World world, double x, double y, double z, float yaw, float pitch) { String soundPath = ARKCraft.MODID + ":" + this.getUnlocalizedName() + "_shoot"; InventoryAttachment att = InventoryAttachment.create(stack); if (att != null && att.isSilencerPresent()) soundPath = soundPath + "_silenced"; world.playSoundEffect(x, y, z, soundPath, 1.5F, 1F / (this.getItemRand().nextFloat() * 0.4F + 0.7F)); float particleX = -MathHelper.sin(((yaw + 23) / 180F) * 3.141593F) * MathHelper .cos((pitch / 180F) * 3.141593F); float particleY = -MathHelper.sin((pitch / 180F) * 3.141593F) - 0.1F; float particleZ = MathHelper.cos(((yaw + 23) / 180F) * 3.141593F) * MathHelper .cos((pitch / 180F) * 3.141593F); for (int i = 0; i < 3; i++) { world.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, x + particleX, y + particleY, z + particleZ, 0.0D, 0.0D, 0.0D); } world.spawnParticle(EnumParticleTypes.FLAME, x + particleX, y + particleY, z + particleZ, 0.0D, 0.0D, 0.0D); } public void fire(ItemStack stack, World world, EntityPlayer player, int timeLeft) { if (!world.isRemote) { for (int i = 0; i < getAmmoConsumption(); i++) { EntityProjectile p = createProjectile(stack, world, player); applyProjectileEnchantments(p, stack); if (p != null) world.spawnEntityInWorld(p); } } afterFire(stack, world, player); } protected void afterFire(ItemStack stack, World world, EntityPlayer player) { this.setAmmoQuantity(stack, this.getAmmoQuantity(stack) - ammoConsumption); int damage = 1; int ammo = this.getAmmoQuantity(stack); if (stack.getItemDamage() + damage > stack.getMaxDamage()) { String type = this.getAmmoType(stack); Item i = GameRegistry.findItem(ARKCraft.MODID, type); ItemStack s = new ItemStack(i, ammo); player.inventory.addItemStackToInventory(s); } else if (ammo < 1) { if (hasAmmoInInventory(player) && FMLCommonHandler.instance().getSide().isClient()) { ClientEventHandler.doReload(); } else { this.setAmmoType(stack, ""); } } this.nextShotMillis = System.currentTimeMillis() + this.shotInterval; stack.damageItem(damage, player); postShootingEffects(stack, player, world); } protected EntityProjectile createProjectile(ItemStack stack, World world, EntityPlayer player) { try { String type = this.getAmmoType(stack); Class<?> c = Class.forName("com.arkcraft.module.weapon.common.entity." + ProjectileType .valueOf(type.toUpperCase()).getEntity()); Constructor<?> con = c.getConstructor(World.class, EntityLivingBase.class, float.class, float.class); return (EntityProjectile) con.newInstance(world, player, this.speed, this.inaccuracy); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } public void effectReloadDone(ItemStack stack, World world, EntityPlayer player) { // player.swingItem(); } @Override public Multimap<String, AttributeModifier> getItemAttributeModifiers() { Multimap<String, AttributeModifier> multimap = HashMultimap.create(); this.addItemAttributeModifiers(multimap); return multimap; } public void addItemAttributeModifiers(Multimap<String, AttributeModifier> multimap) { multimap.put(WeaponModAttributes.RELOAD_TIME.getAttributeUnlocalizedName(), new AttributeModifier("Weapon reloadtime modifier", this.getReloadDuration(), 0)); } @Override @SideOnly(Side.CLIENT) public boolean isFull3D() { return true; } }