diff --git a/README.md b/README.md index a7f222e..8a4ac2f 100644 --- a/README.md +++ b/README.md @@ -3,38 +3,29 @@ [![Licence badge](https://img.shields.io/github/license/NeRdTheNed/More-bows "Licence")](https://github.com/NeRdTheNed/More-bows/blob/master/LICENSE) [![Java SE version compatibility badge](https://img.shields.io/badge/Java%20SE-5-orange?logo=java "Java SE version compatibility")](https://en.wikipedia.org/wiki/Java_version_history#J2SE_5.0) -### _This port is not finished yet! Stay tuned for progress on it, and feel free to check out the latest dev builds!_ +**_This port is currently in beta, so things might still be incomplete or break! Stay tuned for progress on it, and feel free to check out the latest builds!_**
-This is a port of the More Bows mod to 1.7.10! This mod was originally created by GaussFire, and then maintained & updated by iDiamondhunter. This port aims to faithfully re-create the original mod, while fixing some bugs & then potentially introducing new mechanics (or re-adding cut ideas!). +This is a port of the More Bows mod to 1.7.10! This mod was originally created by GaussFire, and then maintained & updated by iDiamondhunter. This port aims to faithfully re-create the original mod, while fixing some bugs & potentially introducing new mechanics (or re-adding cut ideas!). -Other people's ports: -- LucidSage's port of the More Bows mod to 1.8 can be found [here](https://github.com/LucidSage/More-bows)! - -## Progress: Most things (barely) work! +### Original descriptions of each bow (not currently 100% accurate!): -Issues / TODO list: +- Reinforced Bow ![Reinforced Bow Icon](https://raw.githubusercontent.com/NeRdTheNed/More-bows/master/src/main/resources/assets/morebows/textures/items/StoneBow1.png): This bow is just like the regular wooden bow, but has more durability. +- Iron Bow ![Iron Bow Icon](https://raw.githubusercontent.com/NeRdTheNed/More-bows/master/src/main/resources/assets/morebows/textures/items/IronBow1.png): This bow is a step up from the reinforced bow, having slightly more damage and durability, along with a minuscule upgrade of draw speed. +- Golden Bow ![Golden Bow Icon](https://raw.githubusercontent.com/NeRdTheNed/More-bows/master/src/main/resources/assets/morebows/textures/items/GoldBow1.png): The bow forged of gold: it has a pathetic amount of uses but overall does the most damage. Quick reflexes allow you to shoot at double the speed! +- Crystal Bow ![Crystal Bow Icon](https://raw.githubusercontent.com/NeRdTheNed/More-bows/master/src/main/resources/assets/morebows/textures/items/DiamondBow1.png): A bow sealed with the power of diamond, not many can survive it's swift and damaging moves. With a diamond base, you don't need to worry about over-pulling, this bow also doubles your draw speed! +- Blazing Bow ![Blazing Bow Icon](https://raw.githubusercontent.com/NeRdTheNed/More-bows/master/src/main/resources/assets/morebows/textures/items/FlameBow1.png): A bow from the horrible pits of the Nether, the power of fire emanates from the weapon in your hand. With this bow, you can do double the damage of a normal bow, while setting your foes alight! +- Ender Bow ![Ender Bow Icon](https://raw.githubusercontent.com/NeRdTheNed/More-bows/master/src/main/resources/assets/morebows/textures/items/EnderBow1.png): A mysterious bow with the secrets of the Ender within. Along with having a slow drawback, it will use the Ender's technique to shoot a regular arrow that will not damage anything but, after 3 seconds, will summon 5 more arrows to kill it's opponents. +- Legia Bow ![Legia Bow Icon](https://raw.githubusercontent.com/NeRdTheNed/More-bows/master/src/main/resources/assets/morebows/textures/items/MultiBow1.png): The final and most overwhelming bow, it delivers fast and many blows to its enemies. Even with two arrows, your draw speed will be faster than the iron bow! +- Frost Bow ![Frost Bow Icon](https://raw.githubusercontent.com/NeRdTheNed/More-bows/master/src/main/resources/assets/morebows/textures/items/FrostBow1.png): Bonus bow for Christmas! Present for everyone who was supporting (iDiamondhunter) with the mod! This bow makes entities go slowly but its draw speed is awful. It also spawns a snow layer on impact, and freezes water! --
diff --git a/gradle.properties b/gradle.properties index 0e7324c..8dce331 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ minecraft_version=1.7.10 forge_version=10.13.4.1558-1.7.10 -mod_version=1.0.0-beta.1 +mod_version=1.0.0-beta.2 mod_group=iDiamondhunter.morebows mod_name=More Bows diff --git a/src/main/java/iDiamondhunter/morebows/Client.java b/src/main/java/iDiamondhunter/morebows/Client.java index 8c28763..5705c4e 100644 --- a/src/main/java/iDiamondhunter/morebows/Client.java +++ b/src/main/java/iDiamondhunter/morebows/Client.java @@ -2,19 +2,30 @@ import cpw.mods.fml.client.registry.RenderingRegistry; import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; import iDiamondhunter.morebows.bows.CustomBow; import iDiamondhunter.morebows.client.NoRender; import iDiamondhunter.morebows.entities.ArrowSpawner; -import net.minecraft.client.renderer.entity.RenderSnowball; -import net.minecraft.init.Items; import net.minecraftforge.client.event.FOVUpdateEvent; +/* import org.lwjgl.opengl.GL11; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.client.event.RenderPlayerEvent.Specials.Pre; */ + +/* import net.minecraft.client.renderer.entity.RenderSnowball; +import net.minecraft.init.Items; */ + public class Client extends MoreBows { + /** Handles the FOV "zoom in" when drawing a custom bow */ @SubscribeEvent + @SideOnly(value = Side.CLIENT) public void FOVUpdate(FOVUpdateEvent event) { if ((event.entity.getItemInUse() != null) && (event.entity.getItemInUse().getItem() instanceof CustomBow)) { - // See net.minecraft.client.entity.EntityPlayerSP.getFOVMultiplier() + /** See net.minecraft.client.entity.EntityPlayerSP.getFOVMultiplier() */ final CustomBow bow = (CustomBow) event.entity.getItemInUse().getItem(); float f1 = (float) event.entity.getItemInUseDuration() / (float) (bow.iconTimes[0] * (10 / 9)); @@ -28,10 +39,48 @@ public void FOVUpdate(FOVUpdateEvent event) { } } + /* What's this? An unfinished future feature, not enabled in this commit due to potential bugs? Sneaky... */ + /*@SubscribeEvent + @SideOnly(value = Side.CLIENT) + public void playerRenderEvent(Pre event) { + final EntityPlayer player = event.entityPlayer; + + if ((player.getItemInUse() != null) && (player.getItemInUse().getItem() instanceof CustomBow)) { + // We'll handle it. + event.renderItem = false; + // Get the item to render + final ItemStack currItem = player.inventory.getCurrentItem(); + // Start the OpenGL stuff + GL11.glPushMatrix(); + event.renderer.modelBipedMain.bipedRightArm.postRender(0.0625F); + GL11.glTranslatef(-0.0625F, 0.4375F, 0.0625F); + final float scale = 0.625F; + GL11.glTranslatef(0.0F, 0.125F, 0.3125F); + GL11.glRotatef(-20.0F, 0.0F, 1.0F, 0.0F); + GL11.glScalef(scale, -scale, scale); + GL11.glRotatef(-100.0F, 1.0F, 0.0F, 0.0F); + GL11.glRotatef(45.0F, 0.0F, 1.0F, 0.0F); + // Get the RBG value + final int itemColor = currItem.getItem().getColorFromItemStack(currItem, 0); + // Split the RGB values + final float red = ((itemColor >> 16) & 255) / 255.0F; + final float green = ((itemColor >> 8) & 255) / 255.0F; + final float blue = (itemColor & 255) / 255.0F; + final float alpha = 1.0F; + GL11.glColor4f(red, green, blue, alpha); + // I think this is actually the best way to do this, which is just super cursed. + Minecraft.getMinecraft().entityRenderer.itemRenderer.renderItem(event.entityLiving, currItem, 0); + // GL is gone. Who needs it anyway? + GL11.glPopMatrix(); + } + }*/ + @Override protected void registerEntities() { super.registerEntities(); + // Handles not rendering the arrow spawner RenderingRegistry.registerEntityRenderingHandler(ArrowSpawner.class, new NoRender()); + /* TODO Re-implement */ //RenderingRegistry.registerEntityRenderingHandler(FrostArrow.class, new RenderSnowball(Items.snowball)); } diff --git a/src/main/java/iDiamondhunter/morebows/MoreBows.java b/src/main/java/iDiamondhunter/morebows/MoreBows.java index f0cbc6c..9307e82 100644 --- a/src/main/java/iDiamondhunter/morebows/MoreBows.java +++ b/src/main/java/iDiamondhunter/morebows/MoreBows.java @@ -29,28 +29,25 @@ import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.event.entity.living.LivingHurtEvent; -/* TODO: Document. */ +/* If you're reading this, I'm very sorry you have to deal with my code. */ @Mod(modid = MoreBows.MOD_ID, useMetadata = true) public class MoreBows { - /* TODO: Document. */ + /* Mod specific reusable values */ public static final String MOD_ID = "MoreBows"; private static final String modSeperator = "morebows:"; - //private static final boolean isDev = true; private static Random rand = new Random(); - /* TODO: Document. */ + /* Mod instance */ @Instance(MOD_ID) public static MoreBows inst; - /* TODO: Document. This is super janky. */ + /* Mod proxy. TODO This is super janky, see if it's possible to remove this */ @SidedProxy(clientSide = "iDiamondhunter.morebows.Client", serverSide = "iDiamondhunter.morebows.MoreBows") public static MoreBows proxy; - //private final static float defaultPowerDiv = 20.0F; - - /* TODO: Re-evaluate how & where stuff should be declared & initialized. */ + /* Names of bows. TODO: Re-evaluate how & where stuff should be declared & initialized. */ public final static String DiamondBowName = "DiamondBow"; public final static String GoldBowName = "GoldBow"; public final static String EnderBowName = "EnderBow"; @@ -59,29 +56,29 @@ public class MoreBows { public final static String MultiBowName = "MultiBow"; public final static String FlameBowName = "FlameBow"; public final static String FrostBowName = "FrostBow"; - //public final static String zzz_DevBowName = "DevBow"; private static final ArrowType defaultArrowType = ArrowType.NOT_CUSTOM; - /* This is super janky. */ + /* Bow items. TODO: This is super janky. */ public final static Item DiamondBow = new CustomBow(1016, EnumRarity.rare, new byte[] {8, 4}, 2.2F, 6F, 140, 2.25D).setUnlocalizedName(DiamondBowName).setTextureName(modSeperator + DiamondBowName); - public final static Item GoldBow = new CustomBow(550, EnumRarity.uncommon, new byte[] {8, 4}, 2.4F, 5F, 100, 1.5D).setUnlocalizedName(GoldBowName).setTextureName(modSeperator + GoldBowName); + public final static Item GoldBow = new CustomBow(68, EnumRarity.uncommon, new byte[] {8, 4}, 2.4F, 5F, 100, 1.5D).setUnlocalizedName(GoldBowName).setTextureName(modSeperator + GoldBowName); public final static Item EnderBow = new EnderBow().setUnlocalizedName(EnderBowName).setTextureName(modSeperator + EnderBowName); public final static Item StoneBow = new CustomBow(484, EnumRarity.common, (byte[]) null, 17F, 1.15D, defaultArrowType).setUnlocalizedName(StoneBowName).setTextureName(modSeperator + StoneBowName); public final static Item IronBow = new CustomBow(550, EnumRarity.common, new byte[] {16, 11}, 2.1F, 17F, 105, 1.5D).setUnlocalizedName(IronBowName).setTextureName(modSeperator + IronBowName); public final static Item MultiBow = new MultiBow().setUnlocalizedName(MultiBowName).setTextureName(modSeperator + MultiBowName); public final static Item FlameBow = new CustomBow(576, EnumRarity.uncommon, new byte[] {14, 9}, 15F, 2.0D, ArrowType.FIRE).setUnlocalizedName(FlameBowName).setTextureName(modSeperator + FlameBowName); public final static Item FrostBow = new CustomBow(550, EnumRarity.common, new byte[] {26, 13}, 26.0F, 1D, ArrowType.FROST).setUnlocalizedName(FrostBowName).setTextureName(modSeperator + FrostBowName); - //public final static Item zzz_DevBow = new CustomBow().setUnlocalizedName(zzz_DevBowName).setTextureName(modSeperator + StoneBowName); - /* TODO: Document. */ + /** Calls the server world specific method to spawn a particle on the server. This particle will be sent to connected clients. + * The parameter randDisp can be set, which sets the particles position to somewhere random close to the entity. + * TODO Cleanup and re-evaluate, document better. + */ private static void spawnParticle(WorldServer server, Entity entity, String particle, boolean randDisp, double velocity) { final int numPart = 1; final double xDisp; final double yDisp; final double zDisp; - //final double vel = 0; if (randDisp) { xDisp = (rand.nextFloat() * entity.width * 2.0F) - entity.width; yDisp = 0.5D + (rand.nextFloat() * entity.height); @@ -95,7 +92,9 @@ private static void spawnParticle(WorldServer server, Entity entity, String part server.func_147487_a(particle, entity.posX, entity.posY, entity.posZ, numPart, xDisp, yDisp, zDisp, velocity); } - /* TODO: Document. */ + /** Effectively a helper method for spawnParticle. + * TODO Cleanup and re-evaluate, document better. + */ public static boolean trySpawnParticle(World world, Entity entity, String particle, boolean randDisp, double velocity) { if (!world.isRemote) { final WorldServer server = (WorldServer) world; @@ -106,11 +105,10 @@ public static boolean trySpawnParticle(World world, Entity entity, String partic } } - /*public static boolean trySpawnParticle(World world, Entity entity, String particle) { - return trySpawnParticle(world, entity, particle, ParicleDisplacement.CENTER, 0); - }*/ - - /* TODO: Document. */ + /** Handles particle effects on custom arrows hitting an entity, and adds critical damage to frost arrows. + * Frost arrows always return false when normal methods to get if they're critical are called. This is to hide the vanilla particle trail, so it can create its own custom one. + * TODO Cleanup, document better. + */ @SubscribeEvent public void arrAttack(LivingAttackEvent event) { if (!event.entity.worldObj.isRemote && (event.source.getSourceOfDamage() instanceof CustomArrow)) { @@ -121,7 +119,6 @@ public void arrAttack(LivingAttackEvent event) { final int numPart; final double velocity; final boolean randDisp; - //final ParicleDisplacement motion; switch (type) { case BASE: @@ -129,15 +126,18 @@ public void arrAttack(LivingAttackEvent event) { numPart = 3; randDisp = true; velocity = 1; - //motion = ParicleDisplacement.RANDOM; break; case FIRE: - particle = "flame"; + if (arr.isBurning()) { + particle = "flame"; + } else { + particle = "smoke"; + } + numPart = 5; randDisp = true; velocity = 0.05; - //motion = ParicleDisplacement.RANDOM; break; case FROST: @@ -145,7 +145,6 @@ public void arrAttack(LivingAttackEvent event) { numPart = 1; randDisp = false; velocity = 0.01; - //motion = ParicleDisplacement.CENTER; break; default: @@ -153,7 +152,6 @@ public void arrAttack(LivingAttackEvent event) { numPart = 1; randDisp = false; velocity = 1; - //motion = ParicleDisplacement.CENTER; break; } @@ -172,14 +170,17 @@ public void arrAttack(LivingAttackEvent event) { } } - /* TODO: Document. */ + /** Handles custom effects from the frost arrow. + * TODO Cleanup? + */ @SubscribeEvent public void arrHit(LivingHurtEvent event) { if (event.source.getSourceOfDamage() instanceof CustomArrow) { final CustomArrow arr = (CustomArrow) event.source.getSourceOfDamage(); if (arr.getType() == ArrowType.FROST) { - event.entity.setInWeb(); //TODO Replace with slowness effect? This is the original behavior... + event.entity.setInWeb(); // TODO Replace with slowness effect? This is the original behavior... + //event.entity.extinguish(); // Potentially would be nice to have? Not in the original mod, just though it seemed right. if (!(event.entity instanceof EntityEnderman)) { //TODO Verify that this is the right behavior event.source.getSourceOfDamage().setDead(); @@ -212,10 +213,6 @@ protected void registerItems() { GameRegistry.registerItem(MultiBow, MultiBowName); GameRegistry.registerItem(FlameBow, FlameBowName); GameRegistry.registerItem(FrostBow, FrostBowName); - // Test bow, don't leave this in for releases - //if (isDev) { - // GameRegistry.registerItem(zzz_DevBow, zzz_DevBowName); - //} /** Recipes */ GameRegistry.addRecipe(new ItemStack(StoneBow, 1), " Ss", "TBs", " Ss", 'T', Items.stick, 's', Items.string, 'S', Blocks.stone, 'B', Items.bow); GameRegistry.addRecipe(new ItemStack(StoneBow, 1), "sS ", "sBT", "sS ", 'T', Items.stick, 's', Items.string, 'S', Blocks.stone, 'B', Items.bow); diff --git a/src/main/java/iDiamondhunter/morebows/bows/CustomBow.java b/src/main/java/iDiamondhunter/morebows/bows/CustomBow.java index 8cd36ba..9d8041e 100644 --- a/src/main/java/iDiamondhunter/morebows/bows/CustomBow.java +++ b/src/main/java/iDiamondhunter/morebows/bows/CustomBow.java @@ -26,8 +26,9 @@ **/ public class CustomBow extends ItemBow { + /* Default values for bow construction */ private static final EnumRarity defaultRarity = EnumRarity.common; - private static final byte[] defaultIconTimes = {}; + private static final byte[] defaultIconTimes = {18, 13}; private static final double defaultDamageMult = 1D; private static final int defaultFlameTime = 100; private static final int defaultMaxDamage = 384; @@ -35,33 +36,40 @@ public class CustomBow extends ItemBow { private static final float defaultVelocityMult = 2.0F; private static final ArrowType defaultArrowType = ArrowType.NOT_CUSTOM; + /* Bow instance variables */ private final double damageMult; private final int flameTime; private final float powerDiv; private final EnumRarity rarity; private final ArrowType arrowType; private final float velocityMult; + + /* Arrows to shoot for a given release of the bow. TODO Replace this. */ private EntityArrow[] arrows; + /* Icon related variables */ @SideOnly(Side.CLIENT) private IIcon[] icons; - public final byte[] iconTimes; + public final byte[] iconTimes; // TODO This is not a great solution, and could be considered a "magic number" in some ways. /* TODO Remove as many constructors as possible */ - /* Reference method for each default option. This bow should be roughly the same as the vanilla bow. */ - public CustomBow() { + /* Reference constructor with each default option. This bow should be roughly the same as the vanilla bow. */ + /*public CustomBow() { this(defaultMaxDamage, defaultRarity, defaultIconTimes, defaultVelocityMult, defaultPowerDiv, defaultFlameTime, defaultDamageMult, defaultArrowType); - } + }*/ + /** A constructor that is useful for a number of bows, as they only use these parameters. */ public CustomBow(int maxDamage, EnumRarity rarity, byte[] iconTimes, float powerDiv, double damageMult, ArrowType arrowType) { this(maxDamage, rarity, iconTimes, defaultVelocityMult, powerDiv, defaultFlameTime, damageMult, arrowType); } + /** A constructor that can use every customization, minus a bow having a custom arrow. */ public CustomBow(int maxDamage, EnumRarity rarity, byte[] iconTimes, float velocityMult, float powerDiv, int flameTime, double damageMult) { this(maxDamage, rarity, iconTimes, velocityMult, powerDiv, flameTime, damageMult, defaultArrowType); } + /** A constructor that can use every customization. */ public CustomBow(int maxDamage, EnumRarity rarity, byte[] iconTimes, float velocityMult, float powerDiv, int flameTime, double damageMult, ArrowType arrowType) { //super(); maxStackSize = 1; @@ -72,7 +80,7 @@ public CustomBow(int maxDamage, EnumRarity rarity, byte[] iconTimes, float veloc if (iconTimes != null) { this.iconTimes = iconTimes; } else { - this.iconTimes = new byte[] {18, 13}; + this.iconTimes = defaultIconTimes; } setMaxDamage(maxDamage); @@ -84,20 +92,18 @@ public CustomBow(int maxDamage, EnumRarity rarity, byte[] iconTimes, float veloc this.arrowType = arrowType; } - /** TODO: replace this */ - public EntityArrow[] addModifiers(EntityArrow[] arrs, final ItemStack stack, final boolean noPickup, final boolean isCrit) { //TODO rename later - //TODO THIS CODE IS AWFULL FIX IT - //not just the readability, but also the fact that this is literal garbage to work with - //when you need to insert an effect into this chain - //see: ItemFlameBow + /** This method handles adding or changing the properties of the arrow, based on a variety of factors including enchantments the bow has etc. + * This is largely based on vanilla, with specific additions for this mod. + * TODO: possibly replace this */ + public EntityArrow[] addModifiers(EntityArrow[] arrs, final ItemStack stack, final boolean noPickup, final boolean isCrit) { final int powerEnchResult = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, stack); final boolean powerEnch = (powerEnchResult > 0); final int knockback = EnchantmentHelper.getEnchantmentLevel(Enchantment.punch.effectId, stack); final boolean punchEnch = (knockback > 0); final boolean flameEnch = (EnchantmentHelper.getEnchantmentLevel(Enchantment.flame.effectId, stack) > 0); + final boolean isFireArr = (arrowType == ArrowType.FIRE); final boolean shouldMulti = (damageMult != 1); - //default behavior for (final EntityArrow arr : arrs) { if (isCrit) { /* setIsCritical calls dataWatcher methods, avoid this unless needed with the check. */ arr.setIsCritical(true); @@ -113,6 +119,14 @@ public EntityArrow[] addModifiers(EntityArrow[] arrs, final ItemStack stack, fin if (flameEnch) { arr.setFire(flameTime); + + if (isFireArr) { + arr.setDamage(arr.getDamage() * 1.25D); // TODO: Verify + } + } + + if (isFireArr) { + arr.setFire(50); // TODO: Verify. I'm pretty sure the original mod did this. } if (noPickup) { @@ -127,7 +141,7 @@ public EntityArrow[] addModifiers(EntityArrow[] arrs, final ItemStack stack, fin return arrs; } - /** TODO This is still a bit janky. Remove this message when you're certain this is a good way to do it. */ + /** This returns the bow sprite for a given duration of drawing the bow back. TODO This is still a bit janky. Remove this message when you're certain this is a good way to do it. */ @Override @SideOnly(Side.CLIENT) public IIcon getIcon(ItemStack stack, int u, EntityPlayer p, ItemStack i, int useRem) { @@ -153,7 +167,7 @@ public final EnumRarity getRarity(ItemStack item) { return rarity; } - /** TODO find a cleaner way to implement this, change like all of this. also make better names. */ + /** This handles the process of shooting an arrow, with methods for specific parts of this process. These were intended to be overridden when needed, but this has been changed a bit since. TODO Cleanup. */ @Override public void onPlayerStoppedUsing(ItemStack stack, World world, EntityPlayer player, int remaining) { final int initCharge = getMaxItemUseDuration(stack) - remaining; @@ -193,11 +207,12 @@ public void onPlayerStoppedUsing(ItemStack stack, World world, EntityPlayer play } } + /** This method plays the bow releasing noise for a given release of the bow. TODO Remove this. */ protected void playNoise(World world, EntityPlayer player, float shotVelocity) { world.playSoundAtEntity(player, "random.bow", 1.0F, (1.0F / ((itemRand.nextFloat() * 0.4F) + 1.2F)) + (shotVelocity * 0.5F)); } - /* Overrides are used as ItemBow's icon related variables are not visible :( */ + /** This method registers the icons of a given bow. Overrides are used as ItemBow's icon related variables are not visible :( */ @Override @SideOnly(Side.CLIENT) public void registerIcons(IIconRegister iconReg) { @@ -212,6 +227,7 @@ public void registerIcons(IIconRegister iconReg) { } } + /** This method creates the arrows for a given release of the bow. TODO Remove this. */ public EntityArrow[] setArrows(World world, EntityPlayer player, float shotVelocity) { //TODO rename later if (arrowType == ArrowType.NOT_CUSTOM) { return new EntityArrow[] { new EntityArrow(world, player, shotVelocity * velocityMult) }; @@ -220,6 +236,7 @@ public EntityArrow[] setArrows(World world, EntityPlayer player, float shotVeloc } } + /** This method spawns the arrows for a given release of the bow. TODO Remove this. */ protected void spawnArrows(World world, EntityPlayer player, float shotVelocity, EntityArrow[] arrs) { for (final EntityArrow arr : arrs) { world.spawnEntityInWorld(arr); diff --git a/src/main/java/iDiamondhunter/morebows/bows/EnderBow.java b/src/main/java/iDiamondhunter/morebows/bows/EnderBow.java index 35cfd7e..878ca72 100644 --- a/src/main/java/iDiamondhunter/morebows/bows/EnderBow.java +++ b/src/main/java/iDiamondhunter/morebows/bows/EnderBow.java @@ -14,16 +14,17 @@ public class EnderBow extends CustomBow { public EnderBow() { - super(384, EnumRarity.epic, (byte[]) null, 22F, 1D, ArrowType.BASE); + super(215, EnumRarity.epic, new byte[] {19, 10}, 22F, 1D, ArrowType.BASE); } - /** TODO Document */ + /** This method creates particles when left clicking with an ender bow. */ @Override public boolean onEntitySwing(EntityLivingBase entityLiving, ItemStack stack) { MoreBows.trySpawnParticle(entityLiving.worldObj, entityLiving, "portal", true, 1); return false; } + /* Creates the multiple ender arrows to use with the ArrowSpawner TODO Replace this */ @Override public EntityArrow[] setArrows(World world, EntityPlayer player, float shotVelocity) { final EntityArrow[] arrs = new EntityArrow[] { diff --git a/src/main/java/iDiamondhunter/morebows/bows/MultiBow.java b/src/main/java/iDiamondhunter/morebows/bows/MultiBow.java index 44c0f7e..03f1bc8 100644 --- a/src/main/java/iDiamondhunter/morebows/bows/MultiBow.java +++ b/src/main/java/iDiamondhunter/morebows/bows/MultiBow.java @@ -16,6 +16,7 @@ public MultiBow() { super(550, EnumRarity.rare, new byte[] {12, 7}, 13F, 1D, ArrowType.BASE); } + /** Plays the noises at each arrow */ @Override protected void playNoise(World world, EntityPlayer player, float shotVelocity) { //TODO: Clean this up @@ -30,6 +31,7 @@ protected void playNoise(World world, EntityPlayer player, float shotVelocity) { } } + /* Creates the multiple arrows of the bow. TODO Replace this */ @Override public EntityArrow[] setArrows(World world, EntityPlayer player, float shotVelocity) { final EntityArrow[] arrs = new EntityArrow[] { @@ -42,7 +44,7 @@ public EntityArrow[] setArrows(World world, EntityPlayer player, float shotVeloc return arrs; } - /** TODO Fix weird angles on arrows */ + /* Spawns the multiple arrows of the bow. TODO Replace this, fix weird angles on arrows */ @Override protected void spawnArrows(World world, EntityPlayer player, float shotVelocity, EntityArrow[] arrs) { world.spawnEntityInWorld(arrs[0]); @@ -69,11 +71,6 @@ protected void spawnArrows(World world, EntityPlayer player, float shotVelocity, arrs[2].posX = arrs[2].posX - (arrs[2].shootingEntity.rotationYaw / 180); } } - - //iDiamondhunter.morebows.MoreBows.modLog.error("Arrows"); - //iDiamondhunter.morebows.MoreBows.modLog.error("Test arrows[0]: rot yaw " + arrows[0].shootingEntity.rotationYaw + " divided rot yaw " + (arrows[0].shootingEntity.rotationYaw / 180) + " pos x " + arrows[0].posX); //debug - //iDiamondhunter.morebows.MoreBows.modLog.error("Test arrows[1]: rot yaw " + arrows[1].shootingEntity.rotationYaw + " divided rot yaw " + (arrows[1].shootingEntity.rotationYaw / 180) + " pos x " + arrows[1].posX); //debug - //iDiamondhunter.morebows.MoreBows.modLog.error("Test arrows[2]: rot yaw " + arrows[2].shootingEntity.rotationYaw + " divided rot yaw " + (arrows[2].shootingEntity.rotationYaw / 180) + " pos x " + arrows[2].posX); //debug } } diff --git a/src/main/java/iDiamondhunter/morebows/entities/ArrowSpawner.java b/src/main/java/iDiamondhunter/morebows/entities/ArrowSpawner.java index 03dc6c4..6bef6f6 100644 --- a/src/main/java/iDiamondhunter/morebows/entities/ArrowSpawner.java +++ b/src/main/java/iDiamondhunter/morebows/entities/ArrowSpawner.java @@ -10,15 +10,11 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; +/* This entity is responsible for storing and spawning the time delayed "bonus" arrows of the ender bow. TODO Cleanup, more documentation */ public class ArrowSpawner extends Entity { - //@Deprecated - //private final static String bonusArrowSounds = "mob.endermen.portal"; - //@Deprecated - //private final static String defaultShotSound = "random.bow"; private EntityArrow[] arrows; private byte existed = 0; - //private EntityLivingBase creator; Random rand = new Random(); private float shotVelocity; @@ -28,12 +24,10 @@ public ArrowSpawner(World world) { noClip = true; preventEntitySpawning = false; isImmuneToFire = true; - //this.setDead(); } public ArrowSpawner(World world, double posX, double posY, double posZ, float shotVelocity, EntityArrow[] arrows) { this(world); - //creator = living; this.shotVelocity = shotVelocity; this.posX = posX; this.posY = posY; @@ -41,7 +35,7 @@ public ArrowSpawner(World world, double posX, double posY, double posZ, float sh if (arrows.length != 6) { // TODO Fix - //iDiamondhunter.morebows.MoreBows.modLog.error("ArrowSpawner expects 6 arrows, got " + arrows.length + " instead! It will not spawn any arrows until I implement better methods."); + //System.out.println("ArrowSpawner expects 6 arrows, got " + arrows.length + " instead! It will not spawn any arrows until I implement better methods."); // debug setDead(); } @@ -113,7 +107,7 @@ public void onUpdate() { if (!worldObj.isRemote) { if (arrows == null) { - //iDiamondhunter.morebows.MoreBows.modLog.info("Bonus ender arrows lost! Will fix this soon..."); // debug + //System.out.println("Bonus ender arrows lost! Will fix this soon..."); // debug setDead(); return; } @@ -124,7 +118,7 @@ public void onUpdate() { } if (existed == 61) { - // Second batch of arrows + // Second batch of arrows TODO Check if accurate to older versions of the mod worldObj.spawnEntityInWorld(arrows[1]); worldObj.playSoundAtEntity(arrows[1], "mob.endermen.portal", 0.5F, (1F / ((rand.nextFloat() * 0.4F) + 1F)) + (shotVelocity * 0.4F)); worldObj.spawnEntityInWorld(arrows[2]); @@ -151,11 +145,13 @@ public void onUpdate() { } } + /** This method reads the entity specific data from saved NBT data, including the stored arrows. TODO Better documentation */ @Override protected void readEntityFromNBT(NBTTagCompound tag) { - //iDiamondhunter.morebows.MoreBows.modLog.info("reading"); //debug + // Variables related to this entity existed = tag.getByte("existed"); shotVelocity = tag.getFloat("shotVelocity"); + // Variables related to the arrows stored by this entity final int arrowsArmount = tag.getInteger("arrowsAmount"); arrows = new EntityArrow[arrowsArmount]; @@ -163,37 +159,41 @@ protected void readEntityFromNBT(NBTTagCompound tag) { for (int i = 0; i < arrowsArmount; i++) { final NBTTagCompound arrTag = tag.getCompoundTag("arrows").getCompoundTag("arrow" + i); final String arrType = tag.getCompoundTag("arrowsType").getString("arrow" + i); - //iDiamondhunter.morebows.MoreBows.modLog.info("arrow[" + i + "] " + arrTag.toString() + " of type " + arrType); //debug - arrows[i] = (EntityArrow) EntityList.createEntityByName(arrType, worldObj); - //iDiamondhunter.morebows.MoreBows.modLog.info("arrow[" + i + "] " + arrows[i].toString()); //debug - arrows[i].readFromNBT(arrTag); - } - //iDiamondhunter.morebows.MoreBows.modLog.info("arrows " + arrows.toString() + " zero " + arrows[0].toString() + " one " + arrows[1].toString()); //debug + try { + // Attempt to spawn in the specified entity while assuming that the data saved is completely valid + arrows[i] = (EntityArrow) EntityList.createEntityByName(arrType, worldObj); + arrows[i].readFromNBT(arrTag); + } catch (final Exception e) { + // This can fail in numerous ways, so it's probably for the best just to create a new arrow. + e.printStackTrace(); + arrows[i] = new EntityArrow(worldObj); + } + } } + /** This method saves the entity specific data to NBT data, including the stored arrows. TODO Better documentation */ @Override protected void writeEntityToNBT(NBTTagCompound tag) { + // Variables related to this entity + tag.setByte("existed", existed); + tag.setFloat("shotVelocity", shotVelocity); + // Variables related to the arrows stored by this entity + tag.setInteger("arrowsAmount", arrows.length); final NBTTagCompound arrowsTag = new NBTTagCompound(); final NBTTagCompound arrowsType = new NBTTagCompound(); - //iDiamondhunter.morebows.MoreBows.modLog.info("writing"); //debug - /** An over engineered system to save an arbitrary amount of entities */ for (int i = 0; i < arrows.length; i++) { final NBTTagCompound arrTag = new NBTTagCompound(); arrows[i].writeToNBT(arrTag); - //iDiamondhunter.morebows.MoreBows.modLog.info("arrow[" + i + "] " + arrTag.toString() + " getEntityString " + EntityList.getEntityString(arrows[i]) + " id " + EntityList.getEntityID(arrows[i])); //debug arrowsTag.setTag("arrow" + i, arrTag); arrowsType.setString("arrow" + i, EntityList.getEntityString(arrows[i])); } - //iDiamondhunter.morebows.MoreBows.modLog.info("arrows " + arrowsTag.toString()); //debug - tag.setByte("existed", existed); - tag.setFloat("shotVelocity", shotVelocity); + // These values are then saved with these tags tag.setTag("arrows", arrowsTag); tag.setTag("arrowsType", arrowsType); - tag.setInteger("arrowsAmount", arrows.length); } } diff --git a/src/main/java/iDiamondhunter/morebows/entities/CustomArrow.java b/src/main/java/iDiamondhunter/morebows/entities/CustomArrow.java index 1258beb..7a3b2b0 100644 --- a/src/main/java/iDiamondhunter/morebows/entities/CustomArrow.java +++ b/src/main/java/iDiamondhunter/morebows/entities/CustomArrow.java @@ -10,40 +10,44 @@ import net.minecraft.util.MathHelper; import net.minecraft.world.World; +/* This entity is a custom arrow. A large portion of logic around these arrows is handled in the MoreBows class with SubscribeEvents. TODO Better documentation. Re add custom arrow renderer for frost arrows. Weird rotation issues seem to be happening with the fire & frost arrows, but not the ender arrows. */ public class CustomArrow extends EntityArrow implements IEntityAdditionalSpawnData { public enum ArrowType { NOT_CUSTOM, BASE, FIRE, FROST; } - //* TODO Attempt to merge FrostArrow with this if possible (need to create custom renderer for the "snowball") */ - private ArrowType type = ArrowType.BASE; - private boolean crit = false; + private boolean crit = false; private byte inTicks = -1; + private ArrowType type = ArrowType.BASE; // TODO I think I can't remove these constructors, but I'm not sure. public CustomArrow(World world) { super(world); } + // TODO I think I can't remove these constructors, but I'm not sure. public CustomArrow(World world, double var1, double var2, double var3) { super(world, var1, var2, var3); } + // TODO I think I can't remove these constructors, but I'm not sure. public CustomArrow(World world, EntityLivingBase living1, EntityLivingBase living2, float var1, float var2) { super(world, living1, living2, var1, var2); } + // TODO I think I can't remove these constructors, but I'm not sure. public CustomArrow(World world, EntityLivingBase living, float var) { super(world, living, var); } + // TODO I think I can't remove these constructors, but I'm not sure. public CustomArrow(World world, EntityLivingBase living, float var, ArrowType type) { this(world, living, var); - - if ((this.type = type) == ArrowType.NOT_CUSTOM /* This should never happen, NOT_CUSTOM is only used as a reference point. */) { - setDead(); - } + this.type = type; + /* if (type == ArrowType.FROST) { // I'm not sure it makes sense for a frost arrow to be on fire, but I don't think people care about it that much, and the frost bow is a bit under powered as is... + this.extinguish(); + } */ } public final boolean getCrit() { @@ -61,27 +65,25 @@ public final boolean getCrit() { @Override public boolean getIsCritical() { if (type == ArrowType.FROST) { - //System.out.println("getIsCritical false " + type); return false; - /* Obviously, you're just a bad shot :D + /** Obviously, you're just a bad shot :D * - * This is an awful hack to prevent the vanilla crit particles from displaying. - * The vanilla code to display the arrow particle trail is buried deep inside onUpdate, - * and the only other options I have are to: - * - intercept the particles with packets, - * - intercept the particles with events (not feasible from what I can tell), - * - ASM it out, - * - or perform some ridiculous wrapping around the World to intercept the method to spawn particles. + * This is an awful hack to prevent the vanilla crit particles from displaying. + * The vanilla code to display the arrow particle trail is buried deep inside onUpdate, + * and the only other options I have are to: + * - intercept the particles with packets, + * - intercept the particles with events (not feasible from what I can tell), + * - ASM it out, + * - or perform some ridiculous wrapping around the World to intercept the method to spawn particles. * - * Instead of doing that, I just prevent anything from ever knowing that it's crited, - * and instead I wrap around the event when the arrow attacks something. See onLivingAttackEvent() for the details, - * but the TLDR is that I cancel the attack and start a new one with the crit taken into account. - * This allows the entity to take the crit into account when deciding if it's damaged or not. + * Instead of doing that, I just prevent anything from ever knowing that it's crited, + * and instead I wrap around the event when the arrow attacks something. See onLivingAttackEvent() for the details, + * but the TLDR is that I cancel the attack and start a new one with the crit taken into account. + * This allows the entity to take the crit into account when deciding if it's damaged or not. * - * This is probably the lesser of these evils. + * This is probably the lesser of these evils. */ } else { - //System.out.println("getIsCritical super " + type); return super.getIsCritical(); } } @@ -95,10 +97,11 @@ public void onUpdate() { super.onUpdate(); if (type == ArrowType.FROST) { - // Hack to determine when the arrow has hit the ground. inGround is a private field. - // Access transformers can be used for this, but they're are annoying to deal with and they aren't always safe. - // However, instead we can take advantage of the fact that arrowShake is always set to 7 after an arrow has hit the ground. - // inGround is used to store this information. + /** Hack to determine when the arrow has hit the ground. inGround is a private field. + * Access transformers can be used for this, but they're are annoying to deal with and they aren't always safe. + * However, instead we can take advantage of the fact that arrowShake is always set to 7 after an arrow has hit the ground. + * inGround is used to store this information. + */ if (arrowShake == 7) { inTicks = 0; canBePickedUp = 0; @@ -106,7 +109,6 @@ public void onUpdate() { if (inTicks > -1) { inTicks++; - //System.out.println(getEntityId() + " in - inTicks " + inTicks); if (inTicks <= 2) { worldObj.spawnParticle("snowballpoof", posX, posY, posZ, 0.0D, 0.0D, 0.0D); @@ -122,7 +124,6 @@ public void onUpdate() { worldObj.spawnParticle("splash", posX, posY - 0.3D, posZ, 0.0D, 0.0D, 0.0D); } - //if (this.ticksInGround >= 64 && this.ticksInGround <= 65) //Why was this the original logic? /** Responsible for adding snow layers on top the block the arrow hits, or "freezing" the water it's in by setting the block to ice. */ if (inTicks == 64) { final int arrX = MathHelper.floor_double(posX); @@ -147,16 +148,14 @@ public void onUpdate() { setDead(); } } else if (crit) { - //System.out.println(getEntityId() + " very crit"); for (int i = 0; i < 4; ++i) { + // No need for fancy server side particle handling worldObj.spawnParticle("splash", posX + ((motionX * i) / 4.0D), posY + ((motionY * i) / 4.0D), posZ + ((motionZ * i) / 4.0D), -motionX, -motionY + 0.2D, -motionZ); - //MoreBows.trySpawnParticle(worldObj, this, "splash", ParicleDisplacement.TRAIL, 0); } - - //MoreBows.spawnParticle(this.worldObj, this, "splash", 4); } } + // TODO Probably remove this // else if (crit && type == ArrowType.FIRE) { // if (((ticksExisted + 1) % 2) == 0) { // System.out.println("ticks existed " + this.ticksExisted); @@ -174,54 +173,58 @@ public void onUpdate() { public void readEntityFromNBT(NBTTagCompound tag) { super.readEntityFromNBT(tag); inTicks = tag.getByte("inTicks"); - //ArrowType.valueOf(arg0) - //ArrowType[] allTypes = ArrowType.values(); - //type = allTypes[tag.getByte("type")]; - //type = ArrowType.valueOf(tag.getString("type")); + crit = tag.getBoolean("crit"); - if ((type = ArrowType.valueOf(tag.getString("type"))) == ArrowType.NOT_CUSTOM /* This should never happen, NOT_CUSTOM is only used as a reference point. */) { - setDead(); + try { + /** It's completely possible that the ArrowType enums might change in the future if needed. */ + type = ArrowType.valueOf(tag.getString("type")); + } catch (final Exception e) { + /** If we don't know what the arrow type is, just ignore the issue. */ + e.printStackTrace(); + type = ArrowType.NOT_CUSTOM; } - - crit = tag.getBoolean("crit"); - //System.out.println("load from nbt " + type.name()); } @Override public void readSpawnData(ByteBuf additionalData) { - //int nameLength = additionalData.readInt(); - //byte[] typeBytes = additionalData.readBytes(nameLength).array(); - //String typeName = StringUtils.newStringIso8859_1(typeBytes); - //type = ArrowType.valueOf(typeName); - //System.out.println("readSpawnData - Recive " + typeBytes + " \nName is " + typeName); - type = ArrowType.values()[additionalData.readInt()]; crit = additionalData.readBoolean(); + + try { + /** This should really not need error handling, as this data should always be right (the ordinal should be the same between compatible servers and clients), but mistakes happen sometimes. */ + type = ArrowType.values()[additionalData.readInt()]; + } catch (final Exception e) { + /** Although this is a very strange error, it's probably OK to ignore it. */ + e.printStackTrace(); + type = ArrowType.NOT_CUSTOM; + } } @Override public void setIsCritical(boolean crit) { - /* This line of code brings a tear to my eye. It's glorious. */ super.setIsCritical(this.crit = crit); - //iDiamondhunter.morebows.MoreBows.modLog.info("setIsCritical " + crit); } @Override public void writeEntityToNBT(NBTTagCompound tag) { super.writeEntityToNBT(tag); tag.setByte("inTicks", inTicks); - tag.setString("type", type.name()); tag.setBoolean("crit", crit); + /** Hopefully saving this by name instead of ordinal should help prevent issues when loading with any changes made to enum order. */ + tag.setString("type", type.name()); } @Override public void writeSpawnData(ByteBuf buffer) { - //byte[] typeBytes = StringUtils.getBytesIso8859_1(type.name()); - //int nameLength = typeBytes.length; - //buffer.writeInt(nameLength); - //buffer.writeBytes(typeBytes); - //System.out.println("writeSpawnData - Send " + typeBytes); - buffer.writeInt(type.ordinal()); buffer.writeBoolean(crit); + /** Sending the ordinal instead of the enum name should save network overhead. This should be consistent between compatible servers and clients, so it shouldn't have any issues. */ + buffer.writeInt(type.ordinal()); } + /*@Override + public void extinguish() { // Might cause weird issues + if (type != ArrowType.FIRE) { + super.extinguish(); + } + }*/ + }