From da6b007a3a1ad5f055a2350cd6f2f1b01b10ce15 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Fri, 19 Jan 2018 20:33:04 +0000 Subject: [PATCH] Initial commit --- .gitattributes | 2 + .gitignore | 22 + CREDITS-fml.txt | 28 + LICENSE-new.txt | 483 + MinecraftForge-Credits.txt | 26 + Paulscode IBXM Library License.txt | 10 + Paulscode SoundSystem CodecIBXM License.txt | 40 + README.md | 1 + README.txt | 59 + build.gradle | 76 + forge-1.10.2-12.18.3.2185-changelog.txt | 11549 ++++++++++++++++ gradle.properties | 3 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 52271 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 + gradlew.bat | 90 + .../electroblob/wizardry/CommonProxy.java | 176 + .../java/electroblob/wizardry/Settings.java | 507 + .../electroblob/wizardry/SpellGlyphData.java | 161 + .../java/electroblob/wizardry/WizardData.java | 581 + .../java/electroblob/wizardry/Wizardry.java | 265 + .../wizardry/WizardryEventHandler.java | 938 ++ .../wizardry/WizardryGuiFactory.java | 36 + .../wizardry/WizardryGuiHandler.java | 66 + .../wizardry/WizardryKeyHandler.java | 67 + .../wizardry/WizardryWorldGenerator.java | 1546 +++ .../wizardry/block/BlockArcaneWorkbench.java | 120 + .../wizardry/block/BlockCrystalFlower.java | 46 + .../wizardry/block/BlockCrystalOre.java | 35 + .../wizardry/block/BlockMagicLight.java | 58 + .../wizardry/block/BlockSnare.java | 110 + .../wizardry/block/BlockSpectral.java | 94 + .../wizardry/block/BlockStatue.java | 146 + .../block/BlockTransportationStone.java | 115 + .../wizardry/block/BlockVanishingCobweb.java | 70 + .../wizardry/client/ClientProxy.java | 579 + .../wizardry/client/EntityNameEntry.java | 76 + .../wizardry/client/GuiArcaneWorkbench.java | 230 + .../wizardry/client/GuiButtonApply.java | 41 + .../wizardry/client/GuiButtonInvisible.java | 23 + .../wizardry/client/GuiButtonTurnPage.java | 52 + .../wizardry/client/GuiConfigWizardry.java | 80 + .../wizardry/client/GuiPortableCrafting.java | 39 + .../wizardry/client/GuiSpellBook.java | 127 + .../wizardry/client/GuiSpellDisplay.java | 155 + .../wizardry/client/GuiWizardHandbook.java | 809 ++ .../wizardry/client/MixedFontRenderer.java | 94 + .../wizardry/client/MovingSoundEntity.java | 59 + .../client/WizardryClientEventHandler.java | 752 + .../wizardry/client/model/ModelHammer.java | 83 + .../wizardry/client/model/ModelIceGiant.java | 321 + .../wizardry/client/model/ModelPhoenix.java | 139 + .../wizardry/client/model/ModelWizard.java | 174 + .../client/model/ModelWizardArmour.java | 111 + .../client/model/WizardryItemModels.java | 192 + .../client/particle/ParticleBlizzard.java | 72 + .../particle/ParticleCustomTexture.java | 195 + .../client/particle/ParticleDarkMagic.java | 90 + .../client/particle/ParticleDust.java | 57 + .../client/particle/ParticleGiantBubble.java | 50 + .../wizardry/client/particle/ParticleIce.java | 34 + .../client/particle/ParticleLeaf.java | 33 + .../client/particle/ParticleMagicFlame.java | 47 + .../client/particle/ParticlePath.java | 93 + .../particle/ParticleRotatingSparkle.java | 59 + .../client/particle/ParticleSnow.java | 33 + .../client/particle/ParticleSpark.java | 58 + .../client/particle/ParticleSparkle.java | 96 + .../client/particle/ParticleTornado.java | 83 + .../wizardry/client/renderer/LayerStone.java | 191 + .../wizardry/client/renderer/RayHelper.java | 48 + .../wizardry/client/renderer/RenderArc.java | 129 + .../renderer/RenderArcaneWorkbench.java | 99 + .../client/renderer/RenderBlackHole.java | 180 + .../wizardry/client/renderer/RenderBlank.java | 25 + .../client/renderer/RenderBubble.java | 104 + .../wizardry/client/renderer/RenderDecay.java | 74 + .../wizardry/client/renderer/RenderDecoy.java | 108 + .../client/renderer/RenderEvilWizard.java | 34 + .../client/renderer/RenderFireRing.java | 180 + .../client/renderer/RenderForceArrow.java | 127 + .../client/renderer/RenderHammer.java | 39 + .../client/renderer/RenderIceGiant.java | 39 + .../client/renderer/RenderIceSpike.java | 84 + .../client/renderer/RenderLightningDisc.java | 82 + .../client/renderer/RenderLightningPulse.java | 72 + .../client/renderer/RenderMagicArrow.java | 122 + .../client/renderer/RenderMagicLight.java | 130 + .../client/renderer/RenderPhoenix.java | 52 + .../client/renderer/RenderProjectile.java | 88 + .../wizardry/client/renderer/RenderSigil.java | 89 + .../client/renderer/RenderSpiritHorse.java | 36 + .../client/renderer/RenderSpiritWolf.java | 35 + .../client/renderer/RenderStatue.java | 64 + .../client/renderer/RenderWizard.java | 34 + .../client/renderer/RenderWraithMinion.java | 26 + .../wizardry/command/CommandCastSpell.java | 183 + .../command/CommandDiscoverSpell.java | 130 + .../wizardry/command/CommandSetAlly.java | 113 + .../wizardry/command/CommandViewAllies.java | 112 + .../wizardry/constants/Constants.java | 44 + .../wizardry/constants/Element.java | 67 + .../wizardry/constants/SpellType.java | 23 + .../electroblob/wizardry/constants/Tier.java | 81 + .../enchantment/EnchantmentMagicSword.java | 59 + .../enchantment/EnchantmentTimed.java | 48 + .../wizardry/enchantment/Imbuement.java | 11 + .../wizardry/entity/EntityArc.java | 73 + .../wizardry/entity/EntityMeteor.java | 127 + .../wizardry/entity/EntityShield.java | 94 + .../entity/construct/EntityArrowRain.java | 39 + .../entity/construct/EntityBlackHole.java | 138 + .../entity/construct/EntityBlizzard.java | 68 + .../entity/construct/EntityBubble.java | 123 + .../entity/construct/EntityDecay.java | 78 + .../entity/construct/EntityEarthquake.java | 107 + .../entity/construct/EntityFireRing.java | 67 + .../entity/construct/EntityFireSigil.java | 87 + .../entity/construct/EntityForcefield.java | 91 + .../entity/construct/EntityFrostSigil.java | 91 + .../entity/construct/EntityHailstorm.java | 37 + .../entity/construct/EntityHammer.java | 183 + .../entity/construct/EntityHealAura.java | 85 + .../entity/construct/EntityIceSpike.java | 50 + .../construct/EntityLightningPulse.java | 26 + .../construct/EntityLightningSigil.java | 125 + .../construct/EntityMagicConstruct.java | 153 + .../entity/construct/EntityTornado.java | 184 + .../entity/living/EntityAIAttackSpell.java | 211 + .../entity/living/EntityAISelectSpell.java | 14 + .../entity/living/EntityBlazeMinion.java | 160 + .../wizardry/entity/living/EntityDecoy.java | 107 + .../entity/living/EntityEvilWizard.java | 364 + .../entity/living/EntityIceGiant.java | 199 + .../entity/living/EntityIceWraith.java | 295 + .../entity/living/EntityLightningWraith.java | 179 + .../entity/living/EntityMagicSlime.java | 177 + .../wizardry/entity/living/EntityPhoenix.java | 189 + .../entity/living/EntityShadowWraith.java | 165 + .../entity/living/EntitySilverfishMinion.java | 183 + .../entity/living/EntitySkeletonMinion.java | 216 + .../entity/living/EntitySpiderMinion.java | 207 + .../entity/living/EntitySpiritHorse.java | 203 + .../entity/living/EntitySpiritWolf.java | 157 + .../entity/living/EntityStormElemental.java | 160 + .../entity/living/EntitySummonedCreature.java | 144 + .../wizardry/entity/living/EntityWizard.java | 803 ++ .../entity/living/EntityZombieMinion.java | 175 + .../living/IIntelligentSpellCaster.java | 20 + .../wizardry/entity/living/ISpellCaster.java | 61 + .../entity/living/ISummonedCreature.java | 278 + .../entity/projectile/EntityBomb.java | 59 + .../entity/projectile/EntityDarknessOrb.java | 88 + .../entity/projectile/EntityDart.java | 95 + .../entity/projectile/EntityFirebolt.java | 93 + .../entity/projectile/EntityFirebomb.java | 87 + .../entity/projectile/EntityForceArrow.java | 85 + .../entity/projectile/EntityForceOrb.java | 111 + .../entity/projectile/EntityIceCharge.java | 135 + .../entity/projectile/EntityIceLance.java | 117 + .../entity/projectile/EntityIceShard.java | 103 + .../projectile/EntityLightningArrow.java | 95 + .../projectile/EntityLightningDisc.java | 121 + .../entity/projectile/EntityMagicArrow.java | 582 + .../entity/projectile/EntityMagicMissile.java | 82 + .../projectile/EntityMagicProjectile.java | 79 + .../entity/projectile/EntityPoisonBomb.java | 85 + .../entity/projectile/EntitySmokeBomb.java | 81 + .../entity/projectile/EntitySpark.java | 116 + .../entity/projectile/EntitySparkBomb.java | 124 + .../entity/projectile/EntityThunderbolt.java | 100 + .../wizardry/event/DiscoverSpellEvent.java | 35 + .../wizardry/event/SpellBindEvent.java | 28 + .../wizardry/event/SpellCastEvent.java | 22 + .../wizardry/item/IConjuredItem.java | 32 + .../wizardry/item/ItemArcaneTome.java | 59 + .../wizardry/item/ItemArmourUpgrade.java | 46 + .../wizardry/item/ItemFirebomb.java | 50 + .../wizardry/item/ItemFlamingAxe.java | 92 + .../wizardry/item/ItemFrostAxe.java | 94 + .../item/ItemIdentificationScroll.java | 81 + .../wizardry/item/ItemPoisonBomb.java | 51 + .../electroblob/wizardry/item/ItemScroll.java | 139 + .../wizardry/item/ItemSmokeBomb.java | 50 + .../wizardry/item/ItemSpectralArmour.java | 110 + .../wizardry/item/ItemSpectralBow.java | 229 + .../wizardry/item/ItemSpectralPickaxe.java | 82 + .../wizardry/item/ItemSpectralSword.java | 82 + .../wizardry/item/ItemSpellBook.java | 82 + .../electroblob/wizardry/item/ItemWand.java | 430 + .../wizardry/item/ItemWizardArmour.java | 217 + .../wizardry/item/ItemWizardHandbook.java | 46 + .../wizardry/loot/RandomSpell.java | 259 + .../wizardry/loot/WizardSpell.java | 65 + .../packet/PacketCastContinuousSpell.java | 70 + .../wizardry/packet/PacketCastSpell.java | 80 + .../wizardry/packet/PacketClairvoyance.java | 81 + .../wizardry/packet/PacketControlInput.java | 102 + .../wizardry/packet/PacketGlyphData.java | 70 + .../wizardry/packet/PacketNPCCastSpell.java | 80 + .../wizardry/packet/PacketPlayerSync.java | 71 + .../wizardry/packet/PacketSyncSettings.java | 90 + .../wizardry/packet/PacketTransportation.java | 58 + .../packet/WizardryPacketHandler.java | 36 + .../potion/ICustomPotionParticles.java | 23 + .../wizardry/potion/PotionDecay.java | 53 + .../wizardry/potion/PotionFrost.java | 53 + .../wizardry/potion/PotionMagicEffect.java | 42 + .../potion/PotionMagicEffectParticles.java | 11 + .../electroblob/wizardry/registry/Spells.java | 351 + .../registry/WizardryAchievements.java | 47 + .../wizardry/registry/WizardryBlocks.java | 92 + .../registry/WizardryEnchantments.java | 41 + .../wizardry/registry/WizardryItems.java | 419 + .../wizardry/registry/WizardryPotions.java | 113 + .../wizardry/registry/WizardryRegistry.java | 320 + .../wizardry/registry/WizardrySounds.java | 68 + .../wizardry/registry/WizardryTabs.java | 175 + .../electroblob/wizardry/spell/Agility.java | 46 + .../java/electroblob/wizardry/spell/Arc.java | 105 + .../wizardry/spell/ArcaneJammer.java | 95 + .../electroblob/wizardry/spell/ArrowRain.java | 57 + .../electroblob/wizardry/spell/Banish.java | 159 + .../electroblob/wizardry/spell/BlackHole.java | 66 + .../electroblob/wizardry/spell/Blink.java | 134 + .../electroblob/wizardry/spell/Blizzard.java | 75 + .../electroblob/wizardry/spell/Bubble.java | 110 + .../wizardry/spell/ChainLightning.java | 141 + .../wizardry/spell/Clairvoyance.java | 127 + .../electroblob/wizardry/spell/Cobwebs.java | 133 + .../wizardry/spell/ConjureArmour.java | 85 + .../wizardry/spell/ConjureBow.java | 58 + .../wizardry/spell/ConjurePickaxe.java | 48 + .../wizardry/spell/ConjureSword.java | 48 + .../wizardry/spell/CureEffects.java | 72 + .../wizardry/spell/CurseOfSoulbinding.java | 57 + .../wizardry/spell/DarknessOrb.java | 65 + .../wizardry/spell/Darkvision.java | 42 + .../java/electroblob/wizardry/spell/Dart.java | 63 + .../electroblob/wizardry/spell/Decay.java | 97 + .../electroblob/wizardry/spell/Decoy.java | 83 + .../electroblob/wizardry/spell/Detonate.java | 99 + .../wizardry/spell/Diamondflesh.java | 50 + .../wizardry/spell/Earthquake.java | 61 + .../wizardry/spell/Entrapment.java | 106 + .../wizardry/spell/FireResistance.java | 72 + .../electroblob/wizardry/spell/FireSigil.java | 50 + .../electroblob/wizardry/spell/Fireball.java | 87 + .../electroblob/wizardry/spell/Firebolt.java | 68 + .../electroblob/wizardry/spell/Firebomb.java | 66 + .../electroblob/wizardry/spell/Fireskin.java | 67 + .../electroblob/wizardry/spell/Firestorm.java | 79 + .../electroblob/wizardry/spell/FlameRay.java | 96 + .../wizardry/spell/FlamingAxe.java | 49 + .../wizardry/spell/FlamingWeapon.java | 67 + .../electroblob/wizardry/spell/Flight.java | 49 + .../wizardry/spell/FontOfMana.java | 55 + .../wizardry/spell/FontOfVitality.java | 53 + .../wizardry/spell/ForceArrow.java | 65 + .../electroblob/wizardry/spell/ForceOrb.java | 66 + .../wizardry/spell/Forcefield.java | 69 + .../wizardry/spell/ForestsCurse.java | 64 + .../electroblob/wizardry/spell/Freeze.java | 158 + .../wizardry/spell/FreezingWeapon.java | 71 + .../electroblob/wizardry/spell/FrostAxe.java | 50 + .../electroblob/wizardry/spell/FrostRay.java | 132 + .../wizardry/spell/FrostSigil.java | 50 + .../electroblob/wizardry/spell/Glide.java | 46 + .../wizardry/spell/GreaterFireball.java | 86 + .../wizardry/spell/GreaterHeal.java | 63 + .../electroblob/wizardry/spell/GroupHeal.java | 89 + .../wizardry/spell/GrowthAura.java | 75 + .../electroblob/wizardry/spell/Hailstorm.java | 57 + .../java/electroblob/wizardry/spell/Heal.java | 67 + .../electroblob/wizardry/spell/HealAlly.java | 54 + .../wizardry/spell/HealingAura.java | 62 + .../wizardry/spell/HomingSpark.java | 63 + .../electroblob/wizardry/spell/IceAge.java | 147 + .../electroblob/wizardry/spell/IceCharge.java | 66 + .../electroblob/wizardry/spell/IceLance.java | 63 + .../electroblob/wizardry/spell/IceShard.java | 63 + .../electroblob/wizardry/spell/IceShroud.java | 67 + .../electroblob/wizardry/spell/IceSpikes.java | 108 + .../electroblob/wizardry/spell/IceStatue.java | 120 + .../electroblob/wizardry/spell/Ignite.java | 136 + .../wizardry/spell/ImbueWeapon.java | 76 + .../wizardry/spell/Intimidate.java | 105 + .../wizardry/spell/InvigoratingPresence.java | 54 + .../wizardry/spell/Invisibility.java | 72 + .../wizardry/spell/InvokeWeather.java | 67 + .../electroblob/wizardry/spell/Ironflesh.java | 73 + .../java/electroblob/wizardry/spell/Leap.java | 47 + .../wizardry/spell/Levitation.java | 39 + .../electroblob/wizardry/spell/LifeDrain.java | 102 + .../electroblob/wizardry/spell/Light.java | 77 + .../wizardry/spell/LightningArrow.java | 65 + .../wizardry/spell/LightningBolt.java | 90 + .../wizardry/spell/LightningDisc.java | 65 + .../wizardry/spell/LightningHammer.java | 61 + .../wizardry/spell/LightningPulse.java | 80 + .../wizardry/spell/LightningRay.java | 143 + .../wizardry/spell/LightningSigil.java | 52 + .../wizardry/spell/LightningWeb.java | 193 + .../wizardry/spell/MagicMissile.java | 67 + .../wizardry/spell/Metamorphosis.java | 132 + .../electroblob/wizardry/spell/Meteor.java | 55 + .../wizardry/spell/MindControl.java | 169 + .../electroblob/wizardry/spell/MindTrick.java | 100 + .../java/electroblob/wizardry/spell/None.java | 32 + .../electroblob/wizardry/spell/Oakflesh.java | 73 + .../electroblob/wizardry/spell/Petrify.java | 114 + .../electroblob/wizardry/spell/PhaseStep.java | 80 + .../wizardry/spell/PlagueOfDarkness.java | 72 + .../wizardry/spell/PocketFurnace.java | 72 + .../wizardry/spell/PocketWorkbench.java | 40 + .../electroblob/wizardry/spell/Poison.java | 108 + .../wizardry/spell/PoisonBomb.java | 66 + .../wizardry/spell/ReplenishHunger.java | 44 + .../wizardry/spell/RingOfFire.java | 68 + .../wizardry/spell/ShadowWard.java | 39 + .../electroblob/wizardry/spell/Shield.java | 42 + .../electroblob/wizardry/spell/Shockwave.java | 99 + .../wizardry/spell/SilverfishSwarm.java | 47 + .../wizardry/spell/SixthSense.java | 41 + .../electroblob/wizardry/spell/Slime.java | 117 + .../electroblob/wizardry/spell/SmokeBomb.java | 66 + .../electroblob/wizardry/spell/Snare.java | 66 + .../electroblob/wizardry/spell/Snowball.java | 41 + .../electroblob/wizardry/spell/SparkBomb.java | 66 + .../wizardry/spell/SpectralPathway.java | 80 + .../electroblob/wizardry/spell/Spell.java | 424 + .../wizardry/spell/SpiderSwarm.java | 72 + .../wizardry/spell/StaticAura.java | 67 + .../wizardry/spell/SummonBlaze.java | 67 + .../wizardry/spell/SummonIceGiant.java | 51 + .../wizardry/spell/SummonIceWraith.java | 66 + .../wizardry/spell/SummonIronGolem.java | 50 + .../wizardry/spell/SummonLightningWraith.java | 65 + .../wizardry/spell/SummonPhoenix.java | 46 + .../wizardry/spell/SummonShadowWraith.java | 51 + .../wizardry/spell/SummonSkeleton.java | 72 + .../wizardry/spell/SummonSkeletonLegion.java | 75 + .../wizardry/spell/SummonSnowGolem.java | 48 + .../wizardry/spell/SummonSpiritHorse.java | 53 + .../wizardry/spell/SummonSpiritWolf.java | 52 + .../wizardry/spell/SummonStormElemental.java | 42 + .../wizardry/spell/SummonWitherSkeleton.java | 75 + .../wizardry/spell/SummonZombie.java | 64 + .../wizardry/spell/Telekinesis.java | 114 + .../wizardry/spell/Thunderbolt.java | 65 + .../wizardry/spell/Thunderstorm.java | 119 + .../electroblob/wizardry/spell/Tornado.java | 72 + .../wizardry/spell/Transience.java | 44 + .../wizardry/spell/Transportation.java | 61 + .../wizardry/spell/VanishingBox.java | 43 + .../wizardry/spell/WallOfFrost.java | 91 + .../wizardry/spell/WaterBreathing.java | 42 + .../electroblob/wizardry/spell/Whirlwind.java | 99 + .../electroblob/wizardry/spell/Wither.java | 113 + .../wizardry/spell/WitherSkull.java | 85 + .../tileentity/ContainerArcaneWorkbench.java | 265 + .../ContainerPortableWorkbench.java | 23 + .../wizardry/tileentity/SlotItemList.java | 36 + .../wizardry/tileentity/SlotWandArmour.java | 49 + .../tileentity/TileEntityArcaneWorkbench.java | 481 + .../tileentity/TileEntityMagicLight.java | 53 + .../tileentity/TileEntityPlayerSave.java | 72 + .../wizardry/tileentity/TileEntityStatue.java | 174 + .../wizardry/tileentity/TileEntityTimer.java | 76 + .../wizardry/util/IElementalDamage.java | 17 + .../wizardry/util/IndirectMagicDamage.java | 28 + .../wizardry/util/IndirectMinionDamage.java | 35 + .../wizardry/util/MagicDamage.java | 264 + .../wizardry/util/MinionDamage.java | 32 + .../wizardry/util/SpellModifiers.java | 141 + .../electroblob/wizardry/util/WandHelper.java | 290 + .../wizardry/util/WizardryParticleType.java | 19 + .../wizardry/util/WizardryPathFinder.java | 136 + .../wizardry/util/WizardryUtilities.java | 967 ++ .../blockstates/arcane_workbench.json | 6 + .../wizardry/blockstates/crystal_block.json | 6 + .../wizardry/blockstates/crystal_flower.json | 5 + .../wizardry/blockstates/crystal_ore.json | 6 + .../wizardry/blockstates/ice_statue.json | 6 + .../wizardry/blockstates/magic_light.json | 6 + .../assets/wizardry/blockstates/meteor.json | 6 + .../wizardry/blockstates/petrified_stone.json | 6 + .../assets/wizardry/blockstates/snare.json | 6 + .../wizardry/blockstates/spectral_block.json | 6 + .../blockstates/transportation_stone.json | 6 + .../blockstates/vanishing_cobweb.json | 6 + .../resources/assets/wizardry/lang/en_GB.lang | 738 + .../resources/assets/wizardry/lang/en_US.lang | 738 + .../resources/assets/wizardry/lang/es_ES.lang | 736 + .../resources/assets/wizardry/lang/es_MX.lang | 736 + .../resources/assets/wizardry/lang/ru_RU.lang | 519 + .../loot_tables/chests/dungeon_additions.json | 92 + .../loot_tables/chests/wizard_tower.json | 77 + .../loot_tables/entities/evil_wizard.json | 55 + .../loot_tables/entities/mob_additions.json | 29 + .../loot_tables/subsets/arcane_tomes.json | 46 + .../loot_tables/subsets/novice_wands.json | 50 + .../loot_tables/subsets/wand_upgrades.json | 50 + .../loot_tables/subsets/wizard_armour.json | 170 + .../models/block/arcane_workbench.json | 21 + .../wizardry/models/block/crystal_block.json | 6 + .../wizardry/models/block/crystal_flower.json | 6 + .../wizardry/models/block/crystal_ore.json | 6 + .../wizardry/models/block/ice_statue.json | 3 + .../wizardry/models/block/magic_light.json | 16 + .../assets/wizardry/models/block/meteor.json | 6 + .../models/block/petrified_stone.json | 20 + .../assets/wizardry/models/block/snare.json | 16 + .../wizardry/models/block/spectral_block.json | 6 + .../models/block/transportation_stone.json | 20 + .../models/block/vanishing_cobweb.json | 6 + .../models/item/advanced_earth_wand.json | 6 + .../models/item/advanced_fire_wand.json | 6 + .../models/item/advanced_healing_wand.json | 6 + .../models/item/advanced_ice_wand.json | 6 + .../models/item/advanced_lightning_wand.json | 6 + .../models/item/advanced_necromancy_wand.json | 6 + .../models/item/advanced_sorcery_wand.json | 6 + .../wizardry/models/item/advanced_wand.json | 6 + .../models/item/apprentice_earth_wand.json | 6 + .../models/item/apprentice_fire_wand.json | 6 + .../models/item/apprentice_healing_wand.json | 6 + .../models/item/apprentice_ice_wand.json | 6 + .../item/apprentice_lightning_wand.json | 6 + .../item/apprentice_necromancy_wand.json | 6 + .../models/item/apprentice_sorcery_wand.json | 6 + .../wizardry/models/item/apprentice_wand.json | 6 + .../wizardry/models/item/arcane_tome.json | 6 + .../models/item/arcane_workbench.json | 3 + .../wizardry/models/item/armour_upgrade.json | 6 + .../models/item/attunement_upgrade.json | 6 + .../models/item/basic_earth_wand.json | 6 + .../wizardry/models/item/basic_fire_wand.json | 6 + .../models/item/basic_healing_wand.json | 6 + .../wizardry/models/item/basic_ice_wand.json | 6 + .../models/item/basic_lightning_wand.json | 6 + .../models/item/basic_necromancy_wand.json | 6 + .../models/item/basic_sorcery_wand.json | 6 + .../wizardry/models/item/blank_scroll.json | 6 + .../wizardry/models/item/blast_upgrade.json | 6 + .../models/item/condenser_upgrade.json | 6 + .../models/item/cooldown_upgrade.json | 6 + .../wizardry/models/item/crystal_block.json | 3 + .../wizardry/models/item/crystal_flower.json | 6 + .../wizardry/models/item/crystal_ore.json | 3 + .../models/item/duration_upgrade.json | 6 + .../assets/wizardry/models/item/firebomb.json | 6 + .../wizardry/models/item/flaming_axe.json | 6 + .../wizardry/models/item/frost_axe.json | 6 + .../wizardry/models/item/ice_statue.json | 3 + .../models/item/identification_scroll.json | 6 + .../wizardry/models/item/magic_crystal.json | 6 + .../wizardry/models/item/magic_light.json | 3 + .../wizardry/models/item/magic_silk.json | 6 + .../wizardry/models/item/magic_wand.json | 6 + .../wizardry/models/item/mana_flask.json | 6 + .../models/item/master_earth_wand.json | 6 + .../models/item/master_fire_wand.json | 6 + .../models/item/master_healing_wand.json | 6 + .../wizardry/models/item/master_ice_wand.json | 6 + .../models/item/master_lightning_wand.json | 6 + .../models/item/master_necromancy_wand.json | 6 + .../models/item/master_sorcery_wand.json | 6 + .../wizardry/models/item/master_wand.json | 6 + .../assets/wizardry/models/item/meteor.json | 3 + .../wizardry/models/item/petrified_stone.json | 3 + .../wizardry/models/item/poison_bomb.json | 6 + .../wizardry/models/item/range_upgrade.json | 6 + .../assets/wizardry/models/item/scroll.json | 6 + .../wizardry/models/item/siphon_upgrade.json | 6 + .../wizardry/models/item/smoke_bomb.json | 6 + .../assets/wizardry/models/item/snare.json | 6 + .../wizardry/models/item/spawn_wizard.json | 7 + .../wizardry/models/item/spectral_block.json | 3 + .../wizardry/models/item/spectral_boots.json | 6 + .../wizardry/models/item/spectral_bow.json | 50 + .../models/item/spectral_bow_pulling_0.json | 6 + .../models/item/spectral_bow_pulling_1.json | 6 + .../models/item/spectral_bow_pulling_2.json | 6 + .../models/item/spectral_chestplate.json | 6 + .../wizardry/models/item/spectral_helmet.json | 6 + .../models/item/spectral_leggings.json | 6 + .../models/item/spectral_pickaxe.json | 6 + .../wizardry/models/item/spectral_sword.json | 6 + .../wizardry/models/item/spell_book.json | 6 + .../wizardry/models/item/storage_upgrade.json | 6 + .../models/item/transportation_stone.json | 3 + .../models/item/vanishing_cobweb.json | 6 + .../wizardry/models/item/wizard_boots.json | 6 + .../models/item/wizard_boots_earth.json | 6 + .../models/item/wizard_boots_fire.json | 6 + .../models/item/wizard_boots_healing.json | 6 + .../models/item/wizard_boots_ice.json | 6 + .../models/item/wizard_boots_lightning.json | 6 + .../models/item/wizard_boots_necromancy.json | 6 + .../models/item/wizard_boots_sorcery.json | 6 + .../wizardry/models/item/wizard_handbook.json | 6 + .../wizardry/models/item/wizard_hat.json | 6 + .../models/item/wizard_hat_earth.json | 6 + .../wizardry/models/item/wizard_hat_fire.json | 6 + .../models/item/wizard_hat_healing.json | 6 + .../wizardry/models/item/wizard_hat_ice.json | 6 + .../models/item/wizard_hat_lightning.json | 6 + .../models/item/wizard_hat_necromancy.json | 6 + .../models/item/wizard_hat_sorcery.json | 6 + .../wizardry/models/item/wizard_leggings.json | 6 + .../models/item/wizard_leggings_earth.json | 6 + .../models/item/wizard_leggings_fire.json | 6 + .../models/item/wizard_leggings_healing.json | 6 + .../models/item/wizard_leggings_ice.json | 6 + .../item/wizard_leggings_lightning.json | 6 + .../item/wizard_leggings_necromancy.json | 6 + .../models/item/wizard_leggings_sorcery.json | 6 + .../wizardry/models/item/wizard_robe.json | 6 + .../models/item/wizard_robe_earth.json | 6 + .../models/item/wizard_robe_fire.json | 6 + .../models/item/wizard_robe_healing.json | 6 + .../wizardry/models/item/wizard_robe_ice.json | 6 + .../models/item/wizard_robe_lightning.json | 6 + .../models/item/wizard_robe_necromancy.json | 6 + .../models/item/wizard_robe_sorcery.json | 6 + .../resources/assets/wizardry/sounds.json | 39 + .../resources/assets/wizardry/sounds/arc1.ogg | Bin 0 -> 19855 bytes .../resources/assets/wizardry/sounds/arc2.ogg | Bin 0 -> 13963 bytes .../resources/assets/wizardry/sounds/arc3.ogg | Bin 0 -> 14309 bytes .../resources/assets/wizardry/sounds/aura.ogg | Bin 0 -> 28530 bytes .../resources/assets/wizardry/sounds/boom.ogg | Bin 0 -> 38721 bytes .../assets/wizardry/sounds/crackle.ogg | Bin 0 -> 25145 bytes .../assets/wizardry/sounds/darkaura1.ogg | Bin 0 -> 28323 bytes .../assets/wizardry/sounds/darkaura2.ogg | Bin 0 -> 56426 bytes .../assets/wizardry/sounds/effect1.ogg | Bin 0 -> 33685 bytes .../assets/wizardry/sounds/effect2.ogg | Bin 0 -> 29616 bytes .../assets/wizardry/sounds/electricitya.ogg | Bin 0 -> 21626 bytes .../assets/wizardry/sounds/electricityb.ogg | Bin 0 -> 26461 bytes .../assets/wizardry/sounds/flameray1.ogg | Bin 0 -> 23817 bytes .../assets/wizardry/sounds/flameray2.ogg | Bin 0 -> 31282 bytes .../assets/wizardry/sounds/force.ogg | Bin 0 -> 32548 bytes .../assets/wizardry/sounds/freeze.ogg | Bin 0 -> 19753 bytes .../assets/wizardry/sounds/frostray.ogg | Bin 0 -> 40652 bytes .../resources/assets/wizardry/sounds/heal.ogg | Bin 0 -> 24691 bytes .../resources/assets/wizardry/sounds/ice.ogg | Bin 0 -> 19226 bytes .../assets/wizardry/sounds/largeaura.ogg | Bin 0 -> 49796 bytes .../assets/wizardry/sounds/magic1.ogg | Bin 0 -> 16877 bytes .../assets/wizardry/sounds/magic2.ogg | Bin 0 -> 19283 bytes .../assets/wizardry/sounds/magic3.ogg | Bin 0 -> 15372 bytes .../assets/wizardry/sounds/magic4.ogg | Bin 0 -> 23573 bytes .../assets/wizardry/sounds/rumble.ogg | Bin 0 -> 58391 bytes .../assets/wizardry/sounds/sparkle.ogg | Bin 0 -> 49399 bytes .../resources/assets/wizardry/sounds/wind.ogg | Bin 0 -> 107150 bytes .../assets/wizardry/texts/handbook_en_GB.txt | 217 + .../assets/wizardry/texts/handbook_en_US.txt | 217 + .../assets/wizardry/texts/handbook_es_ES.txt | 311 + .../assets/wizardry/texts/handbook_es_MX.txt | 311 + .../assets/wizardry/texts/handbook_ru_RU.txt | 222 + .../textures/armour/invisible_armour.png | Bin 0 -> 2411 bytes .../textures/armour/spectral_armour.png | Bin 0 -> 2024 bytes .../textures/armour/spectral_armour_legs.png | Bin 0 -> 990 bytes .../textures/armour/wizard_armour.png | Bin 0 -> 2566 bytes .../textures/armour/wizard_armour_earth.png | Bin 0 -> 2803 bytes .../armour/wizard_armour_earth_legs.png | Bin 0 -> 425 bytes .../textures/armour/wizard_armour_fire.png | Bin 0 -> 2807 bytes .../armour/wizard_armour_fire_legs.png | Bin 0 -> 430 bytes .../textures/armour/wizard_armour_healing.png | Bin 0 -> 2797 bytes .../armour/wizard_armour_healing_legs.png | Bin 0 -> 417 bytes .../textures/armour/wizard_armour_ice.png | Bin 0 -> 2781 bytes .../armour/wizard_armour_ice_legs.png | Bin 0 -> 417 bytes .../textures/armour/wizard_armour_legs.png | Bin 0 -> 406 bytes .../armour/wizard_armour_lightning.png | Bin 0 -> 2787 bytes .../armour/wizard_armour_lightning_legs.png | Bin 0 -> 429 bytes .../armour/wizard_armour_necromancy.png | Bin 0 -> 2800 bytes .../armour/wizard_armour_necromancy_legs.png | Bin 0 -> 431 bytes .../textures/armour/wizard_armour_sorcery.png | Bin 0 -> 2792 bytes .../armour/wizard_armour_sorcery_legs.png | Bin 0 -> 416 bytes .../assets/wizardry/textures/blocks/Thumbs.db | Bin 0 -> 7680 bytes .../blocks/arcane_workbench_bottom.png | Bin 0 -> 754 bytes .../textures/blocks/arcane_workbench_side.png | Bin 0 -> 694 bytes .../textures/blocks/arcane_workbench_top.png | Bin 0 -> 569 bytes .../textures/blocks/crystal_block.png | Bin 0 -> 794 bytes .../textures/blocks/crystal_flower.png | Bin 0 -> 392 bytes .../wizardry/textures/blocks/crystal_ore.png | Bin 0 -> 651 bytes .../wizardry/textures/blocks/meteor.png | Bin 0 -> 937 bytes .../assets/wizardry/textures/blocks/snare.png | Bin 0 -> 568 bytes .../textures/blocks/spectral_block.png | Bin 0 -> 312 bytes .../textures/blocks/transportation_stone.png | Bin 0 -> 756 bytes .../assets/wizardry/textures/entity/Thumbs.db | Bin 0 -> 71168 bytes .../assets/wizardry/textures/entity/arc_0.png | Bin 0 -> 4071 bytes .../assets/wizardry/textures/entity/arc_1.png | Bin 0 -> 4037 bytes .../wizardry/textures/entity/arc_10.png | Bin 0 -> 3619 bytes .../wizardry/textures/entity/arc_11.png | Bin 0 -> 3865 bytes .../wizardry/textures/entity/arc_12.png | Bin 0 -> 3836 bytes .../wizardry/textures/entity/arc_13.png | Bin 0 -> 3868 bytes .../wizardry/textures/entity/arc_14.png | Bin 0 -> 3891 bytes .../wizardry/textures/entity/arc_15.png | Bin 0 -> 3830 bytes .../assets/wizardry/textures/entity/arc_2.png | Bin 0 -> 4126 bytes .../assets/wizardry/textures/entity/arc_3.png | Bin 0 -> 4071 bytes .../assets/wizardry/textures/entity/arc_4.png | Bin 0 -> 4167 bytes .../assets/wizardry/textures/entity/arc_5.png | Bin 0 -> 3858 bytes .../assets/wizardry/textures/entity/arc_6.png | Bin 0 -> 3756 bytes .../assets/wizardry/textures/entity/arc_7.png | Bin 0 -> 3685 bytes .../assets/wizardry/textures/entity/arc_8.png | Bin 0 -> 3611 bytes .../assets/wizardry/textures/entity/arc_9.png | Bin 0 -> 3617 bytes .../assets/wizardry/textures/entity/aura.png | Bin 0 -> 1165 bytes .../wizardry/textures/entity/black_hole.png | Bin 0 -> 1109 bytes .../wizardry/textures/entity/dark_orb.png | Bin 0 -> 4968 bytes .../wizardry/textures/entity/dark_ray.png | Bin 0 -> 1079 bytes .../wizardry/textures/entity/darkness_orb.png | Bin 0 -> 1691 bytes .../assets/wizardry/textures/entity/dart.png | Bin 0 -> 603 bytes .../wizardry/textures/entity/decay_0.png | Bin 0 -> 499 bytes .../wizardry/textures/entity/decay_1.png | Bin 0 -> 566 bytes .../wizardry/textures/entity/decay_2.png | Bin 0 -> 538 bytes .../wizardry/textures/entity/decay_3.png | Bin 0 -> 652 bytes .../wizardry/textures/entity/decay_4.png | Bin 0 -> 602 bytes .../wizardry/textures/entity/decay_5.png | Bin 0 -> 584 bytes .../wizardry/textures/entity/decay_6.png | Bin 0 -> 633 bytes .../wizardry/textures/entity/decay_7.png | Bin 0 -> 555 bytes .../wizardry/textures/entity/decay_8.png | Bin 0 -> 645 bytes .../wizardry/textures/entity/decay_9.png | Bin 0 -> 642 bytes .../textures/entity/evil_wizard_0.png | Bin 0 -> 1639 bytes .../textures/entity/evil_wizard_1.png | Bin 0 -> 1639 bytes .../textures/entity/evil_wizard_2.png | Bin 0 -> 1725 bytes .../textures/entity/evil_wizard_3.png | Bin 0 -> 1674 bytes .../textures/entity/evil_wizard_4.png | Bin 0 -> 1663 bytes .../textures/entity/evil_wizard_5.png | Bin 0 -> 1663 bytes .../wizardry/textures/entity/fire_sigil.png | Bin 0 -> 2116 bytes .../wizardry/textures/entity/firebolt.png | Bin 0 -> 255 bytes .../wizardry/textures/entity/force_arrow.png | Bin 0 -> 1051 bytes .../wizardry/textures/entity/force_orb.png | Bin 0 -> 2344 bytes .../wizardry/textures/entity/frost_sigil.png | Bin 0 -> 2199 bytes .../wizardry/textures/entity/healing_aura.png | Bin 0 -> 3819 bytes .../wizardry/textures/entity/ice_charge.png | Bin 0 -> 516 bytes .../wizardry/textures/entity/ice_giant.png | Bin 0 -> 13984 bytes .../wizardry/textures/entity/ice_lance.png | Bin 0 -> 551 bytes .../wizardry/textures/entity/ice_shard.png | Bin 0 -> 530 bytes .../wizardry/textures/entity/ice_spike.png | Bin 0 -> 446 bytes .../wizardry/textures/entity/ice_wraith.png | Bin 0 -> 3276 bytes .../wizardry/textures/entity/light_aura.png | Bin 0 -> 2244 bytes .../wizardry/textures/entity/light_ray.png | Bin 0 -> 770 bytes .../textures/entity/lightning_arrow.png | Bin 0 -> 420 bytes .../textures/entity/lightning_hammer.png | Bin 0 -> 4603 bytes .../textures/entity/lightning_pulse_0.png | Bin 0 -> 834 bytes .../textures/entity/lightning_pulse_1.png | Bin 0 -> 1779 bytes .../textures/entity/lightning_pulse_2.png | Bin 0 -> 2584 bytes .../textures/entity/lightning_pulse_3.png | Bin 0 -> 3765 bytes .../textures/entity/lightning_pulse_4.png | Bin 0 -> 5044 bytes .../textures/entity/lightning_pulse_5.png | Bin 0 -> 6073 bytes .../textures/entity/lightning_pulse_6.png | Bin 0 -> 4628 bytes .../textures/entity/lightning_pulse_7.png | Bin 0 -> 1943 bytes .../textures/entity/lightning_sigil.png | Bin 0 -> 2675 bytes .../textures/entity/lightning_wraith.png | Bin 0 -> 3399 bytes .../textures/entity/magic_missile.png | Bin 0 -> 863 bytes .../wizardry/textures/entity/phoenix.png | Bin 0 -> 4574 bytes .../wizardry/textures/entity/pointer.png | Bin 0 -> 808 bytes .../wizardry/textures/entity/ring_of_fire.png | Bin 0 -> 6911 bytes .../assets/wizardry/textures/entity/rune.png | Bin 0 -> 2240 bytes .../wizardry/textures/entity/shadow_ward.png | Bin 0 -> 4717 bytes .../wizardry/textures/entity/shield.png | Bin 0 -> 1255 bytes .../wizardry/textures/entity/sixth_sense.png | Bin 0 -> 1023 bytes .../assets/wizardry/textures/entity/spark.png | Bin 0 -> 855 bytes .../wizardry/textures/entity/spark_bomb.png | Bin 0 -> 442 bytes .../wizardry/textures/entity/spirit_horse.png | Bin 0 -> 10374 bytes .../wizardry/textures/entity/spirit_wolf.png | Bin 0 -> 2818 bytes .../textures/entity/stone_statue_32.png | Bin 0 -> 507 bytes .../textures/entity/stone_statue_64.png | Bin 0 -> 574 bytes .../textures/entity/target_pointer.png | Bin 0 -> 844 bytes .../assets/wizardry/textures/entity/wing.png | Bin 0 -> 1471 bytes .../wizardry/textures/entity/wizard_0.png | Bin 0 -> 1558 bytes .../wizardry/textures/entity/wizard_1.png | Bin 0 -> 1556 bytes .../wizardry/textures/entity/wizard_2.png | Bin 0 -> 1557 bytes .../wizardry/textures/entity/wizard_3.png | Bin 0 -> 1584 bytes .../wizardry/textures/entity/wizard_4.png | Bin 0 -> 1582 bytes .../wizardry/textures/entity/wizard_5.png | Bin 0 -> 1583 bytes .../assets/wizardry/textures/gui/Thumbs.db | Bin 0 -> 182272 bytes .../textures/gui/arcane_workbench.png | Bin 0 -> 4698 bytes .../wizardry/textures/gui/decay_icon.png | Bin 0 -> 637 bytes .../textures/gui/element_icon_earth.png | Bin 0 -> 368 bytes .../textures/gui/element_icon_fire.png | Bin 0 -> 280 bytes .../textures/gui/element_icon_healing.png | Bin 0 -> 312 bytes .../textures/gui/element_icon_ice.png | Bin 0 -> 330 bytes .../textures/gui/element_icon_lightning.png | Bin 0 -> 290 bytes .../textures/gui/element_icon_necromancy.png | Bin 0 -> 338 bytes .../textures/gui/element_icon_simple.png | Bin 0 -> 248 bytes .../textures/gui/element_icon_sorcery.png | Bin 0 -> 328 bytes .../textures/gui/empty_slot_crystal.png | Bin 0 -> 240 bytes .../textures/gui/empty_slot_upgrade.png | Bin 0 -> 211 bytes .../wizardry/textures/gui/frost_icon.png | Bin 0 -> 509 bytes .../wizardry/textures/gui/frost_overlay.png | Bin 0 -> 33939 bytes .../assets/wizardry/textures/gui/handbook.png | Bin 0 -> 17760 bytes .../textures/gui/handbook_recipes.png | Bin 0 -> 26539 bytes .../assets/wizardry/textures/gui/logo.png | Bin 0 -> 11755 bytes .../wizardry/textures/gui/ore_picture.png | Bin 0 -> 8674 bytes .../wizardry/textures/gui/potion_icons.png | Bin 0 -> 3317 bytes .../textures/gui/sixth_sense_overlay.png | Bin 0 -> 56730 bytes .../wizardry/textures/gui/spell_hud.png | Bin 0 -> 29809 bytes .../wizardry/textures/gui/spellbook.png | Bin 0 -> 20096 bytes .../assets/wizardry/textures/items/Thumbs.db | Bin 0 -> 29696 bytes .../wizardry/textures/items/arcane_tome.png | Bin 0 -> 443 bytes .../textures/items/armour_upgrade.png | Bin 0 -> 546 bytes .../wizardry/textures/items/firebomb.png | Bin 0 -> 605 bytes .../wizardry/textures/items/flaming_axe.png | Bin 0 -> 1316 bytes .../textures/items/flaming_axe.png.mcmeta | 12 + .../wizardry/textures/items/frost_axe.png | Bin 0 -> 457 bytes .../textures/items/identification_scroll.png | Bin 0 -> 538 bytes .../wizardry/textures/items/magic_crystal.png | Bin 0 -> 510 bytes .../wizardry/textures/items/magic_silk.png | Bin 0 -> 463 bytes .../wizardry/textures/items/mana_flask.png | Bin 0 -> 409 bytes .../wizardry/textures/items/poison_bomb.png | Bin 0 -> 633 bytes .../assets/wizardry/textures/items/scroll.png | Bin 0 -> 538 bytes .../wizardry/textures/items/smoke_bomb.png | Bin 0 -> 558 bytes .../textures/items/spectral_boots.png | Bin 0 -> 270 bytes .../textures/items/spectral_bow_pulling_0.png | Bin 0 -> 392 bytes .../textures/items/spectral_bow_pulling_1.png | Bin 0 -> 407 bytes .../textures/items/spectral_bow_pulling_2.png | Bin 0 -> 392 bytes .../textures/items/spectral_bow_standby.png | Bin 0 -> 315 bytes .../textures/items/spectral_chestplate.png | Bin 0 -> 373 bytes .../textures/items/spectral_helmet.png | Bin 0 -> 267 bytes .../textures/items/spectral_leggings.png | Bin 0 -> 245 bytes .../textures/items/spectral_pickaxe.png | Bin 0 -> 332 bytes .../textures/items/spectral_sword.png | Bin 0 -> 363 bytes .../wizardry/textures/items/spell_book.png | Bin 0 -> 430 bytes .../textures/items/upgrade_attunement.png | Bin 0 -> 556 bytes .../wizardry/textures/items/upgrade_blast.png | Bin 0 -> 371 bytes .../textures/items/upgrade_condenser.png | Bin 0 -> 411 bytes .../textures/items/upgrade_cooldown.png | Bin 0 -> 452 bytes .../textures/items/upgrade_duration.png | Bin 0 -> 412 bytes .../wizardry/textures/items/upgrade_range.png | Bin 0 -> 535 bytes .../textures/items/upgrade_siphon.png | Bin 0 -> 447 bytes .../textures/items/upgrade_storage.png | Bin 0 -> 392 bytes .../wizardry/textures/items/wand_advanced.png | Bin 0 -> 506 bytes .../textures/items/wand_advanced_earth.png | Bin 0 -> 470 bytes .../textures/items/wand_advanced_fire.png | Bin 0 -> 473 bytes .../textures/items/wand_advanced_healing.png | Bin 0 -> 461 bytes .../textures/items/wand_advanced_ice.png | Bin 0 -> 455 bytes .../items/wand_advanced_lightning.png | Bin 0 -> 485 bytes .../items/wand_advanced_necromancy.png | Bin 0 -> 470 bytes .../textures/items/wand_advanced_sorcery.png | Bin 0 -> 468 bytes .../textures/items/wand_apprentice.png | Bin 0 -> 456 bytes .../textures/items/wand_apprentice_earth.png | Bin 0 -> 459 bytes .../textures/items/wand_apprentice_fire.png | Bin 0 -> 447 bytes .../items/wand_apprentice_healing.png | Bin 0 -> 443 bytes .../textures/items/wand_apprentice_ice.png | Bin 0 -> 445 bytes .../items/wand_apprentice_lightning.png | Bin 0 -> 449 bytes .../items/wand_apprentice_necromancy.png | Bin 0 -> 443 bytes .../items/wand_apprentice_sorcery.png | Bin 0 -> 441 bytes .../wizardry/textures/items/wand_basic.png | Bin 0 -> 405 bytes .../textures/items/wand_basic_earth.png | Bin 0 -> 404 bytes .../textures/items/wand_basic_fire.png | Bin 0 -> 396 bytes .../textures/items/wand_basic_healing.png | Bin 0 -> 394 bytes .../textures/items/wand_basic_ice.png | Bin 0 -> 397 bytes .../textures/items/wand_basic_lightning.png | Bin 0 -> 400 bytes .../textures/items/wand_basic_necromancy.png | Bin 0 -> 394 bytes .../textures/items/wand_basic_sorcery.png | Bin 0 -> 389 bytes .../wizardry/textures/items/wand_master.png | Bin 0 -> 517 bytes .../textures/items/wand_master_earth.png | Bin 0 -> 477 bytes .../textures/items/wand_master_fire.png | Bin 0 -> 478 bytes .../textures/items/wand_master_healing.png | Bin 0 -> 477 bytes .../textures/items/wand_master_ice.png | Bin 0 -> 504 bytes .../textures/items/wand_master_lightning.png | Bin 0 -> 512 bytes .../textures/items/wand_master_necromancy.png | Bin 0 -> 447 bytes .../textures/items/wand_master_sorcery.png | Bin 0 -> 488 bytes .../wizardry/textures/items/wizard_boots.png | Bin 0 -> 387 bytes .../textures/items/wizard_boots_earth.png | Bin 0 -> 405 bytes .../textures/items/wizard_boots_fire.png | Bin 0 -> 414 bytes .../textures/items/wizard_boots_healing.png | Bin 0 -> 402 bytes .../textures/items/wizard_boots_ice.png | Bin 0 -> 409 bytes .../textures/items/wizard_boots_lightning.png | Bin 0 -> 408 bytes .../items/wizard_boots_necromancy.png | Bin 0 -> 419 bytes .../textures/items/wizard_boots_sorcery.png | Bin 0 -> 385 bytes .../textures/items/wizard_handbook.png | Bin 0 -> 451 bytes .../wizardry/textures/items/wizard_hat.png | Bin 0 -> 441 bytes .../textures/items/wizard_hat_earth.png | Bin 0 -> 446 bytes .../textures/items/wizard_hat_fire.png | Bin 0 -> 457 bytes .../textures/items/wizard_hat_healing.png | Bin 0 -> 443 bytes .../textures/items/wizard_hat_ice.png | Bin 0 -> 438 bytes .../textures/items/wizard_hat_lightning.png | Bin 0 -> 443 bytes .../textures/items/wizard_hat_necromancy.png | Bin 0 -> 435 bytes .../textures/items/wizard_hat_sorcery.png | Bin 0 -> 432 bytes .../textures/items/wizard_leggings.png | Bin 0 -> 345 bytes .../textures/items/wizard_leggings_earth.png | Bin 0 -> 349 bytes .../textures/items/wizard_leggings_fire.png | Bin 0 -> 352 bytes .../items/wizard_leggings_healing.png | Bin 0 -> 340 bytes .../textures/items/wizard_leggings_ice.png | Bin 0 -> 340 bytes .../items/wizard_leggings_lightning.png | Bin 0 -> 349 bytes .../items/wizard_leggings_necromancy.png | Bin 0 -> 347 bytes .../items/wizard_leggings_sorcery.png | Bin 0 -> 335 bytes .../wizardry/textures/items/wizard_robe.png | Bin 0 -> 480 bytes .../textures/items/wizard_robe_earth.png | Bin 0 -> 491 bytes .../textures/items/wizard_robe_fire.png | Bin 0 -> 496 bytes .../textures/items/wizard_robe_healing.png | Bin 0 -> 472 bytes .../textures/items/wizard_robe_ice.png | Bin 0 -> 489 bytes .../textures/items/wizard_robe_lightning.png | Bin 0 -> 497 bytes .../textures/items/wizard_robe_necromancy.png | Bin 0 -> 496 bytes .../textures/items/wizard_robe_sorcery.png | Bin 0 -> 472 bytes .../textures/particle/ice_particles.png | Bin 0 -> 957 bytes .../textures/particle/leaf_particles.png | Bin 0 -> 701 bytes .../textures/particle/lightning_particles.png | Bin 0 -> 2602 bytes .../textures/particle/path_particles.png | Bin 0 -> 219 bytes .../textures/particle/snow_particles.png | Bin 0 -> 179 bytes .../textures/particle/sparkle_particles.png | Bin 0 -> 917 bytes .../wizardry/textures/spells/agility.png | Bin 0 -> 2200 bytes .../assets/wizardry/textures/spells/arc.png | Bin 0 -> 2059 bytes .../textures/spells/arcane_jammer.png | Bin 0 -> 2352 bytes .../wizardry/textures/spells/arrow_rain.png | Bin 0 -> 2421 bytes .../wizardry/textures/spells/banish.png | Bin 0 -> 2250 bytes .../wizardry/textures/spells/black_hole.png | Bin 0 -> 2113 bytes .../assets/wizardry/textures/spells/blink.png | Bin 0 -> 1937 bytes .../wizardry/textures/spells/blizzard.png | Bin 0 -> 2745 bytes .../wizardry/textures/spells/bubble.png | Bin 0 -> 1970 bytes .../textures/spells/chain_lightning.png | Bin 0 -> 2588 bytes .../wizardry/textures/spells/clairvoyance.png | Bin 0 -> 1981 bytes .../wizardry/textures/spells/cobwebs.png | Bin 0 -> 2650 bytes .../textures/spells/conjure_armour.png | Bin 0 -> 2197 bytes .../wizardry/textures/spells/conjure_bow.png | Bin 0 -> 2215 bytes .../textures/spells/conjure_pickaxe.png | Bin 0 -> 2146 bytes .../textures/spells/conjure_sword.png | Bin 0 -> 2199 bytes .../wizardry/textures/spells/cure_effects.png | Bin 0 -> 2142 bytes .../textures/spells/curse_of_soulbinding.png | Bin 0 -> 1925 bytes .../wizardry/textures/spells/darkness_orb.png | Bin 0 -> 1824 bytes .../wizardry/textures/spells/darkvision.png | Bin 0 -> 2240 bytes .../assets/wizardry/textures/spells/dart.png | Bin 0 -> 1624 bytes .../assets/wizardry/textures/spells/decay.png | Bin 0 -> 1281 bytes .../assets/wizardry/textures/spells/decoy.png | Bin 0 -> 2058 bytes .../wizardry/textures/spells/detonate.png | Bin 0 -> 2120 bytes .../wizardry/textures/spells/diamondflesh.png | Bin 0 -> 2132 bytes .../wizardry/textures/spells/earthquake.png | Bin 0 -> 2564 bytes .../wizardry/textures/spells/entrapment.png | Bin 0 -> 1910 bytes .../textures/spells/fire_resistance.png | Bin 0 -> 2419 bytes .../wizardry/textures/spells/fire_sigil.png | Bin 0 -> 2060 bytes .../wizardry/textures/spells/fireball.png | Bin 0 -> 1927 bytes .../wizardry/textures/spells/firebolt.png | Bin 0 -> 1782 bytes .../wizardry/textures/spells/firebomb.png | Bin 0 -> 2002 bytes .../wizardry/textures/spells/fireskin.png | Bin 0 -> 2052 bytes .../wizardry/textures/spells/firestorm.png | Bin 0 -> 2426 bytes .../wizardry/textures/spells/flame_ray.png | Bin 0 -> 1955 bytes .../wizardry/textures/spells/flaming_axe.png | Bin 0 -> 2290 bytes .../textures/spells/flaming_weapon.png | Bin 0 -> 2003 bytes .../wizardry/textures/spells/flight.png | Bin 0 -> 2524 bytes .../wizardry/textures/spells/font_of_mana.png | Bin 0 -> 2412 bytes .../textures/spells/font_of_vitality.png | Bin 0 -> 2387 bytes .../wizardry/textures/spells/force_arrow.png | Bin 0 -> 2013 bytes .../wizardry/textures/spells/force_orb.png | Bin 0 -> 2057 bytes .../wizardry/textures/spells/forcefield.png | Bin 0 -> 2210 bytes .../textures/spells/forests_curse.png | Bin 0 -> 2275 bytes .../wizardry/textures/spells/freeze.png | Bin 0 -> 1959 bytes .../textures/spells/freezing_weapon.png | Bin 0 -> 2062 bytes .../wizardry/textures/spells/frost_axe.png | Bin 0 -> 2185 bytes .../wizardry/textures/spells/frost_ray.png | Bin 0 -> 2115 bytes .../wizardry/textures/spells/frost_sigil.png | Bin 0 -> 2286 bytes .../assets/wizardry/textures/spells/glide.png | Bin 0 -> 2148 bytes .../textures/spells/greater_fireball.png | Bin 0 -> 2000 bytes .../wizardry/textures/spells/greater_heal.png | Bin 0 -> 2371 bytes .../wizardry/textures/spells/group_heal.png | Bin 0 -> 2446 bytes .../wizardry/textures/spells/growth_aura.png | Bin 0 -> 1955 bytes .../wizardry/textures/spells/hailstorm.png | Bin 0 -> 2426 bytes .../assets/wizardry/textures/spells/heal.png | Bin 0 -> 2221 bytes .../wizardry/textures/spells/heal_ally.png | Bin 0 -> 2360 bytes .../wizardry/textures/spells/healing_aura.png | Bin 0 -> 2344 bytes .../wizardry/textures/spells/homing_spark.png | Bin 0 -> 1727 bytes .../wizardry/textures/spells/ice_age.png | Bin 0 -> 2496 bytes .../wizardry/textures/spells/ice_charge.png | Bin 0 -> 2281 bytes .../wizardry/textures/spells/ice_lance.png | Bin 0 -> 1899 bytes .../wizardry/textures/spells/ice_shard.png | Bin 0 -> 1715 bytes .../wizardry/textures/spells/ice_shroud.png | Bin 0 -> 2135 bytes .../wizardry/textures/spells/ice_spikes.png | Bin 0 -> 2219 bytes .../wizardry/textures/spells/ice_statue.png | Bin 0 -> 2062 bytes .../wizardry/textures/spells/ignite.png | Bin 0 -> 1685 bytes .../wizardry/textures/spells/imbue_weapon.png | Bin 0 -> 2073 bytes .../wizardry/textures/spells/intimidate.png | Bin 0 -> 1464 bytes .../textures/spells/invigorating_presence.png | Bin 0 -> 2308 bytes .../wizardry/textures/spells/invisibility.png | Bin 0 -> 2297 bytes .../textures/spells/invoke_weather.png | Bin 0 -> 2319 bytes .../wizardry/textures/spells/ironflesh.png | Bin 0 -> 1939 bytes .../assets/wizardry/textures/spells/leap.png | Bin 0 -> 1550 bytes .../wizardry/textures/spells/levitation.png | Bin 0 -> 2188 bytes .../wizardry/textures/spells/life_drain.png | Bin 0 -> 1666 bytes .../assets/wizardry/textures/spells/light.png | Bin 0 -> 1890 bytes .../textures/spells/lightning_arrow.png | Bin 0 -> 2036 bytes .../textures/spells/lightning_bolt.png | Bin 0 -> 1865 bytes .../textures/spells/lightning_disc.png | Bin 0 -> 2273 bytes .../textures/spells/lightning_hammer.png | Bin 0 -> 2361 bytes .../textures/spells/lightning_pulse.png | Bin 0 -> 1965 bytes .../textures/spells/lightning_ray.png | Bin 0 -> 2072 bytes .../textures/spells/lightning_sigil.png | Bin 0 -> 2133 bytes .../textures/spells/lightning_web.png | Bin 0 -> 2880 bytes .../textures/spells/magic_missile.png | Bin 0 -> 2088 bytes .../textures/spells/metamorphosis.png | Bin 0 -> 2010 bytes .../wizardry/textures/spells/meteor.png | Bin 0 -> 2003 bytes .../wizardry/textures/spells/mind_control.png | Bin 0 -> 2320 bytes .../wizardry/textures/spells/mind_trick.png | Bin 0 -> 2269 bytes .../assets/wizardry/textures/spells/none.png | Bin 0 -> 809 bytes .../wizardry/textures/spells/oakflesh.png | Bin 0 -> 2106 bytes .../wizardry/textures/spells/petrify.png | Bin 0 -> 1816 bytes .../wizardry/textures/spells/phase_step.png | Bin 0 -> 2023 bytes .../textures/spells/plague_of_darkness.png | Bin 0 -> 2403 bytes .../textures/spells/pocket_furnace.png | Bin 0 -> 1784 bytes .../textures/spells/pocket_workbench.png | Bin 0 -> 1871 bytes .../wizardry/textures/spells/poison.png | Bin 0 -> 1737 bytes .../wizardry/textures/spells/poison_bomb.png | Bin 0 -> 2071 bytes .../textures/spells/replenish_hunger.png | Bin 0 -> 2198 bytes .../wizardry/textures/spells/ring_of_fire.png | Bin 0 -> 2248 bytes .../wizardry/textures/spells/shadow_ward.png | Bin 0 -> 1784 bytes .../wizardry/textures/spells/shield.png | Bin 0 -> 2370 bytes .../wizardry/textures/spells/shockwave.png | Bin 0 -> 2448 bytes .../textures/spells/silverfish_swarm.png | Bin 0 -> 2517 bytes .../wizardry/textures/spells/sixth_sense.png | Bin 0 -> 2099 bytes .../assets/wizardry/textures/spells/slime.png | Bin 0 -> 1944 bytes .../wizardry/textures/spells/smoke_bomb.png | Bin 0 -> 1715 bytes .../assets/wizardry/textures/spells/snare.png | Bin 0 -> 1816 bytes .../wizardry/textures/spells/snowball.png | Bin 0 -> 1687 bytes .../wizardry/textures/spells/spark_bomb.png | Bin 0 -> 2166 bytes .../textures/spells/spectral_pathway.png | Bin 0 -> 2176 bytes .../wizardry/textures/spells/spider_swarm.png | Bin 0 -> 1989 bytes .../wizardry/textures/spells/static_aura.png | Bin 0 -> 2177 bytes .../wizardry/textures/spells/summon_blaze.png | Bin 0 -> 1873 bytes .../textures/spells/summon_ice_giant.png | Bin 0 -> 2080 bytes .../textures/spells/summon_ice_wraith.png | Bin 0 -> 2142 bytes .../textures/spells/summon_iron_golem.png | Bin 0 -> 2482 bytes .../spells/summon_lightning_wraith.png | Bin 0 -> 2127 bytes .../textures/spells/summon_phoenix.png | Bin 0 -> 2295 bytes .../textures/spells/summon_shadow_wraith.png | Bin 0 -> 2289 bytes .../textures/spells/summon_skeleton.png | Bin 0 -> 2153 bytes .../spells/summon_skeleton_legion.png | Bin 0 -> 2080 bytes .../textures/spells/summon_snow_golem.png | Bin 0 -> 1978 bytes .../textures/spells/summon_spirit_horse.png | Bin 0 -> 2211 bytes .../textures/spells/summon_spirit_wolf.png | Bin 0 -> 2241 bytes .../spells/summon_storm_elemental.png | Bin 0 -> 2452 bytes .../spells/summon_wither_skeleton.png | Bin 0 -> 2147 bytes .../textures/spells/summon_zombie.png | Bin 0 -> 2039 bytes .../wizardry/textures/spells/telekinesis.png | Bin 0 -> 1844 bytes .../wizardry/textures/spells/thunderbolt.png | Bin 0 -> 1565 bytes .../wizardry/textures/spells/thunderstorm.png | Bin 0 -> 2815 bytes .../wizardry/textures/spells/tornado.png | Bin 0 -> 2178 bytes .../wizardry/textures/spells/transience.png | Bin 0 -> 2480 bytes .../textures/spells/transportation.png | Bin 0 -> 2280 bytes .../textures/spells/vanishing_box.png | Bin 0 -> 1945 bytes .../textures/spells/wall_of_frost.png | Bin 0 -> 2521 bytes .../textures/spells/water_breathing.png | Bin 0 -> 2316 bytes .../wizardry/textures/spells/whirlwind.png | Bin 0 -> 2292 bytes .../wizardry/textures/spells/wither.png | Bin 0 -> 2098 bytes .../wizardry/textures/spells/wither_skull.png | Bin 0 -> 1582 bytes src/main/resources/mcmod.info | 18 + 945 files changed, 60616 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CREDITS-fml.txt create mode 100644 LICENSE-new.txt create mode 100644 MinecraftForge-Credits.txt create mode 100644 Paulscode IBXM Library License.txt create mode 100644 Paulscode SoundSystem CodecIBXM License.txt create mode 100644 README.md create mode 100644 README.txt create mode 100644 build.gradle create mode 100644 forge-1.10.2-12.18.3.2185-changelog.txt create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 src/main/java/electroblob/wizardry/CommonProxy.java create mode 100644 src/main/java/electroblob/wizardry/Settings.java create mode 100644 src/main/java/electroblob/wizardry/SpellGlyphData.java create mode 100644 src/main/java/electroblob/wizardry/WizardData.java create mode 100644 src/main/java/electroblob/wizardry/Wizardry.java create mode 100644 src/main/java/electroblob/wizardry/WizardryEventHandler.java create mode 100644 src/main/java/electroblob/wizardry/WizardryGuiFactory.java create mode 100644 src/main/java/electroblob/wizardry/WizardryGuiHandler.java create mode 100644 src/main/java/electroblob/wizardry/WizardryKeyHandler.java create mode 100644 src/main/java/electroblob/wizardry/WizardryWorldGenerator.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockArcaneWorkbench.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockCrystalOre.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockMagicLight.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockSnare.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockSpectral.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockStatue.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockTransportationStone.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockVanishingCobweb.java create mode 100644 src/main/java/electroblob/wizardry/client/ClientProxy.java create mode 100644 src/main/java/electroblob/wizardry/client/EntityNameEntry.java create mode 100644 src/main/java/electroblob/wizardry/client/GuiArcaneWorkbench.java create mode 100644 src/main/java/electroblob/wizardry/client/GuiButtonApply.java create mode 100644 src/main/java/electroblob/wizardry/client/GuiButtonInvisible.java create mode 100644 src/main/java/electroblob/wizardry/client/GuiButtonTurnPage.java create mode 100644 src/main/java/electroblob/wizardry/client/GuiConfigWizardry.java create mode 100644 src/main/java/electroblob/wizardry/client/GuiPortableCrafting.java create mode 100644 src/main/java/electroblob/wizardry/client/GuiSpellBook.java create mode 100644 src/main/java/electroblob/wizardry/client/GuiSpellDisplay.java create mode 100644 src/main/java/electroblob/wizardry/client/GuiWizardHandbook.java create mode 100644 src/main/java/electroblob/wizardry/client/MixedFontRenderer.java create mode 100644 src/main/java/electroblob/wizardry/client/MovingSoundEntity.java create mode 100644 src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java create mode 100644 src/main/java/electroblob/wizardry/client/model/ModelHammer.java create mode 100644 src/main/java/electroblob/wizardry/client/model/ModelIceGiant.java create mode 100644 src/main/java/electroblob/wizardry/client/model/ModelPhoenix.java create mode 100644 src/main/java/electroblob/wizardry/client/model/ModelWizard.java create mode 100644 src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java create mode 100644 src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleDust.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleGiantBubble.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleIce.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleMagicFlame.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticlePath.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleRotatingSparkle.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleTornado.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/LayerStone.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RayHelper.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderArc.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderArcaneWorkbench.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderBlackHole.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderBlank.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderBubble.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderDecay.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderDecoy.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderEvilWizard.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderFireRing.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderHammer.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderIceGiant.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderIceSpike.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderLightningDisc.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderLightningPulse.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderMagicArrow.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderMagicLight.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderPhoenix.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderProjectile.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderSigil.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderSpiritHorse.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderSpiritWolf.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderStatue.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderWizard.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderWraithMinion.java create mode 100644 src/main/java/electroblob/wizardry/command/CommandCastSpell.java create mode 100644 src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java create mode 100644 src/main/java/electroblob/wizardry/command/CommandSetAlly.java create mode 100644 src/main/java/electroblob/wizardry/command/CommandViewAllies.java create mode 100644 src/main/java/electroblob/wizardry/constants/Constants.java create mode 100644 src/main/java/electroblob/wizardry/constants/Element.java create mode 100644 src/main/java/electroblob/wizardry/constants/SpellType.java create mode 100644 src/main/java/electroblob/wizardry/constants/Tier.java create mode 100644 src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicSword.java create mode 100644 src/main/java/electroblob/wizardry/enchantment/EnchantmentTimed.java create mode 100644 src/main/java/electroblob/wizardry/enchantment/Imbuement.java create mode 100644 src/main/java/electroblob/wizardry/entity/EntityArc.java create mode 100644 src/main/java/electroblob/wizardry/entity/EntityMeteor.java create mode 100644 src/main/java/electroblob/wizardry/entity/EntityShield.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityMagicConstruct.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityAISelectSpell.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityWizard.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/IIntelligentSpellCaster.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityBomb.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java create mode 100644 src/main/java/electroblob/wizardry/event/DiscoverSpellEvent.java create mode 100644 src/main/java/electroblob/wizardry/event/SpellBindEvent.java create mode 100644 src/main/java/electroblob/wizardry/event/SpellCastEvent.java create mode 100644 src/main/java/electroblob/wizardry/item/IConjuredItem.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemArcaneTome.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemArmourUpgrade.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemFirebomb.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemFrostAxe.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemIdentificationScroll.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemScroll.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemSpectralBow.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemSpectralSword.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemSpellBook.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemWand.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemWizardArmour.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemWizardHandbook.java create mode 100644 src/main/java/electroblob/wizardry/loot/RandomSpell.java create mode 100644 src/main/java/electroblob/wizardry/loot/WizardSpell.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketCastContinuousSpell.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketCastSpell.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketClairvoyance.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketControlInput.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketGlyphData.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketNPCCastSpell.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketPlayerSync.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketTransportation.java create mode 100644 src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java create mode 100644 src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java create mode 100644 src/main/java/electroblob/wizardry/potion/PotionDecay.java create mode 100644 src/main/java/electroblob/wizardry/potion/PotionFrost.java create mode 100644 src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java create mode 100644 src/main/java/electroblob/wizardry/potion/PotionMagicEffectParticles.java create mode 100644 src/main/java/electroblob/wizardry/registry/Spells.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryAchievements.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryBlocks.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryItems.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryPotions.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryRegistry.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardrySounds.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryTabs.java create mode 100644 src/main/java/electroblob/wizardry/spell/Agility.java create mode 100644 src/main/java/electroblob/wizardry/spell/Arc.java create mode 100644 src/main/java/electroblob/wizardry/spell/ArcaneJammer.java create mode 100644 src/main/java/electroblob/wizardry/spell/ArrowRain.java create mode 100644 src/main/java/electroblob/wizardry/spell/Banish.java create mode 100644 src/main/java/electroblob/wizardry/spell/BlackHole.java create mode 100644 src/main/java/electroblob/wizardry/spell/Blink.java create mode 100644 src/main/java/electroblob/wizardry/spell/Blizzard.java create mode 100644 src/main/java/electroblob/wizardry/spell/Bubble.java create mode 100644 src/main/java/electroblob/wizardry/spell/ChainLightning.java create mode 100644 src/main/java/electroblob/wizardry/spell/Clairvoyance.java create mode 100644 src/main/java/electroblob/wizardry/spell/Cobwebs.java create mode 100644 src/main/java/electroblob/wizardry/spell/ConjureArmour.java create mode 100644 src/main/java/electroblob/wizardry/spell/ConjureBow.java create mode 100644 src/main/java/electroblob/wizardry/spell/ConjurePickaxe.java create mode 100644 src/main/java/electroblob/wizardry/spell/ConjureSword.java create mode 100644 src/main/java/electroblob/wizardry/spell/CureEffects.java create mode 100644 src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java create mode 100644 src/main/java/electroblob/wizardry/spell/DarknessOrb.java create mode 100644 src/main/java/electroblob/wizardry/spell/Darkvision.java create mode 100644 src/main/java/electroblob/wizardry/spell/Dart.java create mode 100644 src/main/java/electroblob/wizardry/spell/Decay.java create mode 100644 src/main/java/electroblob/wizardry/spell/Decoy.java create mode 100644 src/main/java/electroblob/wizardry/spell/Detonate.java create mode 100644 src/main/java/electroblob/wizardry/spell/Diamondflesh.java create mode 100644 src/main/java/electroblob/wizardry/spell/Earthquake.java create mode 100644 src/main/java/electroblob/wizardry/spell/Entrapment.java create mode 100644 src/main/java/electroblob/wizardry/spell/FireResistance.java create mode 100644 src/main/java/electroblob/wizardry/spell/FireSigil.java create mode 100644 src/main/java/electroblob/wizardry/spell/Fireball.java create mode 100644 src/main/java/electroblob/wizardry/spell/Firebolt.java create mode 100644 src/main/java/electroblob/wizardry/spell/Firebomb.java create mode 100644 src/main/java/electroblob/wizardry/spell/Fireskin.java create mode 100644 src/main/java/electroblob/wizardry/spell/Firestorm.java create mode 100644 src/main/java/electroblob/wizardry/spell/FlameRay.java create mode 100644 src/main/java/electroblob/wizardry/spell/FlamingAxe.java create mode 100644 src/main/java/electroblob/wizardry/spell/FlamingWeapon.java create mode 100644 src/main/java/electroblob/wizardry/spell/Flight.java create mode 100644 src/main/java/electroblob/wizardry/spell/FontOfMana.java create mode 100644 src/main/java/electroblob/wizardry/spell/FontOfVitality.java create mode 100644 src/main/java/electroblob/wizardry/spell/ForceArrow.java create mode 100644 src/main/java/electroblob/wizardry/spell/ForceOrb.java create mode 100644 src/main/java/electroblob/wizardry/spell/Forcefield.java create mode 100644 src/main/java/electroblob/wizardry/spell/ForestsCurse.java create mode 100644 src/main/java/electroblob/wizardry/spell/Freeze.java create mode 100644 src/main/java/electroblob/wizardry/spell/FreezingWeapon.java create mode 100644 src/main/java/electroblob/wizardry/spell/FrostAxe.java create mode 100644 src/main/java/electroblob/wizardry/spell/FrostRay.java create mode 100644 src/main/java/electroblob/wizardry/spell/FrostSigil.java create mode 100644 src/main/java/electroblob/wizardry/spell/Glide.java create mode 100644 src/main/java/electroblob/wizardry/spell/GreaterFireball.java create mode 100644 src/main/java/electroblob/wizardry/spell/GreaterHeal.java create mode 100644 src/main/java/electroblob/wizardry/spell/GroupHeal.java create mode 100644 src/main/java/electroblob/wizardry/spell/GrowthAura.java create mode 100644 src/main/java/electroblob/wizardry/spell/Hailstorm.java create mode 100644 src/main/java/electroblob/wizardry/spell/Heal.java create mode 100644 src/main/java/electroblob/wizardry/spell/HealAlly.java create mode 100644 src/main/java/electroblob/wizardry/spell/HealingAura.java create mode 100644 src/main/java/electroblob/wizardry/spell/HomingSpark.java create mode 100644 src/main/java/electroblob/wizardry/spell/IceAge.java create mode 100644 src/main/java/electroblob/wizardry/spell/IceCharge.java create mode 100644 src/main/java/electroblob/wizardry/spell/IceLance.java create mode 100644 src/main/java/electroblob/wizardry/spell/IceShard.java create mode 100644 src/main/java/electroblob/wizardry/spell/IceShroud.java create mode 100644 src/main/java/electroblob/wizardry/spell/IceSpikes.java create mode 100644 src/main/java/electroblob/wizardry/spell/IceStatue.java create mode 100644 src/main/java/electroblob/wizardry/spell/Ignite.java create mode 100644 src/main/java/electroblob/wizardry/spell/ImbueWeapon.java create mode 100644 src/main/java/electroblob/wizardry/spell/Intimidate.java create mode 100644 src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java create mode 100644 src/main/java/electroblob/wizardry/spell/Invisibility.java create mode 100644 src/main/java/electroblob/wizardry/spell/InvokeWeather.java create mode 100644 src/main/java/electroblob/wizardry/spell/Ironflesh.java create mode 100644 src/main/java/electroblob/wizardry/spell/Leap.java create mode 100644 src/main/java/electroblob/wizardry/spell/Levitation.java create mode 100644 src/main/java/electroblob/wizardry/spell/LifeDrain.java create mode 100644 src/main/java/electroblob/wizardry/spell/Light.java create mode 100644 src/main/java/electroblob/wizardry/spell/LightningArrow.java create mode 100644 src/main/java/electroblob/wizardry/spell/LightningBolt.java create mode 100644 src/main/java/electroblob/wizardry/spell/LightningDisc.java create mode 100644 src/main/java/electroblob/wizardry/spell/LightningHammer.java create mode 100644 src/main/java/electroblob/wizardry/spell/LightningPulse.java create mode 100644 src/main/java/electroblob/wizardry/spell/LightningRay.java create mode 100644 src/main/java/electroblob/wizardry/spell/LightningSigil.java create mode 100644 src/main/java/electroblob/wizardry/spell/LightningWeb.java create mode 100644 src/main/java/electroblob/wizardry/spell/MagicMissile.java create mode 100644 src/main/java/electroblob/wizardry/spell/Metamorphosis.java create mode 100644 src/main/java/electroblob/wizardry/spell/Meteor.java create mode 100644 src/main/java/electroblob/wizardry/spell/MindControl.java create mode 100644 src/main/java/electroblob/wizardry/spell/MindTrick.java create mode 100644 src/main/java/electroblob/wizardry/spell/None.java create mode 100644 src/main/java/electroblob/wizardry/spell/Oakflesh.java create mode 100644 src/main/java/electroblob/wizardry/spell/Petrify.java create mode 100644 src/main/java/electroblob/wizardry/spell/PhaseStep.java create mode 100644 src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java create mode 100644 src/main/java/electroblob/wizardry/spell/PocketFurnace.java create mode 100644 src/main/java/electroblob/wizardry/spell/PocketWorkbench.java create mode 100644 src/main/java/electroblob/wizardry/spell/Poison.java create mode 100644 src/main/java/electroblob/wizardry/spell/PoisonBomb.java create mode 100644 src/main/java/electroblob/wizardry/spell/ReplenishHunger.java create mode 100644 src/main/java/electroblob/wizardry/spell/RingOfFire.java create mode 100644 src/main/java/electroblob/wizardry/spell/ShadowWard.java create mode 100644 src/main/java/electroblob/wizardry/spell/Shield.java create mode 100644 src/main/java/electroblob/wizardry/spell/Shockwave.java create mode 100644 src/main/java/electroblob/wizardry/spell/SilverfishSwarm.java create mode 100644 src/main/java/electroblob/wizardry/spell/SixthSense.java create mode 100644 src/main/java/electroblob/wizardry/spell/Slime.java create mode 100644 src/main/java/electroblob/wizardry/spell/SmokeBomb.java create mode 100644 src/main/java/electroblob/wizardry/spell/Snare.java create mode 100644 src/main/java/electroblob/wizardry/spell/Snowball.java create mode 100644 src/main/java/electroblob/wizardry/spell/SparkBomb.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpectralPathway.java create mode 100644 src/main/java/electroblob/wizardry/spell/Spell.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpiderSwarm.java create mode 100644 src/main/java/electroblob/wizardry/spell/StaticAura.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonBlaze.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonIceGiant.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonIceWraith.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonIronGolem.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonLightningWraith.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonPhoenix.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonSkeleton.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonStormElemental.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonZombie.java create mode 100644 src/main/java/electroblob/wizardry/spell/Telekinesis.java create mode 100644 src/main/java/electroblob/wizardry/spell/Thunderbolt.java create mode 100644 src/main/java/electroblob/wizardry/spell/Thunderstorm.java create mode 100644 src/main/java/electroblob/wizardry/spell/Tornado.java create mode 100644 src/main/java/electroblob/wizardry/spell/Transience.java create mode 100644 src/main/java/electroblob/wizardry/spell/Transportation.java create mode 100644 src/main/java/electroblob/wizardry/spell/VanishingBox.java create mode 100644 src/main/java/electroblob/wizardry/spell/WallOfFrost.java create mode 100644 src/main/java/electroblob/wizardry/spell/WaterBreathing.java create mode 100644 src/main/java/electroblob/wizardry/spell/Whirlwind.java create mode 100644 src/main/java/electroblob/wizardry/spell/Wither.java create mode 100644 src/main/java/electroblob/wizardry/spell/WitherSkull.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/ContainerPortableWorkbench.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/SlotItemList.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/SlotWandArmour.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/TileEntityMagicLight.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/TileEntityPlayerSave.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/TileEntityStatue.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/TileEntityTimer.java create mode 100644 src/main/java/electroblob/wizardry/util/IElementalDamage.java create mode 100644 src/main/java/electroblob/wizardry/util/IndirectMagicDamage.java create mode 100644 src/main/java/electroblob/wizardry/util/IndirectMinionDamage.java create mode 100644 src/main/java/electroblob/wizardry/util/MagicDamage.java create mode 100644 src/main/java/electroblob/wizardry/util/MinionDamage.java create mode 100644 src/main/java/electroblob/wizardry/util/SpellModifiers.java create mode 100644 src/main/java/electroblob/wizardry/util/WandHelper.java create mode 100644 src/main/java/electroblob/wizardry/util/WizardryParticleType.java create mode 100644 src/main/java/electroblob/wizardry/util/WizardryPathFinder.java create mode 100644 src/main/java/electroblob/wizardry/util/WizardryUtilities.java create mode 100644 src/main/resources/assets/wizardry/blockstates/arcane_workbench.json create mode 100644 src/main/resources/assets/wizardry/blockstates/crystal_block.json create mode 100644 src/main/resources/assets/wizardry/blockstates/crystal_flower.json create mode 100644 src/main/resources/assets/wizardry/blockstates/crystal_ore.json create mode 100644 src/main/resources/assets/wizardry/blockstates/ice_statue.json create mode 100644 src/main/resources/assets/wizardry/blockstates/magic_light.json create mode 100644 src/main/resources/assets/wizardry/blockstates/meteor.json create mode 100644 src/main/resources/assets/wizardry/blockstates/petrified_stone.json create mode 100644 src/main/resources/assets/wizardry/blockstates/snare.json create mode 100644 src/main/resources/assets/wizardry/blockstates/spectral_block.json create mode 100644 src/main/resources/assets/wizardry/blockstates/transportation_stone.json create mode 100644 src/main/resources/assets/wizardry/blockstates/vanishing_cobweb.json create mode 100644 src/main/resources/assets/wizardry/lang/en_GB.lang create mode 100644 src/main/resources/assets/wizardry/lang/en_US.lang create mode 100644 src/main/resources/assets/wizardry/lang/es_ES.lang create mode 100644 src/main/resources/assets/wizardry/lang/es_MX.lang create mode 100644 src/main/resources/assets/wizardry/lang/ru_RU.lang create mode 100644 src/main/resources/assets/wizardry/loot_tables/chests/dungeon_additions.json create mode 100644 src/main/resources/assets/wizardry/loot_tables/chests/wizard_tower.json create mode 100644 src/main/resources/assets/wizardry/loot_tables/entities/evil_wizard.json create mode 100644 src/main/resources/assets/wizardry/loot_tables/entities/mob_additions.json create mode 100644 src/main/resources/assets/wizardry/loot_tables/subsets/arcane_tomes.json create mode 100644 src/main/resources/assets/wizardry/loot_tables/subsets/novice_wands.json create mode 100644 src/main/resources/assets/wizardry/loot_tables/subsets/wand_upgrades.json create mode 100644 src/main/resources/assets/wizardry/loot_tables/subsets/wizard_armour.json create mode 100644 src/main/resources/assets/wizardry/models/block/arcane_workbench.json create mode 100644 src/main/resources/assets/wizardry/models/block/crystal_block.json create mode 100644 src/main/resources/assets/wizardry/models/block/crystal_flower.json create mode 100644 src/main/resources/assets/wizardry/models/block/crystal_ore.json create mode 100644 src/main/resources/assets/wizardry/models/block/ice_statue.json create mode 100644 src/main/resources/assets/wizardry/models/block/magic_light.json create mode 100644 src/main/resources/assets/wizardry/models/block/meteor.json create mode 100644 src/main/resources/assets/wizardry/models/block/petrified_stone.json create mode 100644 src/main/resources/assets/wizardry/models/block/snare.json create mode 100644 src/main/resources/assets/wizardry/models/block/spectral_block.json create mode 100644 src/main/resources/assets/wizardry/models/block/transportation_stone.json create mode 100644 src/main/resources/assets/wizardry/models/block/vanishing_cobweb.json create mode 100644 src/main/resources/assets/wizardry/models/item/advanced_earth_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/advanced_fire_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/advanced_healing_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/advanced_ice_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/advanced_lightning_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/advanced_necromancy_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/advanced_sorcery_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/advanced_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/apprentice_earth_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/apprentice_fire_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/apprentice_healing_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/apprentice_ice_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/apprentice_lightning_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/apprentice_necromancy_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/apprentice_sorcery_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/apprentice_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/arcane_tome.json create mode 100644 src/main/resources/assets/wizardry/models/item/arcane_workbench.json create mode 100644 src/main/resources/assets/wizardry/models/item/armour_upgrade.json create mode 100644 src/main/resources/assets/wizardry/models/item/attunement_upgrade.json create mode 100644 src/main/resources/assets/wizardry/models/item/basic_earth_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/basic_fire_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/basic_healing_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/basic_ice_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/basic_lightning_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/basic_necromancy_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/basic_sorcery_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/blank_scroll.json create mode 100644 src/main/resources/assets/wizardry/models/item/blast_upgrade.json create mode 100644 src/main/resources/assets/wizardry/models/item/condenser_upgrade.json create mode 100644 src/main/resources/assets/wizardry/models/item/cooldown_upgrade.json create mode 100644 src/main/resources/assets/wizardry/models/item/crystal_block.json create mode 100644 src/main/resources/assets/wizardry/models/item/crystal_flower.json create mode 100644 src/main/resources/assets/wizardry/models/item/crystal_ore.json create mode 100644 src/main/resources/assets/wizardry/models/item/duration_upgrade.json create mode 100644 src/main/resources/assets/wizardry/models/item/firebomb.json create mode 100644 src/main/resources/assets/wizardry/models/item/flaming_axe.json create mode 100644 src/main/resources/assets/wizardry/models/item/frost_axe.json create mode 100644 src/main/resources/assets/wizardry/models/item/ice_statue.json create mode 100644 src/main/resources/assets/wizardry/models/item/identification_scroll.json create mode 100644 src/main/resources/assets/wizardry/models/item/magic_crystal.json create mode 100644 src/main/resources/assets/wizardry/models/item/magic_light.json create mode 100644 src/main/resources/assets/wizardry/models/item/magic_silk.json create mode 100644 src/main/resources/assets/wizardry/models/item/magic_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/mana_flask.json create mode 100644 src/main/resources/assets/wizardry/models/item/master_earth_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/master_fire_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/master_healing_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/master_ice_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/master_lightning_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/master_necromancy_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/master_sorcery_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/master_wand.json create mode 100644 src/main/resources/assets/wizardry/models/item/meteor.json create mode 100644 src/main/resources/assets/wizardry/models/item/petrified_stone.json create mode 100644 src/main/resources/assets/wizardry/models/item/poison_bomb.json create mode 100644 src/main/resources/assets/wizardry/models/item/range_upgrade.json create mode 100644 src/main/resources/assets/wizardry/models/item/scroll.json create mode 100644 src/main/resources/assets/wizardry/models/item/siphon_upgrade.json create mode 100644 src/main/resources/assets/wizardry/models/item/smoke_bomb.json create mode 100644 src/main/resources/assets/wizardry/models/item/snare.json create mode 100644 src/main/resources/assets/wizardry/models/item/spawn_wizard.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_block.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_boots.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_bow.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_0.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_1.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_2.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_chestplate.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_helmet.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_leggings.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_pickaxe.json create mode 100644 src/main/resources/assets/wizardry/models/item/spectral_sword.json create mode 100644 src/main/resources/assets/wizardry/models/item/spell_book.json create mode 100644 src/main/resources/assets/wizardry/models/item/storage_upgrade.json create mode 100644 src/main/resources/assets/wizardry/models/item/transportation_stone.json create mode 100644 src/main/resources/assets/wizardry/models/item/vanishing_cobweb.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_boots.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_boots_earth.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_boots_fire.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_boots_healing.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_boots_ice.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_boots_lightning.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_boots_necromancy.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_boots_sorcery.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_handbook.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_hat.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_hat_earth.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_hat_fire.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_hat_healing.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_hat_ice.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_hat_lightning.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_hat_necromancy.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_hat_sorcery.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_leggings.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_leggings_earth.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_leggings_fire.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_leggings_healing.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_leggings_ice.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_leggings_lightning.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_leggings_necromancy.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_leggings_sorcery.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_robe.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_robe_earth.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_robe_fire.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_robe_healing.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_robe_ice.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_robe_lightning.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_robe_necromancy.json create mode 100644 src/main/resources/assets/wizardry/models/item/wizard_robe_sorcery.json create mode 100644 src/main/resources/assets/wizardry/sounds.json create mode 100644 src/main/resources/assets/wizardry/sounds/arc1.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/arc2.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/arc3.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/aura.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/boom.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/crackle.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/darkaura1.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/darkaura2.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/effect1.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/effect2.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/electricitya.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/electricityb.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/flameray1.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/flameray2.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/force.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/freeze.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/frostray.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/heal.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/ice.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/largeaura.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/magic1.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/magic2.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/magic3.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/magic4.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/rumble.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/sparkle.ogg create mode 100644 src/main/resources/assets/wizardry/sounds/wind.ogg create mode 100644 src/main/resources/assets/wizardry/texts/handbook_en_GB.txt create mode 100644 src/main/resources/assets/wizardry/texts/handbook_en_US.txt create mode 100644 src/main/resources/assets/wizardry/texts/handbook_es_ES.txt create mode 100644 src/main/resources/assets/wizardry/texts/handbook_es_MX.txt create mode 100644 src/main/resources/assets/wizardry/texts/handbook_ru_RU.txt create mode 100644 src/main/resources/assets/wizardry/textures/armour/invisible_armour.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/spectral_armour.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/spectral_armour_legs.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_earth_legs.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_fire_legs.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_healing_legs.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_ice_legs.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_legs.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_lightning_legs.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_necromancy_legs.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/armour/wizard_armour_sorcery_legs.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/Thumbs.db create mode 100644 src/main/resources/assets/wizardry/textures/blocks/arcane_workbench_bottom.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/arcane_workbench_side.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/arcane_workbench_top.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/crystal_block.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/crystal_flower.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/crystal_ore.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/meteor.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/snare.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/spectral_block.png create mode 100644 src/main/resources/assets/wizardry/textures/blocks/transportation_stone.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/Thumbs.db create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_0.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_1.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_10.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_11.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_12.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_13.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_14.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_15.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_2.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_3.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_4.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_5.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_6.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_7.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_8.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/arc_9.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/aura.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/black_hole.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/dark_orb.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/dark_ray.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/darkness_orb.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/dart.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_0.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_1.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_2.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_3.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_4.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_5.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_6.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_7.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_8.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/decay_9.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/evil_wizard_0.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/evil_wizard_1.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/evil_wizard_2.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/evil_wizard_3.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/evil_wizard_4.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/evil_wizard_5.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/fire_sigil.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/firebolt.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/force_arrow.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/force_orb.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/frost_sigil.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/healing_aura.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/ice_charge.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/ice_giant.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/ice_lance.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/ice_shard.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/ice_spike.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/ice_wraith.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/light_aura.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/light_ray.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_arrow.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_hammer.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_pulse_0.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_pulse_1.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_pulse_2.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_pulse_3.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_pulse_4.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_pulse_5.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_pulse_6.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_pulse_7.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_sigil.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/lightning_wraith.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/magic_missile.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/phoenix.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/pointer.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/ring_of_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/rune.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/shadow_ward.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/shield.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/sixth_sense.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/spark.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/spark_bomb.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/spirit_horse.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/spirit_wolf.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/stone_statue_32.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/stone_statue_64.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/target_pointer.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/wing.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/wizard_0.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/wizard_1.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/wizard_2.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/wizard_3.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/wizard_4.png create mode 100644 src/main/resources/assets/wizardry/textures/entity/wizard_5.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/Thumbs.db create mode 100644 src/main/resources/assets/wizardry/textures/gui/arcane_workbench.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/decay_icon.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/element_icon_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/element_icon_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/element_icon_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/element_icon_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/element_icon_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/element_icon_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/element_icon_simple.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/element_icon_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/empty_slot_crystal.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/empty_slot_upgrade.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/frost_icon.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/frost_overlay.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/handbook.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/handbook_recipes.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/logo.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/ore_picture.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/potion_icons.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/sixth_sense_overlay.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/spell_hud.png create mode 100644 src/main/resources/assets/wizardry/textures/gui/spellbook.png create mode 100644 src/main/resources/assets/wizardry/textures/items/Thumbs.db create mode 100644 src/main/resources/assets/wizardry/textures/items/arcane_tome.png create mode 100644 src/main/resources/assets/wizardry/textures/items/armour_upgrade.png create mode 100644 src/main/resources/assets/wizardry/textures/items/firebomb.png create mode 100644 src/main/resources/assets/wizardry/textures/items/flaming_axe.png create mode 100644 src/main/resources/assets/wizardry/textures/items/flaming_axe.png.mcmeta create mode 100644 src/main/resources/assets/wizardry/textures/items/frost_axe.png create mode 100644 src/main/resources/assets/wizardry/textures/items/identification_scroll.png create mode 100644 src/main/resources/assets/wizardry/textures/items/magic_crystal.png create mode 100644 src/main/resources/assets/wizardry/textures/items/magic_silk.png create mode 100644 src/main/resources/assets/wizardry/textures/items/mana_flask.png create mode 100644 src/main/resources/assets/wizardry/textures/items/poison_bomb.png create mode 100644 src/main/resources/assets/wizardry/textures/items/scroll.png create mode 100644 src/main/resources/assets/wizardry/textures/items/smoke_bomb.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_boots.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_bow_pulling_0.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_bow_pulling_1.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_bow_pulling_2.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_bow_standby.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_chestplate.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_helmet.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_leggings.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_pickaxe.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spectral_sword.png create mode 100644 src/main/resources/assets/wizardry/textures/items/spell_book.png create mode 100644 src/main/resources/assets/wizardry/textures/items/upgrade_attunement.png create mode 100644 src/main/resources/assets/wizardry/textures/items/upgrade_blast.png create mode 100644 src/main/resources/assets/wizardry/textures/items/upgrade_condenser.png create mode 100644 src/main/resources/assets/wizardry/textures/items/upgrade_cooldown.png create mode 100644 src/main/resources/assets/wizardry/textures/items/upgrade_duration.png create mode 100644 src/main/resources/assets/wizardry/textures/items/upgrade_range.png create mode 100644 src/main/resources/assets/wizardry/textures/items/upgrade_siphon.png create mode 100644 src/main/resources/assets/wizardry/textures/items/upgrade_storage.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_advanced.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_advanced_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_advanced_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_advanced_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_advanced_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_advanced_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_advanced_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_advanced_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_apprentice.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_apprentice_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_apprentice_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_apprentice_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_apprentice_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_apprentice_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_apprentice_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_apprentice_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_basic.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_basic_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_basic_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_basic_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_basic_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_basic_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_basic_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_basic_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_master.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_master_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_master_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_master_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_master_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_master_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_master_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wand_master_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_boots.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_boots_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_boots_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_boots_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_boots_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_boots_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_boots_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_boots_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_handbook.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_hat.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_hat_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_hat_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_hat_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_hat_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_hat_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_hat_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_hat_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_leggings.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_leggings_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_leggings_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_leggings_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_leggings_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_leggings_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_leggings_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_leggings_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_robe.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_robe_earth.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_robe_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_robe_healing.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_robe_ice.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_robe_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_robe_necromancy.png create mode 100644 src/main/resources/assets/wizardry/textures/items/wizard_robe_sorcery.png create mode 100644 src/main/resources/assets/wizardry/textures/particle/ice_particles.png create mode 100644 src/main/resources/assets/wizardry/textures/particle/leaf_particles.png create mode 100644 src/main/resources/assets/wizardry/textures/particle/lightning_particles.png create mode 100644 src/main/resources/assets/wizardry/textures/particle/path_particles.png create mode 100644 src/main/resources/assets/wizardry/textures/particle/snow_particles.png create mode 100644 src/main/resources/assets/wizardry/textures/particle/sparkle_particles.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/agility.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/arc.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/arcane_jammer.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/arrow_rain.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/banish.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/black_hole.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/blink.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/blizzard.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/bubble.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/chain_lightning.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/clairvoyance.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/cobwebs.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/conjure_armour.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/conjure_bow.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/conjure_pickaxe.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/conjure_sword.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/cure_effects.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/curse_of_soulbinding.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/darkness_orb.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/darkvision.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/dart.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/decay.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/decoy.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/detonate.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/diamondflesh.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/earthquake.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/entrapment.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/fire_resistance.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/fire_sigil.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/fireball.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/firebolt.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/firebomb.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/fireskin.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/firestorm.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/flame_ray.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/flaming_axe.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/flaming_weapon.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/flight.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/font_of_mana.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/font_of_vitality.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/force_arrow.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/force_orb.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/forcefield.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/forests_curse.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/freeze.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/freezing_weapon.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/frost_axe.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/frost_ray.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/frost_sigil.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/glide.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/greater_fireball.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/greater_heal.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/group_heal.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/growth_aura.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/hailstorm.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/heal.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/heal_ally.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/healing_aura.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/homing_spark.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ice_age.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ice_charge.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ice_lance.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ice_shard.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ice_shroud.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ice_spikes.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ice_statue.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ignite.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/imbue_weapon.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/intimidate.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/invigorating_presence.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/invisibility.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/invoke_weather.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ironflesh.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/leap.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/levitation.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/life_drain.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/light.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/lightning_arrow.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/lightning_bolt.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/lightning_disc.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/lightning_hammer.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/lightning_pulse.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/lightning_ray.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/lightning_sigil.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/lightning_web.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/magic_missile.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/metamorphosis.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/meteor.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/mind_control.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/mind_trick.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/none.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/oakflesh.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/petrify.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/phase_step.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/plague_of_darkness.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/pocket_furnace.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/pocket_workbench.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/poison.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/poison_bomb.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/replenish_hunger.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/ring_of_fire.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/shadow_ward.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/shield.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/shockwave.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/silverfish_swarm.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/sixth_sense.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/slime.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/smoke_bomb.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/snare.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/snowball.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/spark_bomb.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/spectral_pathway.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/spider_swarm.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/static_aura.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_blaze.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_ice_giant.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_ice_wraith.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_iron_golem.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_lightning_wraith.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_phoenix.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_shadow_wraith.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_skeleton.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_skeleton_legion.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_snow_golem.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_spirit_horse.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_spirit_wolf.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_storm_elemental.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_wither_skeleton.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/summon_zombie.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/telekinesis.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/thunderbolt.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/thunderstorm.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/tornado.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/transience.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/transportation.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/vanishing_box.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/wall_of_frost.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/water_breathing.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/whirlwind.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/wither.png create mode 100644 src/main/resources/assets/wizardry/textures/spells/wither_skull.png create mode 100644 src/main/resources/mcmod.info diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..dfe07704 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..2c770e09 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# eclipse +bin +*.launch +.settings +.metadata +.classpath +.project + +# idea +out +*.ipr +*.iws +*.iml +.idea + +# gradle +build +.gradle + +# other +eclipse +run diff --git a/CREDITS-fml.txt b/CREDITS-fml.txt new file mode 100644 index 00000000..97122f5d --- /dev/null +++ b/CREDITS-fml.txt @@ -0,0 +1,28 @@ +This is Forge Mod Loader. + +You can find the source code at all times at https://github.com/MinecraftForge/FML + +This minecraft mod is a clean open source implementation of a mod loader for minecraft servers +and minecraft clients. + +The code is authored by cpw. + +It began by partially implementing an API defined by the client side ModLoader, authored by Risugami. +http://www.minecraftforum.net/topic/75440- +This support has been dropped as of Minecraft release 1.7, as Risugami no longer maintains ModLoader. + +It also contains suggestions and hints and generous helpings of code from LexManos, author of MinecraftForge. +http://www.minecraftforge.net/ + +Additionally, it contains an implementation of topological sort based on that +published at http://keithschwarz.com/interesting/code/?dir=topological-sort + +It also contains code from the Maven project for performing versioned dependency +resolution. http://maven.apache.org/ + +It also contains a partial repackaging of the javaxdelta library from http://sourceforge.net/projects/javaxdelta/ +with credit to it's authors. + +Forge Mod Loader downloads components from the Minecraft Coder Pack +(http://mcp.ocean-labs.de/index.php/Main_Page) with kind permission from the MCP team. + diff --git a/LICENSE-new.txt b/LICENSE-new.txt new file mode 100644 index 00000000..be2c9e66 --- /dev/null +++ b/LICENSE-new.txt @@ -0,0 +1,483 @@ +Minecraft Forge is licensed under the terms of the LGPL 2.1 found +here http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt and copied +below. + +A note on authorship: +All source artifacts are property of their original author, with +the exclusion of the contents of the patches directory and others +copied from it from time to time. Authorship of the contents of +the patches directory is retained by the Minecraft Forge project. +This is because the patches are partially machine generated +artifacts, and are changed heavily due to the way forge works. +Individual attribution within them is impossible. + +Consent: +All contributions to Forge must consent to the release of any +patch content to the Forge project. + +A note on infectivity: +The LGPL is chosen specifically so that projects may depend on Forge +features without being infected with its license. That is the +purpose of the LGPL. Mods and others using this code via ordinary +Java mechanics for referencing libraries are specifically not bound +by Forge's license for the Mod code. + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/MinecraftForge-Credits.txt b/MinecraftForge-Credits.txt new file mode 100644 index 00000000..d0de5a52 --- /dev/null +++ b/MinecraftForge-Credits.txt @@ -0,0 +1,26 @@ +* Eloraam * + +* FlowerChild * + +* Hawkye * + +* MALfunction84 * + +Submitted the sleep handler code for his mod (Somnia) and others to use. + +* Scokeev9 * + +Gave permission for ScotTools API to be integrated into MCF, and also supported the Forge by converting his mods to use it. + +ScotTools Background: ScotTools was an API that enabled modders to add blocks to harvesting levels (and many other ease-of-use features to create new tools), and the first tool API that used block material for block breaking efficiency which allowed blocks from mods that didn't use ScotTools API to break with the correct speed. + +* SpaceToad * + +* LexManos * + +* cpw * + +* Minecraft Coder Pack (MCP) * +Forge Mod Loader and Minecraft Forge have permission to distribute and automatically download components of MCP and distribute MCP data files. +This permission is not transitive and others wishing to redistribute the Minecraft Forge source independently should seek permission of MCP or +remove the MCP data files and request their users to download MCP separately. diff --git a/Paulscode IBXM Library License.txt b/Paulscode IBXM Library License.txt new file mode 100644 index 00000000..d4884b07 --- /dev/null +++ b/Paulscode IBXM Library License.txt @@ -0,0 +1,10 @@ +IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/Paulscode SoundSystem CodecIBXM License.txt b/Paulscode SoundSystem CodecIBXM License.txt new file mode 100644 index 00000000..a68a4947 --- /dev/null +++ b/Paulscode SoundSystem CodecIBXM License.txt @@ -0,0 +1,40 @@ +SoundSystem CodecIBXM Class License: + +You are free to use this class for any purpose, commercial or otherwise. +You may modify this class or source code, and distribute it any way you +like, provided the following conditions are met: + +1) You may not falsely claim to be the author of this class or any + unmodified portion of it. +2) You may not copyright this class or a modified version of it and then + sue me for copyright infringement. +3) If you modify the source code, you must clearly document the changes + made before redistributing the modified source code, so other users know + it is not the original code. +4) You are not required to give me credit for this class in any derived + work, but if you do, you must also mention my website: + http://www.paulscode.com +5) I the author will not be responsible for any damages (physical, + financial, or otherwise) caused by the use if this class or any + portion of it. +6) I the author do not guarantee, warrant, or make any representations, + either expressed or implied, regarding the use of this class or any + portion of it. + +Author: Paul Lamb +http://www.paulscode.com + + +This software is based on or using the IBXM library available from +http://www.geocities.com/sunet2000/ + + +IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..30732099 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Wizardry diff --git a/README.txt b/README.txt new file mode 100644 index 00000000..b45931f4 --- /dev/null +++ b/README.txt @@ -0,0 +1,59 @@ +------------------------------------------- +Source installation information for modders +------------------------------------------- +This code follows the Minecraft Forge installation methodology. It will apply +some small patches to the vanilla MCP source code, giving you and it access +to some of the data and functions you need to build a successful mod. + +Note also that the patches are built against "unrenamed" MCP source code (aka +srgnames) - this means that you will not be able to read them directly against +normal code. + +Source pack installation information: + +Standalone source installation +============================== + +Step 1: Open your command-line and browse to the folder where you extracted the zip file. + +Step 2: Once you have a command window up in the folder that the downloaded material was placed, type: + +Windows: "gradlew setupDecompWorkspace" +Linux/Mac OS: "./gradlew setupDecompWorkspace" + +Step 3: After all that finished, you're left with a choice. +For eclipse, run "gradlew eclipse" (./gradlew eclipse if you are on Mac/Linux) + +If you preffer to use IntelliJ, steps are a little different. +1. Open IDEA, and import project. +2. Select your build.gradle file and have it import. +3. Once it's finished you must close IntelliJ and run the following command: + +"gradlew genIntellijRuns" (./gradlew genIntellijRuns if you are on Mac/Linux) + +Step 4: The final step is to open Eclipse and switch your workspace to /eclipse/ (if you use IDEA, it should automatically start on your project) + +If at any point you are missing libraries in your IDE, or you've run into problems you can run "gradlew --refresh-dependencies" to refresh the local cache. "gradlew clean" to reset everything {this does not effect your code} and then start the processs again. + +Should it still not work, +Refer to #ForgeGradle on EsperNet for more information about the gradle environment. + +Tip: +If you do not care about seeing Minecraft's source code you can replace "setupDecompWorkspace" with one of the following: +"setupDevWorkspace": Will patch, deobfusicated, and gather required assets to run minecraft, but will not generated human readable source code. +"setupCIWorkspace": Same as Dev but will not download any assets. This is useful in build servers as it is the fastest because it does the least work. + +Tip: +When using Decomp workspace, the Minecraft source code is NOT added to your workspace in a editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes and usually can be accessed under the 'referenced libraries' section of your IDE. + +Forge source installation +========================= +MinecraftForge ships with this code and installs it as part of the forge +installation process, no further action is required on your part. + +LexManos' Install Video +======================= +https://www.youtube.com/watch?v=8VEdtQLuLO0&feature=youtu.be + +For more details update more often refer to the Forge Forums: +http://www.minecraftforge.net/forum/index.php/topic,14048.0.html diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..ed1e5ab8 --- /dev/null +++ b/build.gradle @@ -0,0 +1,76 @@ +buildscript { + repositories { + jcenter() + maven { url = "http://files.minecraftforge.net/maven" } + } + dependencies { + classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT' + } +} +apply plugin: 'net.minecraftforge.gradle.forge' +//Only edit below this line, the above code adds and enables the nessasary things for Forge to be setup. + + +version = " 2.1.0 - MC 1.10.2" +group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html +archivesBaseName = "Electroblob's Wizardry " + +srcCompat = JavaVersion.VERSION_1_8 +targetCompat = JavaVersion.VERSION_1_8 + +minecraft { + version = "1.10.2-12.18.3.2185" + runDir = "run" + + // the mappings can be changed at any time, and must be in the following format. + // snapshot_YYYYMMDD snapshot are built nightly. + // stable_# stables are built at the discretion of the MCP team. + // Use non-default mappings at your own risk. they may not allways work. + // simply re-run your setup task after changing the mappings to update your workspace. + mappings = "snapshot_20161111" + // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. +} + +dependencies { + // you may put jars on which you depend on in ./libs + // or you may define them like so.. + //compile "some.group:artifact:version:classifier" + //compile "some.group:artifact:version" + + // real examples + //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env + //compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env + + // the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime. + //provided 'com.mod-buildcraft:buildcraft:6.0.8:dev' + + // the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided, + // except that these dependencies get remapped to your current MCP mappings + //deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev' + //deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev' + + // for more info... + // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html + // http://www.gradle.org/docs/current/userguide/dependency_management.html + +} + +processResources +{ + // this will ensure that this task is redone when the versions change. + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + // replace stuff in mcmod.info, nothing else + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + + // replace version and mcversion + expand 'version':project.version, 'mcversion':project.minecraft.version + } + + // copy everything else, thats not the mcmod.info + from(sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } +} diff --git a/forge-1.10.2-12.18.3.2185-changelog.txt b/forge-1.10.2-12.18.3.2185-changelog.txt new file mode 100644 index 00000000..479c2ec5 --- /dev/null +++ b/forge-1.10.2-12.18.3.2185-changelog.txt @@ -0,0 +1,11549 @@ +Changelog: +Build 2185: + LexManos: Bump version number for new Recommended Build. + +Build 1.11-13.19.0.2184: + LexManos: + Prevent a crash when scheduling block updates for non-existing blocks + #3485 + +Build 1.10.2-12.18.2.2183: + LexManos: + Prevent a crash when scheduling block updates for non-existing blocks + #3485 + +Build 1.10.2-12.18.2.2182: + LexManos: + Make Container.mergeItemStack respect target slot's max size when slot + is non-empty. Closes #3498 Fix Shift clicking in Beacons with stacked + items when fuel slot is empty. + (cherry picked from commit c6bc4ec5a92b640ebe773bfa48732dfa7eb59a17) + LexManos: + Fix NPE when rendering missing mod screen with version bound + requirements. #3501 + (cherry picked from commit c1e832bff09c949bfe736f492c2e4aa8004baa84) + LexManos: + Fix issue reading chunks from the network when client and server do not + agree on block count. Closes #34925 + (cherry picked from commit daf21e4dcf246cfa15c362800effc5dc787ab777) + +Build 1.11-13.19.0.2181: + LexManos: Make sure to log kick messages in NetworkDispatcher. Closes #3507 + LexManos: + Fix NPE when rendering missing mod screen with version bound + requirements. #3501 + LexManos: + Added isItemValidForSlot check to hopper extraction (#3444) + (cherry picked from commit 0348760a774ca7ed9639376baadae38e272f5bf8) + LexManos: + Fix for showing config default values twice in tooltip (#2257) (#3338) + (cherry picked from commit be73ec3d5ebd972cfacb0f255f71112a0430bc43) + LexManos: + Add null check and informative error message when client receives an + invalid update packet (#3266) + (cherry picked from commit 882e0e3bf22784d693e3816b0efeba5fbedb1a22) + LexManos: + Add ItemBlockSpecial#getBlock (#3343) + (cherry picked from commit cf26f4acbe48ee8790edc03d0b5c16c1167278ab) + LexManos: + Added gradle.properties to MDK (#3361) + The file sets the default max heap size to 3 GiB so that the + decompilation doesn't fail as often. + (cherry picked from commit 49ec3d1b9322ee2b7a1312059118173b0b3fe6d0) + LexManos: + Make SlotItemHandler override Slot.getSlotStackLimit. Closes #3497 Make + Container.mergeItemStack respect target slot's max size when slot is + non-empty. Closes #3498 Fix Shift clicking in Beacons with stacked items + when fuel slot is empty. + LexManos: Restore missed patch in World.updateComparatorOutputLevel. Closes #3495 + LexManos: + Fix issue reading chunks from the network when client and server do not + agree on block count. Closes #34925 + +Build 1.11-13.19.0.2180: + diesieben07: Add missing pooled BlockPos retain in World patch (#3486) + mezz: + Add a way for modded GuiScreens to cancel mouse and keyboard events + (#3438) + blay09: + [1.11] Add canApplyAtEnchantmentTable to Item (#3463) + Allowing increased control of which enchantments can be put on an item + over Vanilla's hard-coded item type checks. + disabled when the item is enchantable but the enchantability requirement + is not met on lower levels. + mezz: [1.11] Add biome dictionary types for newer biomes (#3475) + bs2609: [1.11] Fix null checks in shouldCauseReequipAnimation (#3482) + +Build 1.10.2-12.18.2.2179: + blay09: + Add null check and informative error message when client receives an + invalid update packet (#3266) + raoulvdberge: Add ItemBlockSpecial#getBlock (#3343) + yannick: + Added gradle.properties to MDK (#3361) + The file sets the default max heap size to 3 GiB so that the + decompilation doesn't fail as often. + +Build 1.11-13.19.0.2178: + liach: Moved TextureStitchEvent.Pre to allow custom sprites for blocks (#3436) + +Build 1.11-13.19.0.2177: + bs2609: Fix sky colour blending not working for render distances >16 (#3476) + +Build 1.11-13.19.0.2176: + logictechcorp: Allow connectable blocks to choose what they can connect to (#3437) + +Build 1.11-13.19.0.2175: + dawn0966: Changed Armor Material to use an ItemStack aware version (#3469) + +Build 1.11-13.19.0.2174: + bs2609: Fix Redstone Torch memory leak (#3474) + +Build 1.11-13.19.0.2173: + diesieben07: BiomeDictionary code cleanup (#3466) + +Build 1.11-13.19.0.2172: + TechnicianLP: Added EquipmentChangeEvent (#3411) + +Build 1.10.2-12.18.2.2171: + bs2609: Fix Redstone Torch memory leak (#3271) + +Build 1.10.2-12.18.2.2170: + 1vInc: Fix for showing config default values twice in tooltip (#2257) (#3338) + +Build 1.11-13.19.0.2169: + marvinroesch99: Update assets to new Forge brand (#3464) + +Build 1.11-13.19.0.2168: + LexManos: + First pass at exposing data fixers to modders. Each mod gets its own + version number, mods SHOULD NOT rely on other mod's fixers, just care + about yourself. Walkers can use IDataFixerData to retrieve their + version. + +Build 1.11-13.19.0.2167: + williewillus: Add getSlotLimit(slot) to IItemHandler (#3445) + +Build 1.10.2-12.18.2.2166: + draco18s: Added isItemValidForSlot check to hopper extraction (#3444) + +Build 1.11-13.19.0.2165: + mezz: Provide access to GuiContainer location and dimensions (#3440) + kashike: + Add method to check if an Entity can trample a Block. Fixes #2510 + (#2730) + cpw: + Pass along if the respawn event was the result of the end being + conquered or not (end respawning is really FUNKY code and uses death + instead of 'change dimension') + +Build 1.11-13.19.0.2162: + bs2609: Clean up handling of changes to IVertexConsumer (#3458) + +Build 1.11-13.19.0.2161: + bs2609: Quick fix for another ItemStack null check (#3426) + mezz: Provide access to ShapedOreRecipe width and height (#3439) + +Build 1.11-13.19.0.2160: + cpw: + Fix problem with the server hanging around after forcing the client to + exit, leaving behind stale processes. + +Build 1.11-13.19.0.2159: + mezz: + Fix #3432 Hopper and Dropper item moving does not exactly match vanilla + (#3442) + mezz: Fix using the wrong Pair implementation (#3449) + +Build 1.11-13.19.0.2157: + mezz: Fix #3424 ItemCraftedEvent returns air when shift-clicking (#3441) + +Build 1.11-13.19.0.2156: + mezz: + Cleanup some null checks and remove deprecated methods in Item and Block + (#3429) + +Build 1.11-13.19.0.2155: + LexManos: Make all tests one side only, so we can test vanilla clients in dev env. + LexManos: + Insert FML packet handler into Vanilla pipelines in case modders send + FMLPacket to vanilla. Fixes #3422 + LexManos: Fix max CustomPayload size, 1MB not 16MB. + +Build 1.11-13.19.0.2154: + LexManos: Fix AbstractMethodException in FML Registries. Closes #3427 + +Build 1.11-13.19.0.2153: + shadowfacts: + Move EntityHorse capability patches to AbstractHorse (#3417) + Fixes #3409 + LexManos: Fix ItemStack null check in PlayerInteractionManager + +Build 1.11-13.19.0.2152: + shadowfacts: Initial annotations/nullability changes (#3392) + TechnicianLP: Remove Block.addInformation exists in vanilla (#3413) + LexManos: Fix Item transfers related to Hoppers. + +Build 1.10.2-12.18.2.2151: + ohai.iChun: + Add GetCollisionBoxesEvent. Allows manipulation of the collision boxes + for moving entities and entities stuck in walls. (#3397) + +Build 1.11-13.19.0.2150: + ohai.iChun: + Add GetCollisionBoxesEvent. Allows manipulation of the collision boxes + of blocks for entities. MC1.11 edition. (#3405) + +Build 1.11-13.19.0.2149: + LexManos: First draft of Entity Registry re-write. + +Build 1.11-13.19.0.2148: + LexManos: + Make Wither Skulls respect Block.canEntityDestroy. Closes #3404 + (cherry picked from commit 6b52023a5c341420d976cb50359e2a2a4a6a9192) + +Build 1.10.2-12.18.2.2147: + LexManos: Make Wither Skulls respect Block.canEntityDestroy. Closes #3404 + +Build 1.11-13.19.0.2146: + Bartek_s2: Added EnumHand parameter to Block.getStateForPlacement (#3402) + +Build 1.11-13.19.0.2145: + LexManos: + Fix issues with ZombieVillagers Closes #3398 1.11 doesn't intertwine + zombie types anymore so our edits to split them out for custom + professions are not needed. + LexManos: Fix client side placement issue on blocks with GUIs. Closes #3399 + +Build 1.11-13.19.0.2144: + ezterry3: + Fix Villagers for 1.11 (#3401) + - Add cartographer registry entry + - Fix textures for the nitwit + +Build 1.11-13.19.0.2143: + mezz: [1.11] Fix nullability issues around ForgeHooks and Capabilities (#3395) + +Build 1.11-13.19.0.2142: + larsgerrits99: + Change OreDictionary over from "null" to the new ItemStack system. + (#3400) + +Build 1.11-13.19.0.2141: + LexManos: + Do not install mod_list.json for optional mods. Classpath scanning is in + so they will still be detected + +Build 1.10.2-12.18.2.2140: + LexManos: + Do not install mod_list.json for optional mods. Classpath scanning is in + so they will still be detected + +Build 1.10.2-12.18.2.2139: + LexManos: Include Mercurius in installer. See Forge Forums for more info. + +Build 1.11-13.19.0.2138: + LexManos: Include Mercurius in installer. See Forge Forums for more info. + +Build 1.11-13.19.0.2137: + LexManos: Restore the ability to register modded TileEntities. + +Build 1.11-13.19.0.2136: + mezz: Remove deprecated Fluid stuff + mezz: Implement fluid item capabilities without item swapping + +Build 1.11-13.19.0.2135: + LexManos: + Make EntityShulker fire EnderTeleportEvent. Closes #3383 + (cherry picked from commit d48985fafaed6de6f09136b999ca8aa44184a7b9) + LexManos: Fixed damage bar color. Closes #3389 + LexManos: Fix ItemStackHandler's constructor ignoring size. Closes #3386 + shadowfacts: Fix crafting causing crash (#3388) Closes #3387 + +Build 1.10.2-12.18.2.2134: + LexManos: Update installer to 1.5, and fix local buildscript issues. + LexManos: Make EntityShulker fire EnderTeleportEvent. Closes #3383 + +Build 1.11-13.19.0.2133: + LexManos: + Added event to allow modification of player visibility to mobs/AI + (#3382) + (cherry picked from commit 0a5ef64d6ea96fe85d7c62107081ced649e6a3e9) + +Build 1.10.2-12.18.2.2132: + maxanier: + Added event to allow modification of player visibility to mobs/AI + (#3382) + +Build 1.11-13.19.0.2131: + LexManos: Apply missed patch to WorldProvider. + mezz: [1.11] Fix initCapabilities for ItemStacks (#3379) + LexManos: Disable capabilities for empty ItemStacks. + LexManos: Restore another missing patch in WorldProvider. + +Build 1.11-13.19.0.2130: + LexManos: + Fix build.gradle problems: Installer missing url.png UploadArchives + erroring on local systems due to missing changelog Adding branch name + improperly. + +Build 1.11-13.19.0.2129-1.11.x: + LexManos: Fix localizations not loading correctly in legacy resource packs. + +Build 1.11-13.19.0.2128-1.11.x: + LexManos: Fix FurnaceRecipy registration. + +Build 1.11-13.19.0.2127-1.11.x: + LexManos: Fixed test cases for 1.11 changes. + +Build 1.10.2-12.18.2.2125: + cpw: Update to 20161111 mcp names + cpw: regenerate entitylivingbase patch + +Build 1.10.2-12.18.2.2124: + mezz: Improve error message from crashes during loading (#3362) + +Build 1.10.2-12.18.2.2123: + draco18s: Added events for crop growth (#3320) + +Build 1.10.2-12.18.2.2122: + maxanier: Add support for custom entity selectors in commands (#3356) + +Build 1.10.2-12.18.2.2121: + latvianmodder: Added PermissionAPI (#3155) + +Build 1.10.2-12.18.2.2120: + Choonster.2010: Add hand argument to BlockEvent.PlaceEvent (#3221) (#3270) + +Build 1.10.2-12.18.2.2119: + jezzadabomb: + Fixes #3237 and #2752. (#3347) + * Fix #3237 by correctly utilising the keepLooking argument. + + * Explain within SimpleNetworkWrapper's javadoc that the execute of the + handler isn't on the main Minecraft thread. + +Build 1.10.2-12.18.2.2118: + draco18s: Made default slot implementation respect inventory stack size limit. + +Build 1.10.2-12.18.2.2117: + aa1ronham: Fixed Block.setBedOccupied ignoring 'occupied' parameter + +Build 1.10.2-12.18.2.2116: + raoulvdberge: + Add Item#getNBTShareTag (#3342) + * Add Item#getNBTShareTag + + * Update comment + +Build 1.10.2-12.18.2.2115: + bonii-xx: + Call Looting Event on player death and loot table drops (#3275) + * Call Looting Event on player death and loot table drops + + * Simplify patches + + * More code cleanup: Replace old usage with compact forgehooks + implementation + +Build 1.10.2-12.18.2.2114: + LexManos: Fix POTENTIAL issue with Texture Stitcher exceeding max size. + +Build 1.10.2-12.18.2.2113: + dawn0966: + Fixed Ore Dictionary replacing the oak boat recipe (#3329) + Fixes the oak boat recipe being able to be crafted with any wood + +Build 1.10.2-12.18.2.2112: + rwtema: + Improve the default isItemValid() and getItemStackLimit() + implementations in SlotItemHandler. You can now properly swap the + player's held itemstack with the slot's itemstack. (#3273) + +Build 1.10.2-12.18.2.2111: + LexManos: + Fixed texture stitcher not using full texture height before expanding + width. + +Build 1.10.2-12.18.2.2110: + LexManos: + Special case not drooping snowballs for water and snow layers. Closes + #3326 + LexManos: Update readme to be a little more clear. + +Build 1.10.2-12.18.2.2109: + bs2609: Fix MC-105406 (OpenGL leak in View Frustum) (#3308) + +Build 1.10.2-12.18.2.2108: + mezz: Fix very laggy mipmap slider MC-64581 (#3305) + +Build 1.10.2-12.18.2.2107: + shadowfacts: Add Block#getStateForPlacement (#3129) + +Build 1.10.2-12.18.2.2106: + mezz: Add better key modifier behavior for GUI contexts (#3307) + +Build 1.10.2-12.18.2.2105: + tterrag1098: Make item repair recipe respect itemstack's getMaxDamage (#3295) + +Build 1.10.2-12.18.2.2104: + LexManos: Fix Tabbing issues with config classes. + LexManos: Fix infinite loop in dragon fight when the dragon is over the void. + +Build 1.10.2-12.18.2.2103: + LexManos: Initial pass a re-working the configuration system. Work in progress. + +Build 1.10.2-12.18.2.2102: + atomicblom+github: Allow all Forge Registries to work with ObjectHolder (#3220) + LexManos: @ObjectHolder will now inject null for dummied objects. Closes #3301 + cpw: + Revert "Another fix for registry substitutions. Closes #3212" + This reverts commit ec2977afc919c0f676f59977e6065148ea635f9e. + cpw: + Fix substitutions being broken after freezing - actually store the + original state in registry copies, not the computed state, which is + wrong because it only sees the sub, not the original. + cpw: + Add in missing test runner for a test. Fixes failing tests on jenkins, + hopefully. + +Build 1.10.2-12.18.2.2099: + LexManos: + Revert commits related to filtering proxy and Automatic Subscriber + annotations. Broke some existing setups, will require a annotation + definition change in 1.11. + +Build 1.10.2-12.18.2.2098: + mezz: Fix proxy injector filtering. (#3300) + +Build 1.10.2-12.18.2.2097: + LexManos: Bump version for new Recommended Build. + +Build 1.10.2-12.18.1.2096: + LexManos: Small Cleanup in example build.gradle. + LexManos: + Filter out proxy injectors for incorrect mods. Prevents mod classes + being initialized early when multiple mods are in the same source. + LexManos: + Introduce IContextSetter for events. This will set the active mod + container for events using the normal EventBus. Fixes improper warnings + from initializing mods using the new Registry events. Modders, you + should not use this as it has many performance implementations and if + abused will slow down the event bus A LOT. ActiveModContainer is not + thread safe. + +Build 1.10.2-12.18.1.2095: + mezz: Fix unbound keybindings are activated by unknown keyboard keys (#3288) + +Build 1.10.2-12.18.1.2094: + mmehnert: + caseSensitiveCustomCategories must be set before loading the + configuration file. (#3269) + Otherwise one set with categories in lowercase letters and on case + sensitive + +Build 1.10.2-12.18.1.2093: + tterrag1098: Fix typo in sky rendering causing tons of BlockPos allocations (#3267) + +Build 1.10.2-12.18.1.2092: + cpw: + Add in registry registration events, new subscription events you can use + to make sure you're registering things at the "best" time. + +Build 1.10.2-12.18.1.2091: + LexManos: + Add support for generic filtering of events. Please DO NOT use this in + performance sensitive environments where you will have tons of things + added to the listener list. If that's the case define sub-classes as + they have completely separate lists and will thus be more efficient when + firing the event. + +Build 1.10.2-12.18.1.2090: + lukas.tenbrink: + Fix roofed forests posting decoration events for small mushrooms rather + than big (#3259) + +Build 1.10.2-12.18.1.2089: + mattmess1221: + Add support for offhand bow aiming animation (#3085) + Vanilla allows you to use a bow in your offhand, but it's not visible to + others or in third person. + +Build 1.10.2-12.18.1.2088: + tehgeek: + Remove oredict for Bone Block recipe, stop white dye to bonemeal exploit + (#3255) + +Build 1.10.2-12.18.1.2087: + LexManos: + Fixed Biome.platFlower not being called when bonemealing grass. Closes + #3254 + +Build 1.10.2-12.18.1.2086: + latvianmodder: + Added getCommandMap() & getSortedCommandList() in CommandTreeBase + (#3251) + +Build 1.10.2-12.18.1.2085: + atomicblom+github: New event to allow mutating a baby entity based on it's parents (#3227) + +Build 1.10.2-12.18.1.2084: + latvianmodder: Added CommandTreeBase (#3193) + +Build 1.10.2-12.18.1.2083: + paul.fulham0: Fix debug command creating empty file (MC-103399) (#3218) + +Build 1.10.2-12.18.1.2082: + marvinroesch99: Fix universal bucket not being returned in crafting recipes (#3234) + +Build 1.10.2-12.18.1.2081: + cpw: Create EnergySystems.md + +Build 1.10.2-12.18.1.2080: + LexManos: + Introducing a new standardized energy capability system. Heavily + inspired by the old RedstoneFlux API developed by King Lemming and Team + CoFH. + LexManos: Fix potential shading issue in GuiEditArrayEntries. Closes #3247 + +Build 1.10.2-12.18.1.2079: + LexManos: Fixed ItemStacks having ForgeCaps tag when no caps are serialized. + +Build 1.10.2-12.18.1.2078: + LexManos: Fix Cactus being able top be planted on incorrect soil. + +Build 1.10.2-12.18.1.2077: + bloodmc: Fix wrong var being used during getMaxSpawnPackSize check. (#3240) + +Build 1.10.2-12.18.1.2076: + LexManos: + Move dismount version of EntityMountEvent to Entity class. Should fix + canceling dismounting. Closes #3226 + +Build 1.10.2-12.18.1.2075: + LexManos: Yet another fix for stupid stairs. Closes #3224 + +Build 1.10.2-12.18.1.2074: + LexManos: Make StructureBlock TESRs always render. Closes #3222 + +Build 1.10.2-12.18.1.2073: + paul.fulham0: Fix item use stats (#3216) + +Build 1.10.2-12.18.1.2072: + LexManos: + Fixed decorate event being called with SHROOM type for both convered + trees and large mushrooms. Closes #3215 + +Build 1.10.2-12.18.1.2071: + LexManos: Another fix for registry substitutions. Closes #3212 + +Build 1.10.2-12.18.1.2070: + LexManos: Add legacy support for signature change of AddCallback. + LexManos: + Update gradle wrapper to 2.14, reference MC json, and add java6 compat + lines to default MDK build.gradle. + +Build 1.10.2-12.18.1.2069: + bonii-xx: Revert changes to ItemTool for binary compatibility (#3211) + +Build 1.10.2-12.18.1.2068: + bonii-xx: Expand getHarvestLevel to include player and blockstate (#3192) + +Build 1.10.2-12.18.1.2067: + LexManos: + Make enchantment tables spawn particles for any custom energy provider. + Closes #3208 + +Build 1.10.2-12.18.1.2066: + williewillus: Allow blocks to affect the beacon color (#3205) + +Build 1.10.2-12.18.1.2065: + LexManos: Fix armors rendering badly. Closes #3196 + +Build 1.10.2-12.18.1.2064: + abab9579: Fixed NPE from missing Capabilities (#3191) + +Build 1.10.2-12.18.1.2063: + LexManos: Fix World Capabilities NPE when there are no attached capabilities. + +Build 1.10.2-12.18.1.2062: + abab9579: Introduced Capabilities for World (#3069) + +Build 1.10.2-12.18.1.2061: + LexManos: + Fix vanilla bug in BlockFalling that caused blocks to loose state info + during world gen. Closes #3183 + +Build 1.10.2-12.18.1.2060: + Gerard Bruwn: Added PlayerBrewedPotionEvent (#3187) + +Build 1.10.2-12.18.1.2059: + cpw: Don't crash if you select a fake player + +Build 1.10.2-12.18.1.2058: + LexManos: + Skip searching for mods in the JAVA_HOME directory. Closes #2249 and + #2250 + +Build 1.10.2-12.18.1.2057: + LexManos: + Fix leather armor overlay not rendering when armor is pure white. Closes + #3184 + +Build 1.10.2-12.18.1.2056: + josephcsible: + Fix test mod IDs, names, and versions (#3122) + Most of our test mods have bad IDs (uppercase) and are missing names or + versions. Forge produces a bunch of warnings in the console about this, + which + +Build 1.10.2-12.18.1.2055: + florian: + Make InventoryHelper#spawnItemStack use ItemStack#splitStack to avoid + losing capability data. (#3163) + +Build 1.10.2-12.18.1.2054: + sebastian: + Unlike BakedQuad, UnpackedBakedQuad does not propagate the diffuse + lighting flag to Vertex Consumers. Made UnpackedBakedQuad conform to + BakedQuad's behavior. (#3181) + +Build 1.10.2-12.18.1.2053: + LexManos: + Set ModelLoader.WHITE's texture size iniatlly instead of defaulting to + zero and being set later. + LexManos: Add RenderTooltipEvent (#3034) + +Build 1.10.2-12.18.1.2052: + tehgeek: + Fix #3165 Dispensers with buckets can destroy fluid handler blocks + (#3180) + +Build 1.9.4-12.17.0.2051: + tterrag1098: Add RenderTooltipEvent (#3034) + +Build 1.10.2-12.18.1.2050: + LexManos: Fix Fire not using getFireSpreadSpeed. Closes #3175 + +Build 1.10.2-12.18.1.2049: + LexManos: Fix issue with stairs. + +Build 1.10.2-12.18.1.2048: + LexManos: Removed unintentional functionality when using the Splash Screen. + +Build 1.10.2-12.18.1.2047: + LexManos: Make stair culling use actual state, and be more robust. Closes #3170 + LexManos: Fix name in legacy support in registry changes. + LexManos: + Compleetly skip FML handshake for Vanilla connections. Should fix race + condition. Closes #3084 + LexManos: + Disable DecorateEventDebug by default. Prevents me thinking that + decoration is broken >.< + +Build 1.10.2-12.18.1.2046: + AlgorithmX2: + Fix Vertex Transformer for breaking models (#3132) + * Add setTexture to IVertexConsumer and propagate it. + +Build 1.10.2-12.18.1.2045: + LexManos: + Restone binary compatibility with registry substitution rework. Modders + please switch to using the provided RegistryBuilder to ensure more + forward compatbility. Closes #3144 + LexManos: Fix Forge fluids not serializing properly. Closes #3152 + +Build 1.10.2-12.18.1.2044: + LexManos: + Second pass at fixing 'Dissapearing Doors' This now more robustly fixes + ALL uses of get and has slight performance improvements for itterable + states. Closes #3139 + +Build 1.10.2-12.18.1.2043: + LexManos: + Added config option to disable Forge's fix of Stair/Slab face culling. + Some vanilla resource packs exploit this issue in their custom models + causing unintended rendering issues. + +Build 1.10.2-12.18.1.2042: + LexManos: + Fixed 'Dissapearing Doors', An issue where the world would try to save + blockstates that are not serializeable. + +Build 1.10.2-12.18.1.2041: + cpw: Allow CommandEvent to change the parameter set. Closes #1762 + +Build 1.10.2-12.18.1.2040: + cpw: + Another pass at substitutions - now capable of fixing up ItemBlock to + point at the right block when a block is substituted, should also handle + substituting itemblocks. There's some hackery in the way we have to + change the value of ItemBlock.block, but it's not too egregious in my + opinion. + +Build 1.10.2-12.18.1.2039: + dakotapierone: Update decorate for biomes to support Decorate event + cpw: Clean up AT file + +Build 1.10.2-12.18.1.2038: + cpw: + Fix anvil output slots being wrong by adding new ones. Closes #3121 + without breaking existing mod workarounds for the badly ordered slots. + +Build 1.10.2-12.18.1.2037: + vincent.lee: + Expose vanilla brewing recipe registration (cherry picked from commit + 24bf163) + +Build 1.10.2-12.18.1.2036: + cpw: + Clean up some legacy settings, making sure there's translation strings. + Closes #2965 Thanks for the prompt Zaggy! + +Build 1.10.2-12.18.1.2035: + vincent.lee: Fix MC-91728 (cherry picked from commit 71f75bf) + cpw: Refresh patch after cherry pick (cherry picked from commit 71f75bf) + +Build 1.10.2-12.18.1.2034: + vincent.lee: + Remove sideonly on all other SoundType methods (cherry picked from + commit 46c7cac) + +Build 1.10.2-12.18.1.2033: + mnmiller1: + Fixed NeighborNotifyEvent not containing the piston facing direction. + (cherry picked from commit 5637c41) + +Build 1.10.2-12.18.1.2032: + AlgorithmX2: Use extended state for breaking models (#3086) + +Build 1.10.2-12.18.1.2031: + vincent.lee: No-nonsense getSoundType + cpw: Clean up block patch. Also push json update. + +Build 1.10.2-12.18.1.2030: + Creative-Multimedia-Design: Fixed sound paused/resume issue + +Build 1.10.2-12.18.1.2029: + alexandre.duponchel: FIX : IndexOutOfBoundException + +Build 1.10.2-12.18.1.2028: + cpw: Mark it for actual removal in 1.11 + cpw: Tidy up some more todos + cpw: + Fix #3126 - duplicate stat id error - don't use the "universal + iterators" in statbuilding, use the one without the duplicate entries. + (The duplicate entry one is for rendering setup) + +Build 1.10.2-12.18.1.2027: + cpw: + Fix a vanilla bug with the blockstate ID map not being properly + symmetric with respect to block.getStateFromMeta - closes #3012 properly + but probably has a random MCJIRA ticket somewhere too. + +Build 1.10.2-12.18.1.2026: + vincent.lee: Add ability for custom detector rail output + vincent.lee: Move to a hook in EntityMinecart + vincent.lee: Remove event stuff + +Build 1.10.2-12.18.1.2025: + mezz: Force mipmap even if textures are the wrong size + mezz: Add TextureDump forge test mod + +Build 1.10.2-12.18.1.2024: + vincent.lee: Add hand-specific render event + vincent.lee: Add missing cancelable + cpw: Rename the event to RenderSpecificHandEvent + +Build 1.10.2-12.18.1.2023: + josephcsible: Add CreateFluidSourceEvent to control infinite fluid sources + josephcsible: Add a test for CreateFluidSourceEvent + josephcsible: Use CreateFluidSourceEvent for mod fluids as well + +Build 1.10.2-12.18.1.2022: + mezz: Fix hotkey with default modifier loading wrong when modifier set to NONE + +Build 1.10.2-12.18.1.2021: + bernhard.bonigl: + Add shouldCauseBlockBreakReset callback to Item. This allows to keep + breaking blocks if the NBT or similar changes. + +Build 1.10.2-12.18.1.2020: + Mumfrey: Store member field mappings in the mapping table, possible fix for #3043 + +Build 1.10.2-12.18.1.2019: + cpw: + Something that needs to happen: warn people about bad modids- if they're + not lowercased, or if they're too long. + +Build 1.10.2-12.18.1.2018: + ezterry3: + Fix async race condition on new chunks (closes #3020) (#3090) + This patch fixes a race condition that sometimes caused a just generated + chunk + structures to + generated version + chunk. + This patch ensures when ProvideChunk calls LoadChunk synchronously we + always + condition without + already saved to disk. + Thus this should retain the async functionality from PR #2946 while + preventing + +Build 1.10.2-12.18.1.2017: + cpw: + Some test harness stuffs. Time to get the registry manager properly + tested. + cpw: + More tests. Substitutions now work, and a fix is included. *sigh* Closes + too many bugs to count. + cpw: Some more substitution tests. It seems like it's working as it should. + cpw: Some dummy block replacement tests - it seems they work correctly. + cpw: Add the new tests into the suite + cpw: + Some tweaks to ContainedDeps - it should extract to a file in + versionedMods directly, even if the tag in the jar has a subpath + element. It'll also skip if there is a matching filename in the main + mods dir. + +Build 1.10.2-12.18.1.2016-failtests: + cpw: Some more substitution tests. It seems like it's working as it should. + cpw: Some dummy block replacement tests - it seems they work correctly. + +Build 1.10.2-12.18.1.2014: + LexManos: + Added support for using static methods as event listeners, Register the + .class instead of an instance. And added an improvement to calltime + listener rebuilding. + +Build 1.10.2-12.18.1.2013: + cpw: Lets make a half-decent readme. Thanks to Rorax for the install video! + +Build 1.10.2-12.18.1.2012: + mezz: Add Forge fluid handler test + +Build 1.10.2-12.18.1.2011: + LexManos: Bump version for a RB + +Build 1.10.2-12.18.0.2010: + bernhard.bonigl: + Add an event that allows to modify the looting level based on damage + source + +Build 1.10.2-12.18.0.2009: + williewillus: Add throwable impact event (#3071) + +Build 1.10.2-12.18.0.2007-1.10.0: + LexManos: + Fix hopper extract behavior being broken on edge cases due to + IItemHandler capability. Closes #3062 + +Build 1.10.2-12.18.0.2006-1.10.0: + LexManos: + Fixed FPS graph and new debug lines not being rendered in Debug screen. + Closes #3054 + +Build 1.10.2-12.18.0.2005-1.10.0: + diesieben07: + Restore (buggy?) behavior of vanilla BlockPistonMoving and ignore drop + chance (#3052) + +Build 1.10.2-12.18.0.2004-1.10.0: + LexManos: + Fix villages generating to high when using a cusom sea level. Closes + #3050 + +Build 1.10.2-12.18.0.2003-1.10.0: + LexManos: + Forge will now load extra mods from mods/mod_list.json and + mods/mc_version/mod_list.json. As defined by the same json spec as + --modListFile. And now if repositoryRoot is prefixed with absolute: the + path will NOT be relative to the MC directory. + LexManos: + Update build.gradle to have single line for specifying minecraft + version, and will update ForgeVersion.java as needed. + +Build 1.10.2-12.18.0.2002-1.10.0: + LexManos: + Fixed MC version number... I could of SWORN we removed this in favor of + a automated system... + +Build 1.10.2-12.18.0.2001-1.10.0: + LexManos: 1.10.2 Update + +Build 1.10-12.18.0.2000-1.10.0: + diesieben07: + Fix mob-spawners crashing for non-living entities and simply the patch + in the process (#3042) + +Build 1.10-12.18.0.1999-1.10.0: + mezz: + Fix legacy handling for ItemBucket subclasses and non-universal buckets + (#3038) + mezz: + Fix milk bucket is fillable with water or lava when milk is unregistered + (#3039) + +Build 1.10-12.18.0.1998-1.10.0: + mezz: Remove duplicated universal buckets from the creative list (#3035) + mezz: Fix FluidContainerRegistry handling potions as water bottles (#3037) + +Build 1.10-12.18.0.1997-1.10.0: + cpw: + Big warning for recipe types found without being registered, it turns + out this is pretty severe, modders need to fix it. + +Build 1.10-12.18.0.1996-1.10.0: + mezz: + Fix comparison stability of the Recipe Sorter with unknown recipes #2962 + (#3030) + +Build 1.10-12.18.0.1995-1.10.0: + LexManos: Fixed Husks rendering as standard zombies. Closes #3028 + +Build 1.10-12.18.0.1994-1.10.0: + LexManos: Fixed chests being replaced when trees grew. + +Build 1.10-12.18.0.1993-1.10.0: + luacs1998: Simple implementation of a Open/Close container event (#3017) + +Build 1.10-12.18.0.1991-1.10.0: + LexManos: + Fixed shifted patch in GameSettings causing settings to not load + properly. Closes #3025 #3022 + LexManos: Fixed incorrect variable being sent to doSpecialSpawn. Closes #2986 + LexManos: Fix incorrect logic in ChunkCache.isSideSolid. Closes #3026 + LexManos: Provide 'cleaner' version of TextureMap.setTextureEntry. Closes #1385 + +Build 1.9.4-12.17.0.1990: + LexManos: Fixed incorrect variable being sent to doSpecialSpawn. Closes #2986 + LexManos: Fix incorrect logic in ChunkCache.isSideSolid. Closes #3026 + +Build 1.10-12.18.0.1989-1.10.0: + cpw: Fix doors popping off solid sides. + +Build 1.10-12.18.0.1988-1.10.0: + cpw: Fix that the Missing blocks/items/registries prompt often got stuck. + +Build 1.9.4-12.17.0.1987: + LexManos: + Set ModelLoader.WHITE's texture size iniatlly instead of defaulting to + zero and being set later. + +Build 1.10-12.18.0.1986-1.10.0: + cpw: Fix Realms button text to be shorter again. Closes #3019 + +Build 1.10-12.18.0.1985-1.10.0: + cpw: Fix item pickup dupe bugs. Closes #3015 + +Build 1.10-12.18.0.1984-1.10.0: + blay09: + [1.10] Fix keys with KeyModifier failing to load (#3018) + Fix key options with KeyModifier failing to load due to + NumberFormatException + +Build 1.10-12.18.0.1983-1.10.0: + cpw: + Accept more 1.9.4 version strings. Fix NPE for custom villager types and + their associated zombie spawns. Still needs review. + +Build 1.10-12.18.0.1982-1.10.0: + mezz: Fix all guis closing as soon as they are opened (#3013) + +Build 1.10-12.18.0.1981-1.10.0: + cpw: Update to 1.10 + LexManos: Fix version number. + +Build 1.9.4-12.17.0.1980-1.10.0: + cpw: Fix the MDK - it gets the license too! + +Build 1.9.4-12.17.0.1979-1.10.0: + cpw: + Update the build.gradle script to ship the new license and stop shipping + the old licenses. + +Build 1.9.4-12.17.0.1978-1.10.0: + cpw: + In accordance with our stated goal of relicensing Forge to LGPL v2.1, + this commit enacts that change. Although it is using the 1.9.4 codebase, + it is intended that this branch become public with the 1.10 changes, as + such the license will take effect at that time. The three commits from + persons who have failed to accept the new license, as documented in + #2789, have had their commits reverted. This should complete the license + transition. Commits after the commit date of this commit should be + considered licensed by LGPLv2.1, as indicated in LICENSE-new.txt. All + patches are now considered owned by the Forge project and Forge + Development LLC in particular (note that they will not get the license + boilerplate, as they are machine generated files). + +Build 1.9.4-12.17.0.1976: + GirafiStudios: + Made forge-type spawn eggs spawn childs, when right clicking + EntityAgeable again. (#2982) + +Build 1.9.4-12.17.0.1975: + shadowfacts: Fix broken EntityItem merging for Items with capabilities + diesieben07: + Make ASMDataTable more useful: (#2911) + - EnumHolder now has getters for it's data + - enum arrays work now + - nested annotations work now outside of being in arrays + (cherry picked from commit f10f750) + +Build 1.9.4-12.17.0.1974-1.9.4: + diesieben07: + Make ASMDataTable more useful: (#2911) + - EnumHolder now has getters for it's data + - enum arrays work now + - nested annotations work now outside of being in arrays + +Build 1.9.4-12.17.0.1973: + mezz: Fix incorrect FluidUtil doc (#2996) + +Build 1.9.4-12.17.0.1972: + mezz: Fix ItemStack deserialization can't clear nbt (#3005) + mezz: Improve the "missing mods" on-screen error message (#2997) + +Build 1.9.4-12.17.0.1970: + cpw: Update CONTRIBUTING.md + +Build 1.9.4-12.17.0.1969: + cpw: Update CONTRIBUTING.md + +Build 1.9.4-12.17.0.1968: + mezz: Fix #2918 Make dispensers with buckets work with modded fluids (#2947) + +Build 1.9.4-12.17.0.1967: + LexManos: Fixed brewing stand returning incorrect solts for side inventories. + +Build 1.9.4-12.17.0.1966: + LexManos: Fixed villager career display names being off by one. + +Build 1.9.4-12.17.0.1965: + diesieben07: + Fix DataParameter mixup when vanilla clients are connected causing CCE + in zombie renderer (#2992) + +Build 1.9.4-12.17.0.1964: + williewillus: Fix AnimationItemOverrideList not falling back to super (#2990) + +Build 1.9.4-12.17.0.1963: + mezz: + Fix #2961 Capability data is not preserved by fluid handler interactions + (#2976) + +Build 1.9.4-12.17.0.1962: + cpw: Slight tweak to early loading, to accommodate FMP + +Build 1.9.4-12.17.0.1961: + LexManos: + Fixed Fernflower decompile issue in AnvilChunkLoader.saveExtraData() + Closes #2985 + +Build 1.9.4-12.17.0.1960: + cpw: + Mute the connection reset by peer exception - it's spamilicious for the + most part. + +Build 1.9.4-12.17.0.1959: + cpw: Fix missing IMC message query. + +Build 1.9.4-12.17.0.1958: + man.of.j: Read a Update JSON in UTF-8 (#2978) + +Build 1.9.4-12.17.0.1957: + williewillus: Add getter for the world to LootContext (#2954) + +Build 1.9.4-12.17.0.1956: + gurreja: Fixed arrows not showing in non default AchievementPages (#2968) + +Build 1.9.4-12.17.0.1955: + mezz: Add methods to Fluid to allow custom vaporization overrides (#2959) + +Build 1.9.4-12.17.0.1954: + fry: Fixes #1984. + +Build 1.9.4-12.17.0.1953: + fry: + Modified SimpleModelState to ignore the parts it doesn't know about. + Fixes model part hiding always applying to some models when + transformations are specified in the blockstate json. + +Build 1.9.4-12.17.0.1952: + fry: + Pass the GL context back from the splash screen during the + EntityRenderer init. + +Build 1.9.4-12.17.0.1951: + cpw: + Fire ChunkWatchEvent.Watch event, closes #2767. Based on @sfPlayer1 + patch suggestion. It looks like this logic has shifted relative to 1.8, + so there may be differences in event behaviour now. + +Build 1.9.4-12.17.0.1950: + minecrell: + Fix asynchronous chunk loading (#2946) + Since the update to Minecraft 1.9.4 chunks were actually never loaded + asynchronously because a sync request was always made from the + PlayerChunkMap shortly after the chunk had been queued. + + - PlayerChunkMapEntry now only loads chunks synchronously *after* the + chunk failed to load asynchronously. + - Fixed some minor bugs that caused "Attempted to dequeue chunk" + messages + - Simplified ChunkProviderServer patch. loadChunk no longer generates + chunks, + so there is no need to handle that. + - Moved loader and provider to ChunkIOProvider so there is no need for + "hashCode abuse" + +Build 1.9.4-12.17.0.1949: + mezz: + Make it easier to use FluidTanks that have input/output restrictions + (#2945) + These internal function should NOT be used by anything except the owner + of the tank. + +Build 1.9.4-12.17.0.1948: + LexManos: Fixed BiomeProvider.getModdedBiomeGenerators method name. Closes #2937 + +Build 1.9.4-12.17.0.1947: + williewillus: + Several bugfixes for PlayerInteractEvent (#2943) + * Don't change Result if setCanceled(false) called + + * Fix RightClickEmpty firing even when targeting a block or entity + + * Add a left click empty event + + * Move hook point for EntityInteractSpecific to the right place + + * Fix LeftClickBlock not firing clientside in creative, and clarify docs + about creative + +Build 1.9.4-12.17.0.1946: + mezz: + Add new IFluidHandler for capabilities. (#2942) + Old fluid system is deprecated and slated for removal in the next + cleanup cycle. + +Build 1.9.4-12.17.0.1945: + matti.j.ruohonen: + Add a Slot#isSameInventory() method (#2884) + This fixes shift + double clicking items in Containers that use + SlotItemHandler slots. + +Build 1.9.4-12.17.0.1944: + LexManos: + Fixed POTENTIAL issue where mods would query world infrom from TEs + before they are set. Closes #2863 + +Build 1.9.4-12.17.0.1943: + LexManos: + Fixed client side ticking TileEntites after they are unloaded. Closes + #2852 + LexManos: + Expanded custom villagers to Zombies and world gen. Fixed edge cases + where custom professiosn wernt being used correctly. Closes #2862 + +Build 1.9-12.16.0.1942-1.9: + ljfa-ag: Fix forge:default-tool transformation (#2795) + +Build 1.9.4-12.17.0.1941: + LexManos: Fixed position sent to sanSustainPlant from cactus. Closes #2941 + +Build 1.9.4-12.17.0.1940: + LexManos: + Forge will now warn the user and ask permission to load a world with + unknown registries. Closes #2934 + +Build 1.9.4-12.17.0.1939: + LexManos: Fix BlockFluidBase having collision. Closes #2932 + +Build 1.9.4-12.17.0.1937: + LexManos: + 1.9.4 Update. Major things to note: Class renames: + https://gist.github.com/LexManos/44dd211f90f498ad4015279b103dff86 Tile + Entities are now packed in the ChunkData packet. Forge intends to work + around this to better support large moded worlds, but for the time being + modders should implement the new function carefully and only send what + data they need to! Minecraft's codebase now has annotations, these are + directly from Mojang and should be adheared to! Added support for + package-info.java's containing @Nullable information for all MC code + base. + LexManos: Update mappoings snapshot to 20160518 + cpw: Fix schizophrenia in version numbers. + LexManos: Bump version information for 1.9.4. + LexManos: Update example mod for new mappings. + atomicblom: Add Unit Test to detect mismatches between EnumHelper and Enum ctor + cpw: + Tweak build file slightly - allow passing buildNumber using gradle + parameters (-PbuildNumber=...) and provide a "resetBuildNumber" function + to reset the buildNumber to zero in the ForgeVersion file. Means builds + can be reproducible in-IDE. + tterrag1098: Fix screenshot link paths on Windows (#2886) + LexManos: + Take capabilities into account when comparing ItemStack NBT's. Closes + #2726 + LexManos: + Tipped arrows are now not affected by infinite enchantment but are still + effected by creative mode. + LexManos: Set max enchantment ID to Short.MAX_VALUE. Closes #2799 + LexManos: + Fix Container.compouteStackSize not respecting stack version of + maxStackSize. Closes #2756 + LexManos: Fire playerDestroyItem event's in some cases where we were not. + LexManos: Fix villagers having farmer skin on vanilla servers. Closes #2894 + LexManos: Add alternative ItemAxe Constructor + LexManos: Fix paramters for addArmorMaterial, addOption and addGameType. + LexManos: + Make unit test for EnumHelper more robust and less spammy. Now detects + missing accessors as well. + the.f1repl4ce: Switch new constructor to use floats (#2904) + tterrag1098: Add hook for TE data sync on client (#2893) + cpw: + Strip Optional from the class signature as well, since that's loaded by + the TypeToken registry code and might cause a crash. + LexManos: + Fix installer downloading vanilla jar when not needed. And filter some + more known libraries. + LexManos: + Capture interfaces when scanning classes and preload implementations of + ICrashReportDetail. + LexManos: Set Enchantment table's harvest level. Closes #1349 + LexManos: + More uniformly apply Configuration.caseSensitiveCustomCategories. Closes + #1353 + LexManos: + Close player's inventory to prevent potential dupe issues on some modded + items. Closes #1431 + LexManos: + Move getArmorModel hook up two lines so that the attributes and + animation information is set. Closes #1939 + LexManos: Fire PopulateChunkEvent Pre and Post in ChunkProviderFlat. Closes #2050 + LexManos: Fire LivingSpawnEvents for MobSpawners. Closes #2079 + LexManos: Fix javadocs for BiomeColor events. Closes #2093 + LexManos: + Fixed EntityRegistry.addSpawn adding duplicate spawn entries. Closes + #2112 + LexManos: + Fix setTileEntity causing the world to remove the new and old tile + entities. Closes #2164 + LexManos: Add ServerHangWatchdog to TerminalTransformer whitelist. Closes #2203 + LexManos: Fixed NBTTagString.toString not properly escaping \'s. Closes #2393 + LexManos: + Reinitalize statistics information on Mapping changes. Fixes mismatched + stats to item/block ids. And auto registers stats for modded items. + Closes #2454 + LexManos: + Fix Thorns enchantment bypassing ISpecialArmor.damageArmor function. + Closes #2463 + LexManos: + Fix tooltip for survival tab in the creative menu not drawing on any but + the first page. Closes #2908 and #2504 + LexManos: + Make sure tool-classes for vanilla tools are initialized early. Closes + #2909 and #2525 + LexManos: + Fixed FluidUtil.tryEmptyFluidContainerItem not checking if the tank can + accept fluids first. Closes #2527 + LexManos: + Fixed potential issue with Chunk.getLightOpacity being called before the + chunk is added to the world map. Closes #2529 + LexManos: + Fixed TileEntityBeacon not using position-aware getLightOpacity. Closes + #2530 and #2910 + LexManos: Fixed village wells not having their biomes set. Closes #2499 + LexManos: + Fixed issue with @ObjectHolder and the new registry system. Closes #2640 + Only run static initalizers for classes we need to get the names from + values. + LexManos: + Fixed new ICrashReportDetail loader working with packaged mods by + delaying it until the ModContainer's construct event. Closes #2924 + fry: Reordered transformations during LayerHeldItem rendering, fixes #2827. + fry: + Initial support for model visibility system. Implemented it for OBJ, B3D + and normal vanilla models; fixed NPE accessing parent state in B3DModel. + Fixes #2801. + +Build 1.9.4-12.17.0.1935-1.9.4: + fry: Initial support for model visibility system. Implemented it for OBJ, B3D and normal vanilla models; fixed NPE accessing parent state in B3DModel. Fixes #2801. + +Build 1.9-12.16.1.1934: + mezz: + Improve JavaDoc links, fix some broken JavaDocs (#2833) + + Improve JavaDoc links, fix broken JavaDocs + +Build 1.9.4-12.17.0.1933-1.9.4: + fry: Reordered transformations during LayerHeldItem rendering, fixes #2827. + +Build 1.9.4-12.17.0.1932-1.9.4: + LexManos: Fixed new ICrashReportDetail loader working with packaged mods by delaying it until the ModContainer's construct event. Closes #2924 + +Build 1.9.4-12.17.0.1931-1.9.4: + LexManos: Fixed village wells not having their biomes set. Closes #2499 + LexManos: + Fixed issue with @ObjectHolder and the new registry system. Closes #2640 + Only run static initalizers for classes we need to get the names from values. + +Build 1.9.4-12.17.0.1930-1.9.4: + LexManos: Fix tooltip for survival tab in the creative menu not drawing on any but the first page. Closes #2908 and #2504 + LexManos: Make sure tool-classes for vanilla tools are initialized early. Closes #2909 and #2525 + LexManos: Fixed FluidUtil.tryEmptyFluidContainerItem not checking if the tank can accept fluids first. Closes #2527 + LexManos: Fixed potential issue with Chunk.getLightOpacity being called before the chunk is added to the world map. Closes #2529 + LexManos: Fixed TileEntityBeacon not using position-aware getLightOpacity. Closes #2530 and #2910 + +Build 1.9.4-12.17.0.1929-1.9.4: + LexManos: Fix Thorns enchantment bypassing ISpecialArmor.damageArmor function. Closes #2463 + +Build 1.9.4-12.17.0.1928-1.9.4: + LexManos: Fixed NBTTagString.toString not properly escaping \'s. Closes #2393 + LexManos: + Reinitalize statistics information on Mapping changes. + Fixes mismatched stats to item/block ids. And auto registers stats for modded items. + Closes #2454 + +Build 1.9.4-12.17.0.1927-1.9.4: + LexManos: Fire LivingSpawnEvents for MobSpawners. Closes #2079 + LexManos: Fix javadocs for BiomeColor events. Closes #2093 + LexManos: Fixed EntityRegistry.addSpawn adding duplicate spawn entries. Closes #2112 + LexManos: Fix setTileEntity causing the world to remove the new and old tile entities. Closes #2164 + LexManos: Add ServerHangWatchdog to TerminalTransformer whitelist. Closes #2203 + +Build 1.9.4-12.17.0.1926-1.9.4: + LexManos: Set Enchantment table's harvest level. Closes #1349 + LexManos: More uniformly apply Configuration.caseSensitiveCustomCategories. Closes #1353 + LexManos: Close player's inventory to prevent potential dupe issues on some modded items. Closes #1431 + LexManos: Move getArmorModel hook up two lines so that the attributes and animation information is set. Closes #1939 + LexManos: Fire PopulateChunkEvent Pre and Post in ChunkProviderFlat. Closes #2050 + +Build 1.9.4-12.17.0.1925-1.9.4: + LexManos: Fix installer downloading vanilla jar when not needed. And filter some more known libraries. + LexManos: Capture interfaces when scanning classes and preload implementations of ICrashReportDetail. + +Build 1.9.4-12.17.0.1924-1.9.4: + cpw: Strip Optional from the class signature as well, since that's loaded by the TypeToken registry code and might cause a crash. + +Build 1.9-12.16.1.1923: + shadowfacts: Pass the correct position into isSideSolid in BlockRailBase#canPlaceBlockAt (#2919) + +Build 1.9.4-12.17.0.1922-1.9.4: + tterrag1098: Add hook for TE data sync on client (#2893) + +Build 1.9.4-12.17.0.1921-1.9.4: + the.f1repl4ce: Switch new constructor to use floats (#2904) + +Build 1.9.4-12.17.0.1920-1.9.4: + atomicblom: Add Unit Test to detect mismatches between EnumHelper and Enum ctor + LexManos: Fix paramters for addArmorMaterial, addOption and addGameType. + LexManos: Make unit test for EnumHelper more robust and less spammy. Now detects missing accessors as well. + +Build 1.9.4-12.17.0.1918-1.9.4: + LexManos: Add alternative ItemAxe Constructor + +Build 1.9.4-12.17.0.1917-1.9.4: + LexManos: Fix villagers having farmer skin on vanilla servers. Closes #2894 + +Build 1.9.4-12.17.0.1916-1.9.4: + LexManos: Fire playerDestroyItem event's in some cases where we were not. + +Build 1.9.4-12.17.0.1915-1.9.4: + LexManos: Fix Container.compouteStackSize not respecting stack version of maxStackSize. Closes #2756 + +Build 1.9.4-12.17.0.1914-1.9.4: + LexManos: Set max enchantment ID to Short.MAX_VALUE. Closes #2799 + +Build 1.9.4-12.17.0.1913-1.9.4: + LexManos: Tipped arrows are now not affected by infinite enchantment but are still effected by creative mode. + +Build 1.9.4-12.17.0.1912-1.9.4: + tterrag1098: Fix screenshot link paths on Windows (#2886) + LexManos: Take capabilities into account when comparing ItemStack NBT's. Closes #2726 + +Build 1.9.4-12.17.0.1910-1.9.4: + cpw: Tweak build file slightly - allow passing buildNumber using gradle parameters (-PbuildNumber=...) and provide a "resetBuildNumber" function to reset the buildNumber to zero in the ForgeVersion file. Means builds can be reproducible in-IDE. + +Build 1.9.4-12.17.0.1909-1.9.4: + LexManos: Update example mod for new mappings. + +Build 1.9-12.16.1.1907: + bonii-xx: + Fix Bucket rendering and add sound (#2865) + + * Adjust generated quads from texture to take texture size into account #2858 + + * Fix universal bucket not passing through when rightclicking on a non-block + Add proper sound events when picking up modded fluids #2821 + + * Have FluidUtil execute properly on both sides and sync as expected. Add default sounds to interacting with tanks + + * Save sound for filling/emptying in the fluid + +Build 1.9-12.16.1.1906: + LexManos: Lets just simply this. Fixes last commit. + +Build 1.9-12.16.1.1905: + LexManos: Add modder facing API for Villager Career level trades. Ref: #2854 + +Build 1.9-12.16.1.1904: + cpw: Fix up release jsons to clean up extraneous netty references + fry: Extended Animation State Machine format to allow multiple transitions from one state. + +Build 1.8.9-11.15.1.1902-1.8.9: + cpw: Fix up release jsons to clean up extraneous netty references + +Build 1.9-12.16.1.1901: + cpw: Fix up release jsons to clean up extraneous netty references + +Build 1.9-12.16.1.1900: + LexManos: Make LootPool constructor public again. Closes #2847 + +Build 1.9-12.16.1.1899: + LexManos: Fix type in LootEntry json name. And rename LootTable.finalize to freeze to avoid overriding Object function. Closes #2846 and #2847 + +Build 1.9-12.16.1.1898: + fry: Fixed joint animation application correctly. + +Build 1.9-12.16.1.1897: + shadowfacts: + Add ScreenshotEvent (#2828) + + Add ScreenshotEvent + +Build 1.9-12.16.1.1896: + LexManos: + New LootTable interaction system and event. + Modders can now modify and reference internal elements of a loot table by name. + Editing can ONLY be done in the event and any external editing will cause a exception to be thrown. + See this gist for more information: https://gist.github.com/LexManos/77c983d67b9ad27010428478b66d50fd + +Build 1.9-12.16.1.1895: + fry: Fixed joint hierarchy not being used fully in the animation system. + +Build 1.9-12.16.1.1894: + LexManos: Fixed issue in ChunkIO that would potentially cause NPEs on chunks. Closes #2837 + +Build 1.9-12.16.1.1893: + LexManos: Fixed map extension recipie. + +Build 1.9-12.16.1.1892: + mezz: Fix the rand given to PopulateChunkEvent (#2834) + +Build 1.9-12.16.1.1891: + LexManos: Fix areas where dimension types are used as dimension IDs. + +Build 1.9-12.16.1.1889: + LexManos: Add NPE protection to in-hand item rendering. + +Build 1.9-12.16.1.1888: + mattmess1221: + Fix url regex (#2815) + + Fixed url detection in chat messages. Stops false positives such as `um.....no` + +Build 1.9-12.16.1.1887: + LexManos: Slightly better practice because wait can be randomly interupted. + LexManos: Bump version for new RB. + +Build 1.9-12.16.0.1886: + cpw: Don't ignore rejects + cpw: Add in mcp named patches and use them. Initial 1.9 setup. + cpw: Add rejects with mcp names for application to main codebase. Let's roll? + cpw: First few patches applied + LexManos: net.minecraft.block.* patches + LexManos: util, tileentity, stats, realms. Potions got an overhaul and out registry will need to be adapted. + LexManos: Some import renames and compile error fixes, killed ~800. + fry: Updated various block model patches. + fry: A bunch of rendering rejects updated. + fry: RendererLivingEntity, RenderEntityItem, RenderItem, RenderManager, LayerArmorBase; Item.getModel + ISmartItemModel are now inside ItemOverrideList; fix class rename in TESR patch. + fry: EntityRenderer, most of RenderGlobal, minor fix to LayerBipedArmor. + fry: tabs -> spaces. + fry: FontRenderer + fry: Fixed most errors in the model stuff, except for ModelLoader and b3d and obj getQuads/handleBlockState methods. + LexManos: Some entity patches. + CovertJaguar: Fix broken patches for EntityMinecart + LexManos: Items done, <1000 errors whoot! + LexManos: Small renames before bed. + fry: GuiCreateWorld, GuiSlot, GuiUtilRenderComponents, GuiContainerCreative + fry: GuiOverlayDebug, ItemModelMesher, RenderManager, Stitcher fixed + minor fixes in forge gui classes. + fry: removed Item.getModel, functionality is now achieveable via ItemOverrides. + fry: Updated raw types in ExtendedBlockState, fixed some ATs, updated some things that needed updating in model classes. + fry: Chunk + cpw: + DedicatedServer + IntegratedServer + Adubbz: + Updated the biome dictionary + + Squashed commits: + + [4064de6] Updated the biome dictionary + LexManos: Enchantments, some world, Biomes, bucks, world/gen/features. + Adubbz: Updated BiomeManager to 1.9 + LexManos: Delete reject files i missed + LexManos: More work on misc things. + LexManos: World Patches work. + fry: Fix various errors in text mods. + fry: Fixed B3D loader, fixed some obvious errors in ModelLoader. + cpw: + LanguageManager + NetHandlerPlayClient + fry: ModelBox, PositionTextureVertex, TexturedQuad. Does anyone really use those on the server? + cpw: + ServerPinger + PlayerList + cpw: + WorldServer: NOTE - ChestGenHooks has NOT been updated in accordance with plans for removing it + GuiStats + Fixup deletion of egg handling in entity registry? + fry: Removed generics from IModel subinterfaces, add ed ModelProcessingHelper instead. + fry: Model UV lock handling from the state to the model, fixed most compile errors in ModelLoader, disabled it (and ModelBakeEvent) until it's functional, fixed some errors in ForgeHooksClient. + fry: Made OBJModel.java compile. + LexManos: Fixed errrors in Fluids package. TODO: Make BlockLiquid implement IFluidBlock and REMOVE FluidContainerRegsitry. Everything *should* be able to use IFluidContainer directly. + LexManos: Fishing is now a loot table no more need for FishingHooks. {LootTables still need to be evaludated if they need extra hooks, but thats later} Goodbye 44 compile errors! + LexManos: Temporary hack to fix MCP mappings for param names we are using that is causing compile errors. + LexManos: NetworkDispatcher/FMLProxyPacket 41 more errors cleaned. + cpw: Some fixups for FML, and use the FML registry for potions + cpw: Some more FML related fixups + cpw: Fix up import in Potion + cpw: Some client handler cleanup + cpw: Remove two patches that aren't needed anymore + cpw: Command fixups + cpw: Few more compile fixups + LexManos: More patch work, client patches. + LexManos: + 10 more rejects down. + 98 errors 6 rejects left. + fry: World + fry: Most of ItemInWorldManager reject, various small error fixes. + cpw: Some more forge code fixes + cpw: + Another compilation fix + More patch tweaks for compilation errors. onItemUseTick takes an entity now, cos skellies use stuff too + cpw: More fixups, removing chestgenstuff aggressively. Use loot tables. Any missing ones WILL be added by Mojang. + cpw: Remove more chestgenhooks stuff. Clean up some more ATs + cpw: Potion cleanup. Moar fixes! + cpw: Finish world, chunkloading should work again? + cpw: Another AT, for the player + cpw: Fix up PlayerSP for the AT + LexManos: Interaction hooks need to be re-added but compiles {Doesn't run} + LexManos: + Added bypass functions to Defaulted registry, DO NOT USE THIS MODDERS FORGE INTERNAL ONLY. + And some other fixups for running. + LexManos: Bump version info. Rather important. + LexManos: Fixed position being shifted before being sent to shouldSideBeRendered. + fry: Fix perspective transformations for left-handed items, disable ModelAnimationDebug until model loading is fixed. + cpw: Fix race condition between server ticks and the netlogin code handshaking for FML + cpw: Move the patch into the fml override handler, for less patch + fry: Fix items rendering too low in first person. + fry: Fixed (hopefully) perspective transformations for custom models too. + cpw: Capture Biome Registry within FML + fry: Fixed emply hand not rendering in first person. + fry: Fixed incorrect rendering state caused by transparent rendering pass for entities. + fry: Fixed armor rendering + cpw: Switch to srg patches + fry: Updated to latest mappings. Exc is broken, some anonymous classes didn't map to srg names. + fry: Fixed some errors in forge.exc + fry: First version of updated of ModelLoader, mostly works. + fry: Big model loader refactoring: simplified a lot of things, broke some error reporting. Still generally works. + LexManos: Update patches for fixed inner class suffeling in srg files. + LexManos: We are based on 1.9 not 1.8.9 :D + LexManos: Delete mcp patches. + LexManos: PlayerManager updated. + LexManos: Fix digging blocks in survival. + LexManos: Fixed breaking of tall grass. It now uses fortune. Expanded grass seed hooks to allow Fortune. Potentially removing in future in favor of LootTables. + vazkii: + 1.9: Fixed registering armor materials through EnumHelper exploding + + 1.9 ArmorMaterial now requires a SoundEvent for the equip sound. + fry: Fixed model error reporting, fixed model errors in test mods that shouldn't happen, fixed custom texture loading, made more things private/final. + fry: Fixed incorrect rotations for items in the left hand. Closes #2548. + fry: Fixed incorrect culling of mod TESRs. + fry: Fixed EffectRenderer patch, closes #2547. + fry: Removed imports in patches. + fry: Fixed progress reporting for model loading. + fry: Javadocs, small cleanup. + LexManos: Remove our entity position fixer. Vanilla fixed the bug in 1.9. + LexManos: Fix vanilla bug where bows consumed tipped arrows in creative. + LexManos: Fixed onUseStop being called twice {Bows firing twice} + LexManos: Fixed Sand not falling. + LexManos: Fixed NPE when sneak using a item. + Adubbz: BlockColors and ItemColors no longer assume non-Vanilla id constancy. Added a getter for ItemColors. + fry: Fixed MultiLayerModel not getting correct submodels; Unified the gui lighting of normal and custom models - diffuse lighting is now done in the pipeline, no need for IColoredBakedQuad anymore. + fry: Fixed quads that don't need diffuse lighting getting it anyway. + LexManos: Fix AT lines. + fry: Fixed invalid index calculation in BakedQuadRetextured. + fry: Fixed Block.doesSideBlockRendering, closes #2564. + fry: Fixed outline shader rendering, closes #2560. + fry: Fixed sprite not being passed to the quad builder for custom models. + cordonfreeman: Fix for patch targetting the wrong field to change for failed pathfinding penalty + iTitus: + Fix the EntityPlayer patch + + In 1.8.9 the call goes to getDisplayNameString() so that any changes from the PlayerEvent.NameFormat event are being take into account. + In this patch the call goes to func_70005_c_() which is the getter for the GameProfile name. + I changed it back. + + Sorry if you do not want to accept it because it is a one-liner. + vincent.lee: Fix #2555 + diesieben07: Fix broken patch in EntityPlayer.updateRidden + blay09: + Fix KeyInputEvent only being fired if Keyboard.getEventKeyState() is false. + + It used to be called for both key-up and key-down states prior to 1.9, so I assume Vanilla's changes to F3 behavior broke the patch. + matthewprenger: Pass exceptions thrown in mod event buses back to FML to handle apropriately + vincent.lee: Fix double dropping of items. Closes #2549 + cpw: Ignore classes directory + cpw: Fix bucket test + diesieben07: Fix EntityList.func_188429_b not supporting mod-entities, fixes spawn eggs, fixes #2581 + CovertJaguar: Fix #2601 Minecart infinite acceleration + gigaherz: Fix a condition that caused the enchantment table to roll invalid enchantments. + fry: Switched animation system to capabilities, added animated item example, fixed state passing in MultiModel. + fry: Separated model classes to client and common packages. + fry: instance -> INSTANCE + vincent.lee: Expose IItemHandler on vanilla entities + fry: Implemented slightly more generic version of UVLock, re-enabled it for json models. Closes #2607. + fry: Removed blockCenterToCorner from TRSRTransformation constructor. Closes #2461. + fry: Ignore blocks/items with null registry name during model loading. Fixes NPE during resource reloading in worlds with removed blocks/items. + fry: Made VertexBuffer.sortVertexData cleanup pointers after it's done. Closes #2528. + fry: Added default left hand transforms for forge transform strings. Closes #2615. + elpatricimo: + Allow players sized smaller than 1 block to walk into small spaces + + Same as #2605 but for 1.9 branch + LexManos: Rework DimensionManager for new DimensionType enum, replaces the old provider registry. Also fixed save folder issues with dimensions. Closes #2570 + LexManos: Fix Chests not opening correctly with semi-solid blocks on top. + LexManos: Fixed Item.shouldCauseReequipAnimation hook. + LexManos: Add ShieldDecoration and Tipped arrows to recipe sorter. Closes #2613 + LexManos: Exclude jna from termal tansformer. + vincent.lee: Update according to suggestions + LexManos: Fix pushing players inside blocks. + LexManos: Make RenderLivingBase.add/remvoeLayer, Closes #2573 + LexManos: Added support for custom dyes with Banners. Closes #2596 + LexManos: Allow finite fluids to be drained correctly + LexManos: Make OreDictionary.initVanillaEntries() private so that dumb modders will stop calling it. + vincent.lee: Actually fix dupe drop + LexManos: Fix swap animations for sure this time. + fry: Added Capability.cast, to allow avoiding unchecked casts in ICapabilityProvider.getCapability + LexManos: Update FML Entity Spawn packet for 1.9's location change. Closes #2567 + LexManos: Fixed custom entities unique ids. + LexManos: Fix typo causing biomes to be generated in wrong chunks. Closes #2632 + fry: Show meaningful error if ModelLoaderRegistry is used before the missing model is initialized. + fry: Register the animation Capability. No idea how it worked before at some point. + iTitus: + Add flashing update notification icon made by @gigaherz, closes #2582 + + It is added to the "Mods" button in the main menu and to out-of-date mods in the mod list (there it replaces the "U"). + Also fixes a little typo. + diesieben07: Fix BlockCrops.getDrops not respecting new age methods (for beetroots) + diesieben07: Fix PopulateChunkEvent.Post not firing + LexManos: + New Builder class in BlockStateContainer. Makes building containers with both listed and unlisted properties cleaner. + Make all methods of BiomeGenBase$BiomeProperties public so that modders can use that class outside subclasses. + fry: Cleanup: removed IEEP, removed redundant casts, fixed imports, fixed typos. + fry: Fixed isSideSolid causing infinite loops due to the call to getActualState. + fry: Removed LanguageRegistry and CollectionWrapperFactory. + fry: Removed RenderWorldEvent, encapsulated all public event fields. + fry: Made some more public fields either private or final. + fry: Disabled erroring block, fixed DynBucketTest.TestItem model. + mezz: + Make tooltips layout in the right direction, wrap if there is no room + + Same as #2649, but for Minecraft 1.9 + fry: Fixed diffuse lighting not being applied if forge lighting pipeline is disabled, closes #2651 + fry: Enabled diffuse lighting by default in UnpackedBakedQuad.Builder. + fry: Fixed crosshair always being white, closes #2653. + kashike: + Replace Forge's `BlockPos#getImmutable` method with the included `BlockPos#toImmutable` (func_185334_h), while keeping the override in PooledMutableBlockPos to prevent mutable leaks. + Also prevent a mutable blockpos leak in World#setTileEntity + gigaherz: Add wrapper methods for IStorage#readNBT/writeNBT. + mezz: Fix Block.getPickBlock returning an ItemStack with a null Item + fry: Prevent missing model from loading multiple times. + fry: Fixed StackOverflow caused by the previous commit, closes #2669. + LexManos: Fix EntityPlayer still running old armor logic. Closes #2670 + LexManos: Fix shrubs not generating correctly. Closes #2663 + LexManos: Fix bows not animating properly when picking up ammo while using. Closes #2672 + LexManos: Make NoteBlockEvent raw constructor protected to allow subclasses. Closes #2153 + LexManos: Fix landing particles not showing up. Cloes #2661 + shadowfacts: Forward ItemBlock#addInformation to Block#addInformation + tterrag1098: Add state param to canRenderInLayer + hea3venmc: Fix remapped blocks being overriden with dummy air blocks. Closes #2491 + cpw: + Squashed commit of the following: + + commit b3b290aec9d3010a134859da6001ea28a96c2fdc + Merge: c6ce6a0 d803f7d + Author: cpw + Date: Fri Mar 25 13:28:04 2016 -0400 + + Merge branch 'RegistryRework' of https://github.com/LexManos/MinecraftForge into LexManos-RegistryRework + + Implement proper registry slaves. Should help with rollback related issues. + + Missing patch + + commit d803f7db76f65db9d27302c9804a643bc853dc22 + Author: LexManos + Date: Tue Mar 22 03:36:14 2016 -0700 + + Update VillagerRegistry and use it. Should in theory make custom villagers work now. Using string version instead of int id for networking. + + commit eb5e5b4b42fdca26d2a104e4dc1e6a3ea3051a7b + Author: LexManos + Date: Tue Mar 22 02:14:16 2016 -0700 + + More cleanup. + + commit edbc56b2ff314629d0e402709f3cf29fc79c4a3d + Author: LexManos + Date: Tue Mar 22 02:05:23 2016 -0700 + + More cleanups, removed deprecated UniqueIdentifier {ResourceLocation now} + + commit e2df8d1be3c97601508f83dc97b0e8853fa1e271 + Author: LexManos + Date: Tue Mar 22 01:29:19 2016 -0700 + + Stupid generics.... + + commit 46d57dc4677fa5ff3923e64eaccfb33d7e5aad8d + Author: LexManos + Date: Tue Mar 22 01:00:25 2016 -0700 + + Some registry tweaking to provde a non-complicated API modders can use. + cpw: Reconcile Block.patch + cpw: + Add registries for soundevents, enchantments and potiontypes + MinecraftForge-2576 [1.9] SoundEvents (and Enchantments and PotionTypes) need a FML registry + cpw: MinecraftForge-2683 InvocationTargetException for Forge 1820 for 1.9 + cpw: MinecraftForge-2684 [1.9] New Registry ignores keys + fry: Improved UV offset hackery - should fix most visible custom model seams. + cpw: Support ResLocations for IMC + cpw: Capture a vanilla freeze - will be used when FML connects to vanilla servers, soon + LexManos: Fixed compile error in registry code with Eclipse. + mezz: + Add key binding modifiers and contexts. + + Same as #2674, but for Minecraft 1.9 + Adubbz: Fixed mismatch registry names and mod ids + LexManos: Properly deprecate and link the replacement methods in GameRegistry. Add helper method for registering a block with default ItemBlock because people keep complaining -.- + fry: Changed generic signature of GameRegistry.register methods to work around the type inference bug; updated all example mods to the new block/item registration method. + fry: + Revert "Add key binding modifiers and contexts.", until it's fixed. + + This reverts commit 34c3af7e853d578c8e17e1f0cdf886251fad74ae. + mezz: Re-Add key binding modifiers and contexts. + mezz: Fix inability to attack while holding modifier keys + mcjty1: + Added DimensionManager.createProviderFor() to WorldClient constructor similar to what is done + in WorldServer to make sure the correct provider is created client-side too. + AEnterprise: onBlockHarvested is no longer called twice + fry: Added the ability to change the printed model error count; Added printing of actual exceptions causing missing variants related to blockstate loading, closes #2689. + fry: Made both exceptions occuring during item model loading print in the log; closes #2696. + LexManos: Fix issue caused by setting spawnRadius to 0. Closes #2624 + LexManos: Fixed EntityJoinWorldEvent not being fired for some entitites on Server Worlds. Closes #2685 + LexManos: Fix improper logic in ItemHandlerHelper.giveItemToPlayer causing some items to not be added. Closes #2705 + mezz: + Add modifier support to vanilla keybindings. + + Add Orange conflict color for modifier/key conflicts + (like Ctrl and Ctrl-Z conflicting) + Related to #2692 + vincent.lee: Player Interact Event + Zaggy1024: Fixed using PlaySoundEvent to replace a sound with a PositionedSound causing an NPE due to the Sound field not being set by a call to ISound.createAccessor(SoundHandler). + fry: Fixed mod languages not being loaded on the server. + fry: Fixed some test mods not being marked as client-only. + iTitus: Fix dynbucket item transformation. + fry: Fixed zip being closed too early in the server language loading. + fry: Fixed forge fluid having a collision box. + kat.swales: Corrected CapabilityItemHandler.readNBT ignoring anything in slot 0 in 1.9 + mezz: Fix #2717 Pick block hotkey not working in inventories + mezz: Fix some plain keybinds not working when a modifier is active + LexManos: Enhance some error logging related to OBJLoader issues, and RegistryEntries. + LexManos: + Cleanup OBJLoader parse function and fix issues related to JVM differences. + Also fix support for sopme of the spec that was partially respected. + LexManos: Fixed NPE in dedicated server languages. And fixed logger for main FML event bus. + fry: Made forge fluids use smooth lighting. + kashike: + Remove @SideOnly(Side.CLIENT) from BossInfo/BossInfoServer methods + + These methods can also be used by the server (see BossInfoServer, it sends packets to the client but the methods are @SideOnly(Side.CLIENT)) + LexManos: Fix potential desync between Forge's Villager profession and vanilla's int based system. + LexManos: Fix being kicked from server when climbing ladders. + matti.j.ruohonen: Fix ForgeChunkManager world unloading check (#2736) + mezz: + Add cancelable event for Potions shifting the gui position (#2667) + + Add cancelable event for Potions shifting the gui position + matthewprenger: Don't use import static with net.minecraft classes. Using the latest MCP snapshots this causes an import conflict. (#2742) + CrafterKina: make WorldSavedData implement NBTSerializable (#2745) + mezz: Fix log spam from invalid key modifiers (#2746) + LexManos: Expose a central place to access all of Vanilla and Forge's registries using the new registry API. + iTitus: + Fix forge:default-block transformation. (#2760) + + The first-person left-hand rotation was a little bit of. + vincent.lee: + Boss bar render event (#2701) + + Allow control over increment height + LexManos: Fix NPE on shield break. Closes #2786 + cpw: Add the new license text. Not yet applicable to forge. + cpw: + Update LICENSE-new.txt + + Clarification on infectivity + cpw: + Update LICENSE-new.txt + + Words + cpw: + Update LICENSE-new.txt + + Better words + mezz: Close #2780 add CMD localization for Mac key bindings (#2792) + bonii-xx: + Fix SidedInvWrapper accessing wrong slots for setStackInSlot. (#2797) + + Fix DoubleChestItemHandler not implementing IItemHandlerModifiable + LexManos: Fix sluggish scrolling on GuiScrollList's and fix small rendering issue with scroll bar on certian screen sizes. + bloodmc: + Only run block physics for TileEntities while capturing block placement. (#2803) + + Currently, all blocks placed by players that are not TE's run physics + twice. Blocks that contain a TileEntity are not affected due to a check in + 'ForgeHooks.onPlaceItemIntoWorld'. + + In order to fix the problem, 'Chunk.setBlockState' will now verify if + blocks are being captured before running onBlockAdded and if so, only run + physics if the block has a tileentity. This check also prevents blocks such + as TNT's from running its physics (explosion) when event is cancelled. + williewillus: Add Potion.renderHUDEffect (#2798) + bloodmc: + Call markDirty when restoring blocks with TileEntities. (#2809) + + This change makes sure the updated tileentity is saved properly within the + chunk. + AlexIIL: Fix TextureMap failing when registering a sprite's resource location twice (#2785) + fry: Fixed custom fluid sufraces not rendering from the bottom. Closes #2800. + fry: Make ChunkRenderDispatcher.countRenderBuilders configurable. Closes #2775. + fry: Fixed cooldown overlay sometimes rendering opaque. Closes #2772. + fry: Fixed villager profession not being set correctly on the client, and fixed custom village texture rendering. Closes #2766. + LexManos: Fix withers breaking bedrock. Closes #2813 + LexManos: + Add a java version detection and nag system for users on Java 7 or below. + Added detection of mods that rely on Java 8 and a graceful error screen. + The nag screen will be shown once a day. It can be disabled by editing the forge.cfg. + However it is HIGHLY recomended that user update to Java 8. + LexManos: Remove usage of AsynchronousExecutor library in favor or a simpler implementation. + cpw: Merge in a fix from 1.8.9 for rails + +Build 1.9-12.16.0.1885-1.9: + LexManos: Remove usage of AsynchronousExecutor library in favor or a simpler implementation. + +Build 1.9-12.16.0.1884-1.9: + LexManos: + Add a java version detection and nag system for users on Java 7 or below. + Added detection of mods that rely on Java 8 and a graceful error screen. + The nag screen will be shown once a day. It can be disabled by editing the forge.cfg. + However it is HIGHLY recomended that user update to Java 8. + +Build 1.9-12.16.0.1883-1.9: + LexManos: Fix withers breaking bedrock. Closes #2813 + +Build 1.9-12.16.0.1882-1.9: + fry: Fixed villager profession not being set correctly on the client, and fixed custom village texture rendering. Closes #2766. + +Build 1.9-12.16.0.1881-1.9: + fry: Fixed cooldown overlay sometimes rendering opaque. Closes #2772. + +Build 1.9-12.16.0.1880-1.9: + fry: Make ChunkRenderDispatcher.countRenderBuilders configurable. Closes #2775. + +Build 1.9-12.16.0.1879-1.9: + fry: Fixed custom fluid sufraces not rendering from the bottom. Closes #2800. + +Build 1.9-12.16.0.1878-1.9: + AlexIIL: Fix TextureMap failing when registering a sprite's resource location twice (#2785) + +Build 1.9-12.16.0.1877-1.9: + bloodmc: + Call markDirty when restoring blocks with TileEntities. (#2809) + + This change makes sure the updated tileentity is saved properly within the + chunk. + +Build 1.8.9-11.15.1.1875: + bloodmc: + Call markDirty when restoring blocks with TileEntities. (#2807) + + This change makes sure the updated tileentity is saved properly within the + chunk. + +Build 1.9-12.16.0.1874-1.9: + williewillus: Add Potion.renderHUDEffect (#2798) + +Build 1.8.9-11.15.1.1873: + bloodmc: Fix wrong blockstate being passed to notifyNeighborsRespectDebug. (#2806) + +Build 1.8.9-11.15.1.1872: + bloodmc: + Only run block physics for TileEntities while capturing block placement. (#2805) + + Currently, all blocks placed by players that are not TE's run physics + twice. Blocks that contain a TileEntity are not affected due to a check in + 'ForgeHooks.onPlaceItemIntoWorld'. + + In order to fix the problem, 'Chunk.setBlockState' will now verify if + blocks are being captured before running onBlockAdded and if so, only run + physics if the block has a tileentity. This check also prevents blocks + such as TNT's from running its physics (explosion) when placement event is + cancelled. + +Build 1.9-12.16.0.1871-1.9: + bloodmc: + Only run block physics for TileEntities while capturing block placement. (#2803) + + Currently, all blocks placed by players that are not TE's run physics + twice. Blocks that contain a TileEntity are not affected due to a check in + 'ForgeHooks.onPlaceItemIntoWorld'. + + In order to fix the problem, 'Chunk.setBlockState' will now verify if + blocks are being captured before running onBlockAdded and if so, only run + physics if the block has a tileentity. This check also prevents blocks such + as TNT's from running its physics (explosion) when event is cancelled. + +Build 1.9-12.16.0.1870-1.9: + LexManos: Fix sluggish scrolling on GuiScrollList's and fix small rendering issue with scroll bar on certian screen sizes. + +Build 1.9-12.16.0.1869-1.9: + bonii-xx: + Fix SidedInvWrapper accessing wrong slots for setStackInSlot. (#2797) + + Fix DoubleChestItemHandler not implementing IItemHandlerModifiable + +Build 1.9-12.16.0.1868-1.9: + cpw: + Update LICENSE-new.txt + + Clarification on infectivity + cpw: + Update LICENSE-new.txt + + Words + cpw: + Update LICENSE-new.txt + + Better words + mezz: Close #2780 add CMD localization for Mac key bindings (#2792) + +Build 1.9-12.16.0.1867-1.9: + cpw: Add the new license text. Not yet applicable to forge. + +Build 1.9-12.16.0.1866-1.9: + LexManos: Fix NPE on shield break. Closes #2786 + +Build 1.9-12.16.0.1865-1.9: + vincent.lee: + Boss bar render event (#2701) + + Allow control over increment height + +Build 1.9-12.16.0.1864-1.9: + izooDee5: + Fix forge:default-block transformation. (#2760) + + The first-person left-hand rotation was a little bit of. + +Build 1.9-12.16.0.1863-1.9: + LexManos: Expose a central place to access all of Vanilla and Forge's registries using the new registry API. + +Build 1.9-12.16.0.1862-1.9: + LexManos: Fix log spam from invalid key modifiers (#2746) + +Build 1.9-12.16.0.1861-1.9: + LexManos: make WorldSavedData implement NBTSerializable (#2745) + +Build 1.9-12.16.0.1860-1.9: + LexManos: Don't use import static with net.minecraft classes. Using the latest MCP snapshots this causes an import conflict. (#2742) + +Build 1.9-12.16.0.1859-1.9: + LexManos: + Add cancelable event for Potions shifting the gui position (#2667) + + Add cancelable event for Potions shifting the gui position + +Build 1.9-12.16.0.1858-1.9: + LexManos: Fix ForgeChunkManager world unloading check (#2736) + +Build 1.9-12.16.0.1857-1.9: + LexManos: Fix being kicked from server when climbing ladders. + +Build 1.9-12.16.0.1856-1.9: + LexManos: Fix potential desync between Forge's Villager profession and vanilla's int based system. + +Build 1.8.9-11.15.1.1855: + LexManos: + Update ore dictionary (#2721) + + Updated the Ore Dictionary with more vanilla items: + -Prismarine Shard ( "gemPrismarine" ) + -Prismarine Crystals ( "dustPrismarine" ) + -Prismarine Block ( "blockPrismarine" ) + -Prismarine Brick ( "blockPrismarineBrick" ) + -Dark Prismarine ( "blockDarkPrismarine" ) + -Nether Wart ( "cropNetherWart" ) + -Sugarcane ( "sugarcane" ) + -Paper ( "paper" ) + -Ender Pearl ( "enderpearl" ) + -Bone ( "bone) + -Gunpowder ( "gunpowder) + -String ( "string" ) + -Nether Star ( "netherStar" ) + -Leather ( "leather" ) + -Feather ( "feather" ) + -Egg ( "egg" ) + -End Stone ( "endstone" ) + -Torch ( "torch" ) + -Vine ( "vine" ) + -Cactus ( "blockCactus" ) + -Grass ( "grass") + -Obsidian ( "obsidian" ) + -Red Sandstone ( added to "sandstone" ) + -Crafting Table ( "workbench" ) + -Slime Block ( "blockSlime" ) + -Granite ( "stoneGranite" ) + -Polished Granite ( "stoneGranitePolished" ) + -Diorite ( "stoneDiorite" ) + -Polished Diorite ( "stoneDioritePolished" ) + -Andesite ( "stoneAndesite" ) + -Polished Andesite ( "stoneAndesitePolished" ) + +Build 1.9-12.16.0.1854-1.9: + kashike: + Remove @SideOnly(Side.CLIENT) from BossInfo/BossInfoServer methods + + These methods can also be used by the server (see BossInfoServer, it sends packets to the client but the methods are @SideOnly(Side.CLIENT)) + +Build 1.9-12.16.0.1853-1.9: + fry: Made forge fluids use smooth lighting. + +Build 1.9-12.16.0.1852-1.9: + LexManos: Fixed NPE in dedicated server languages. And fixed logger for main FML event bus. + +Build 1.9-12.16.0.1851-1.9: + LexManos: Enhance some error logging related to OBJLoader issues, and RegistryEntries. + LexManos: + Cleanup OBJLoader parse function and fix issues related to JVM differences. + Also fix support for sopme of the spec that was partially respected. + +Build 1.9-12.16.0.1850-1.9: + mezz: Fix some plain keybinds not working when a modifier is active + +Build 1.9-12.16.0.1849-1.9: + mezz: Fix #2717 Pick block hotkey not working in inventories + +Build 1.9-12.16.0.1848-1.9: + kat.swales: Corrected CapabilityItemHandler.readNBT ignoring anything in slot 0 in 1.9 + +Build 1.8.9-11.15.1.1847: + kat.swales: Corrected readNBT ignoring anything in slot 0 + +Build 1.9-12.16.0.1846-1.9: + fry: Fixed zip being closed too early in the server language loading. + fry: Fixed forge fluid having a collision box. + +Build 1.9-12.16.0.1845-1.9: + iTitus: Fix dynbucket item transformation. + +Build 1.9-12.16.0.1844-1.9: + fry: Fixed some test mods not being marked as client-only. + +Build 1.9-12.16.0.1843-1.9: + fry: Fixed mod languages not being loaded on the server. + +Build 1.9-12.16.0.1842-1.9: + Zaggy1024: Fixed using PlaySoundEvent to replace a sound with a PositionedSound causing an NPE due to the Sound field not being set by a call to ISound.createAccessor(SoundHandler). + +Build 1.9-12.16.0.1841-1.9: + mezz: + Add modifier support to vanilla keybindings. + + Add Orange conflict color for modifier/key conflicts + (like Ctrl and Ctrl-Z conflicting) + Related to #2692 + +Build 1.9-12.16.0.1840-1.9: + vincent.lee: Player Interact Event + +Build 1.9-12.16.0.1839-1.9: + AEnterprise: onBlockHarvested is no longer called twice + LexManos: Fixed EntityJoinWorldEvent not being fired for some entitites on Server Worlds. Closes #2685 + LexManos: Fix improper logic in ItemHandlerHelper.giveItemToPlayer causing some items to not be added. Closes #2705 + +Build 1.9-12.16.0.1838-1.9: + LexManos: Fix issue caused by setting spawnRadius to 0. Closes #2624 + +Build 1.9-12.16.0.1837-1.9: + fry: Made both exceptions occuring during item model loading print in the log; closes #2696. + +Build 1.9-12.16.0.1836-1.9: + fry: Added the ability to change the printed model error count; Added printing of actual exceptions causing missing variants related to blockstate loading, closes #2689. + +Build 1.9-12.16.0.1835-1.9: + mcjty1: + Added DimensionManager.createProviderFor() to WorldClient constructor similar to what is done + in WorldServer to make sure the correct provider is created client-side too. + +Build 1.9-12.16.0.1834-1.9: + iTitus: + Add flashing update notification icon made by @gigaherz, closes #2582 + + It is added to the "Mods" button in the main menu and to out-of-date mods in the mod list (there it replaces the "U"). + Also fixes a little typo. + +Build 1.9-12.16.0.1833-1.9: + mezz: Fix inability to attack while holding modifier keys + +Build 1.9-12.16.0.1832-1.9: + mezz: Re-Add key binding modifiers and contexts. + +Build 1.9-12.16.0.1831-1.9: + fry: + Revert "Add key binding modifiers and contexts.", until it's fixed. + + This reverts commit 34c3af7e853d578c8e17e1f0cdf886251fad74ae. + +Build 1.9-12.16.0.1830-1.9: + fry: Changed generic signature of GameRegistry.register methods to work around the type inference bug; updated all example mods to the new block/item registration method. + +Build 1.9-12.16.0.1829-1.9: + Adubbz: Fixed mismatch registry names and mod ids + +Build 1.9-12.16.0.1828-1.9: + mezz: + Add key binding modifiers and contexts. + + Same as #2674, but for Minecraft 1.9 + +Build 1.9-12.16.0.1827-1.9: + LexManos: Properly deprecate and link the replacement methods in GameRegistry. Add helper method for registering a block with default ItemBlock because people keep complaining -.- + +Build 1.9-12.16.0.1826-1.9: + LexManos: Fixed compile error in registry code with Eclipse. + +Build 1.9-12.16.0.1825-1.9: + cpw: Capture a vanilla freeze - will be used when FML connects to vanilla servers, soon + +Build 1.9-12.16.0.1824-1.9: + cpw: Support ResLocations for IMC + +Build 1.9-12.16.0.1823-1.9: + fry: Improved UV offset hackery - should fix most visible custom model seams. + +Build 1.9-12.16.0.1822-1.9: + cpw: MinecraftForge-2684 [1.9] New Registry ignores keys + +Build 1.9-12.16.0.1821-1.9: + cpw: MinecraftForge-2683 InvocationTargetException for Forge 1820 for 1.9 + +Build 1.9-12.16.0.1820-1.9: + cpw: + Add registries for soundevents, enchantments and potiontypes + MinecraftForge-2576 [1.9] SoundEvents (and Enchantments and PotionTypes) need a FML registry + +Build 1.9-12.16.0.1819-1.9: + cpw: Fix remapped blocks being overriden with dummy air blocks. Closes #2491 + cpw: + Squashed commit of the following: + + commit b3b290aec9d3010a134859da6001ea28a96c2fdc + Merge: c6ce6a0 d803f7d + Author: cpw + Date: Fri Mar 25 13:28:04 2016 -0400 + + Merge branch 'RegistryRework' of https://github.com/LexManos/MinecraftForge into LexManos-RegistryRework + + Implement proper registry slaves. Should help with rollback related issues. + + Missing patch + + commit d803f7db76f65db9d27302c9804a643bc853dc22 + Author: LexManos + Date: Tue Mar 22 03:36:14 2016 -0700 + + Update VillagerRegistry and use it. Should in theory make custom villagers work now. Using string version instead of int id for networking. + + commit eb5e5b4b42fdca26d2a104e4dc1e6a3ea3051a7b + Author: LexManos + Date: Tue Mar 22 02:14:16 2016 -0700 + + More cleanup. + + commit edbc56b2ff314629d0e402709f3cf29fc79c4a3d + Author: LexManos + Date: Tue Mar 22 02:05:23 2016 -0700 + + More cleanups, removed deprecated UniqueIdentifier {ResourceLocation now} + + commit e2df8d1be3c97601508f83dc97b0e8853fa1e271 + Author: LexManos + Date: Tue Mar 22 01:29:19 2016 -0700 + + Stupid generics.... + + commit 46d57dc4677fa5ff3923e64eaccfb33d7e5aad8d + Author: LexManos + Date: Tue Mar 22 01:00:25 2016 -0700 + + Some registry tweaking to provde a non-complicated API modders can use. + cpw: Reconcile Block.patch + +Build 1.9-12.16.0.1817-1.9: + kashike: + Replace Forge's `BlockPos#getImmutable` method with the included `BlockPos#toImmutable` (func_185334_h), while keeping the override in PooledMutableBlockPos to prevent mutable leaks. + Also prevent a mutable blockpos leak in World#setTileEntity + gigaherz: Add wrapper methods for IStorage#readNBT/writeNBT. + LexManos: Fix landing particles not showing up. Cloes #2661 + shadowfacts: Forward ItemBlock#addInformation to Block#addInformation + tterrag1098: Add state param to canRenderInLayer + +Build 1.9-12.16.0.1816-1.9: + LexManos: Make NoteBlockEvent raw constructor protected to allow subclasses. Closes #2153 + +Build 1.9-12.16.0.1815-1.9: + LexManos: Fix EntityPlayer still running old armor logic. Closes #2670 + LexManos: Fix shrubs not generating correctly. Closes #2663 + LexManos: Fix bows not animating properly when picking up ammo while using. Closes #2672 + +Build 1.9-12.16.0.1814-1.9: + mezz: Fix Block.getPickBlock returning an ItemStack with a null Item + +Build 1.9-12.16.0.1813-1.9: + fry: Fixed StackOverflow caused by the previous commit, closes #2669. + +Build 1.9-12.16.0.1812-1.9: + fry: Prevent missing model from loading multiple times. + +Build 1.9-12.16.0.1811-1.9: + fry: Enabled diffuse lighting by default in UnpackedBakedQuad.Builder. + fry: Fixed crosshair always being white, closes #2653. + +Build 1.9-12.16.0.1810-1.9: + fry: Fixed diffuse lighting not being applied if forge lighting pipeline is disabled, closes #2651 + +Build 1.9-12.16.0.1809-1.9: + mezz: + Make tooltips layout in the right direction, wrap if there is no room + + Same as #2649, but for Minecraft 1.9 + +Build 1.8.9-11.15.1.1808: + mezz: + Make tooltips layout in the right direction, wrap if there is no room + + Fixes #2255 + +Build 1.9-12.16.0.1807-1.9: + fry: Disabled erroring block, fixed DynBucketTest.TestItem model. + +Build 1.9-12.16.0.1806-1.9: + diesieben07: Fix PopulateChunkEvent.Post not firing + +Build 1.9-12.16.0.1805-1.9: + fry: Cleanup: removed IEEP, removed redundant casts, fixed imports, fixed typos. + fry: Fixed isSideSolid causing infinite loops due to the call to getActualState. + fry: Removed LanguageRegistry and CollectionWrapperFactory. + fry: Removed RenderWorldEvent, encapsulated all public event fields. + fry: Made some more public fields either private or final. + +Build 1.9-12.16.0.1804-1.9: + LexManos: + New Builder class in BlockStateContainer. Makes building containers with both listed and unlisted properties cleaner. + Make all methods of BiomeGenBase$BiomeProperties public so that modders can use that class outside subclasses. + +Build 1.9-12.16.0.1803-1.9: + diesieben07: Fix BlockCrops.getDrops not respecting new age methods (for beetroots) + +Build 1.9-12.16.0.1802-1.9: + fry: Show meaningful error if ModelLoaderRegistry is used before the missing model is initialized. + fry: Register the animation Capability. No idea how it worked before at some point. + +Build 1.9-12.16.0.1801-1.9: + LexManos: Fix typo causing biomes to be generated in wrong chunks. Closes #2632 + +Build 1.9-12.16.0.1800-1.9: + LexManos: Fixed custom entities unique ids. + +Build 1.9-12.16.0.1799-1.9: + LexManos: Update FML Entity Spawn packet for 1.9's location change. Closes #2567 + +Build 1.9-12.16.0.1798-1.9: + vincent.lee: Actually fix dupe drop + +Build 1.9-12.16.0.1797-1.9: + fry: Added Capability.cast, to allow avoiding unchecked casts in ICapabilityProvider.getCapability + +Build 1.9-12.16.0.1796-1.9: + LexManos: Fix swap animations for sure this time. + +Build 1.9-12.16.0.1795-1.9: + LexManos: Allow finite fluids to be drained correctly + LexManos: Make OreDictionary.initVanillaEntries() private so that dumb modders will stop calling it. + +Build 1.8.9-11.15.1.1794: + Choonster.2010: Allow finite fluids to be drained correctly + +Build 1.9-12.16.0.1792-1.9: + matthewprenger: Pass exceptions thrown in mod event buses back to FML to handle apropriately + vincent.lee: Fix double dropping of items. Closes #2549 + diesieben07: Fix EntityList.func_188429_b not supporting mod-entities, fixes spawn eggs, fixes #2581 + +Build 1.8.9-11.15.1.1791: + elpatricimo: + Fix pushing players inside blocks. + + same changes made to the 1.9 branch + +Build 1.9-12.16.0.1790-1.9: + vincent.lee: Expose IItemHandler on vanilla entities + vincent.lee: Update according to suggestions + +Build 1.9-12.16.0.1789-1.9: + LexManos: Make RenderLivingBase.add/remvoeLayer, Closes #2573 + LexManos: Added support for custom dyes with Banners. Closes #2596 + +Build 1.9-12.16.0.1788-1.9: + LexManos: Add ShieldDecoration and Tipped arrows to recipe sorter. Closes #2613 + LexManos: Exclude jna from termal tansformer. + LexManos: Fix pushing players inside blocks. + +Build 1.9-12.16.0.1787-1.9: + LexManos: Fix Chests not opening correctly with semi-solid blocks on top. + LexManos: Fixed Item.shouldCauseReequipAnimation hook. + +Build 1.9-12.16.0.1786-1.9: + elpatricimo: + Allow players sized smaller than 1 block to walk into small spaces + + Same as #2605 but for 1.9 branch + +Build 1.8.9-11.15.1.1785: + elpatricimo: Allow players sized smaller than 1 block to walk into small spaces + +Build 1.9-12.16.0.1784-1.9: + LexManos: Rework DimensionManager for new DimensionType enum, replaces the old provider registry. Also fixed save folder issues with dimensions. Closes #2570 + +Build 1.8.9-11.15.1.1783: + CovertJaguar: Add missing Minecart/Track hook. + +Build 1.9-12.16.0.1782-1.9: + fry: Removed blockCenterToCorner from TRSRTransformation constructor. Closes #2461. + fry: Ignore blocks/items with null registry name during model loading. Fixes NPE during resource reloading in worlds with removed blocks/items. + fry: Made VertexBuffer.sortVertexData cleanup pointers after it's done. Closes #2528. + fry: Added default left hand transforms for forge transform strings. Closes #2615. + +Build 1.9-12.16.0.1781-1.9: + fry: Switched animation system to capabilities, added animated item example, fixed state passing in MultiModel. + fry: Separated model classes to client and common packages. + fry: instance -> INSTANCE + fry: Implemented slightly more generic version of UVLock, re-enabled it for json models. Closes #2607. + +Build 1.9-12.16.0.1780-1.9: + gigaherz: Fix a condition that caused the enchantment table to roll invalid enchantments. + +Build 1.9-12.16.0.1779-1.9: + blay09: + Fix KeyInputEvent only being fired if Keyboard.getEventKeyState() is false. + + It used to be called for both key-up and key-down states prior to 1.9, so I assume Vanilla's changes to F3 behavior broke the patch. + +Build 1.9-12.16.0.1778-1.9: + CovertJaguar: Fix #2601 Minecart infinite acceleration + +Build 1.8.9-11.15.1.1777: + cordonfreeman: Fix for patch targetting the wrong field to change for failed pathfinding penalty + +Build 1.9-12.16.0.1776-1.9: + diesieben07: Fix broken patch in EntityPlayer.updateRidden + +Build 1.9-12.16.0.1775-1.9: + iTitus: + Fix the EntityPlayer patch + + In 1.8.9 the call goes to getDisplayNameString() so that any changes from the PlayerEvent.NameFormat event are being take into account. + In this patch the call goes to func_70005_c_() which is the getter for the GameProfile name. + I changed it back. + + Sorry if you do not want to accept it because it is a one-liner. + vincent.lee: Fix #2555 + +Build 1.9-12.16.0.1774-1.9: + cordonfreeman: Fix for patch targetting the wrong field to change for failed pathfinding penalty + +Build 1.9-12.16.0.1773-1.9: + cpw: Fix bucket test + +Build 1.9-12.16.0.1772-1.9: + bernhard.bonigl: + Fix CombinedInvWrapper accessing incorrect slots + Closes #2533 + +Build 1.9-12.16.0.1771-1.9: + cpw: Ignore classes directory + +Build 1.9-12.16.0.1770-1.9: + fry: Fixed sprite not being passed to the quad builder for custom models. + +Build 1.9-12.16.0.1769-1.9: + fry: Fixed outline shader rendering, closes #2560. + +Build 1.9-12.16.0.1768-1.9: + fry: Fixed Block.doesSideBlockRendering, closes #2564. + +Build 1.9-12.16.0.1767-1.9: + fry: Fixed invalid index calculation in BakedQuadRetextured. + +Build 1.8.9-11.15.1.1765: + bernhard.bonigl: + Fix CombinedInvWrapper accessing incorrect slots + Closes #2533 + +Build 1.8.9-11.15.1.1764: + abab9579: + Added EntityViewRenderEvent#FOVModifier + + Enables mods to modify raw FOV directly. + Avoids modifier limit from FOVUpdateEvent. + Aware of blocks which are needed for fov change related with materials. + +Build 1.8.9-11.15.1.1763: + mnmiller1: Added local click position to PlayerInteractEvent. + +Build 1.8.9-11.15.1.1762: + LexManos: + Fixed dummy blocks not being removed from registry on dedicated server correctly. Closes #2487 + Also added some more debug logs! + +Build 1.8.9-11.15.1.1761: + bernhard.bonigl: + Fix WordServer.canCreatureTypeSpawnHere not using Forge Events. + Followup of #2496 + +Build 1.8.9-11.15.1.1760: + agent-lego: + Increased actual maximum fuel burn time + + Increased actual maximum fuel burn time from 32767 to 2147483647. + Backwards compatible. + +Build 1.8.9-11.15.1.1759: + bernhard.bonigl: Fix WorldEvent.PotentialSpawns Event passing the list instance of the ChunkProvider to users + +Build 1.8.9-11.15.1.1758: + fry: ModelLoader: added verbose error logging showing items/blockstates associated with model locations; removed redundant cast leftover from ungenerified code; fixed up a couple of warnings. + +Build 1.8.9-11.15.1.1757: + cpw: Fix race condition when using indexed codec in a LAN server. Fixes spurious crash when LAN server is running. + +Build 1.8.9-11.15.1.1756: + cpw: Log when it's likely the indexedcodec is gonna fail, because of LAN server derps likely. Try and give some context for debuggers. + +Build 1.8.9-11.15.1.1755: + bernhard.bonigl: Fix universal bucket logging an exception + +Build 1.8.9-11.15.1.1754: + AlgorithmX2: Preserve ItemStack Caps when picking Items up. + AlgorithmX2: Test getLightOpacity(world,pos) in World as well as the chunk. + +Build 1.8.9-11.15.1.1752: + AlgorithmX2: In material Liquid Hooks. + +Build 1.8.9-11.15.1.1751: + diesieben07: Fix Potion.shouldRenderInvText + +Build 1.8.9-11.15.1.1750: + AlgorithmX2: + Fix bug with getLightOpacity based on TileEntities, + Capture getLightOpacity prior to removing the tile entity. + +Build 1.8.9-11.15.1.1749: + LexManos: Fix loading of world ID maps for worlds without dummy data. Closes #2477 + +Build 1.8.9-11.15.1.1748: + bernhard.bonigl: Fix customized bucket names not getting translated correctly + +Build 1.8.9-11.15.1.1747: + fry: Added default levels for fluid extended properties in fluid model. + +Build 1.8.9-11.15.1.1746: + bernhard.bonigl: Add universal bucket + +Build 1.8.9-11.15.1.1745: + LexManos: Fix chat formatting not surviving line wraps in chat messages. + +Build 1.8.9-11.15.1.1744: + diesieben07: Fix the entity shader hook + +Build 1.8.9-11.15.1.1743: + iLexiconn: Added hook to add entity spectator shader + +Build 1.8.9-11.15.1.1742: + ross: Workaround JDK-8087309: Constant folding "static final boolean" in boolean expressions is incomplete + +Build 1.8.9-11.15.1.1741: + LexManos: Protect BlockSnapshot and Chunk.getTileEntity from mutible BlockPos instances. Closes #2438 + +Build 1.8.9-11.15.1.1740: + LexManos: Fixed invalid parameters being sent to LivingSpawnEvent.CheckSpawn. Closes #2453 + LexManos: Fixed Entity.shouldRiderSit modifying game logic and not just rendering. Closes #2402 + LexManos: Fixed Block/Item.setRegistryName printing a incorrect warning when used. Closes #2398 + LexManos: Fixed vanilla bug where network clients would see incorrect break progress on blocks. Closes #2462 + LexManos: Fixed implementation of RenderEntityItem.shouldSpreadItems. Closes #2448 + LexManos: Fixed invalid item being passed to gatherCapabilities when itemstacks changed item. Closes #2445 + LexManos: Add missing classes to CrashReport preloading. Closes #2421 + LexManos: Fixed Block.onNeighborChange not being called for all axises. Closes #2428 + +Build 1.8.9-11.15.1.1739: + LexManos: Potential fix for NPE when using an item to open a slotless inventory. Closes #1354 + +Build 1.8.9-11.15.1.1738: + fry: Fix custom model loader reload hook not firing during registration. + +Build 1.8.9-11.15.1.1737: + fry: Fix incorrectly updated patch to ChunkCache. Related to #2451. + +Build 1.8.9-11.15.1.1736: + fry: Fix multiple registrations of reloading hooks in custom model loaders. + +Build 1.8.9-11.15.1.1735: + LexManos: Fix jar signer not applying to universal packed in the installer. + LexManos: Remove Mojang logger spam in EntityItem. + +Build 1.8.9-11.15.1.1734: + fry: Fix TRSRTransformation.toItemTransform. Closes #2425. + +Build 1.8.9-11.15.1.1733: + paul.fulham0: Fix #2321 + +Build 1.8.9-11.15.1.1732: + Mumfrey: Fix ASM SignatureReader choking on lambda signatures generated by JDT + +Build 1.8.9-11.15.1.1731: + fry: Revert binary-incompatible changes in models. + +Build 1.8.9-11.15.1.1730: + fry: Fix droppers not dropping. + +Build 1.8.9-11.15.1.1729: + fry: Added "gui3d" and "smooth_lighting" options to the forge blockstate. Implemented them for vanilla and B3D models. Added generic types to IModel subinterfaces, to simplify chaining. + fry: One day I will learn to include all required classes in the commit. + +Build 1.8.9-11.15.1.1727: + matthewprenger: Log unknown exceptions in commands. Resolves #2433 + +Build 1.8.9-11.15.1.1726: + fry: Fixed incorrect patch to GenLayer, causing large vanilla biomes to not work properly. + +Build 1.8.9-11.15.1.1725: + fry: Provide original armor model in the custom armor model hook. + +Build 1.8.9-11.15.1.1724: + fry: Fixed small bug in item extraction code. + +Build 1.8.9-11.15.1.1723: + fry: Fix NoSuchElementException in ModelBlockAnimation caused by empty event list. + +Build 1.8.9-11.15.1.1722: + LexManos: Bump version in prep for new Recomended Build. + +Build 1.8.9-11.15.0.1721: + LexManos: Loosen TileEntity's default hasCapability implementation. Modders should specifically opt in. + +Build 1.8.9-11.15.0.1720: + vikestepftb: + Add EntityTravelToDimensionEvent + + Resolve Merge Conflict + + Move event call inside conditional + +Build 1.8.9-11.15.0.1719: + fry: Fixed minor race condition between mouse clicks and TESR in the animation example. + +Build 1.8.9-11.15.0.1718: + fry: + Model animation system. + Main things of interest: + * IAnimationStateMachine - state machine for animations; can load + from json. + * AnimationTESR - automatic TESR for animated models. + * AnimationModelBase - same for entities. + * ITimeValue - time-varying value, used to control animation + parameters from code. + + * TESRs can now be batched - look at TESR.renderTileEntityFast + + TE.hasFastRenderer. + * RegionRenderCache is not accessible to TESRs and other client-side + logic - MinecraftForgeClient.getRegionRenderCache. + fry: Sometimes I forget how much trivial things are missing from Java 6. + +Build 1.8.9-11.15.0.1716: + t.tomkins: Fixed: BlockPos passed to isBeaconBase + rwtema: + Add IItemHandler capability + + Add the actual patches that I forgot. + + Add simple implementations of IStorage and the factory methods. + + Add ItemStackHandler. A simple IItemHandler implementaton. + + return nulls, not throw nulls. + + Move the vanilla wrappers to a separate class for now. + + Minor clean ups of VanillaWrapper code. + + Inline static methods. + + Add comments. + + Minor cleanup of code. + + Remove redundant size field and add a validate slot index method. + + Minor formatting issues. + + Break early If stacksize to insert is 0. + + Remove setByte() methods. + + Throw exception if IItemHandler can't be modifyed in NBT loading. + + Replace event handler with patches + + Add capability to mine cart inventory entities. + + Change formatting and registration of capability. + + Make InventoryPlayer implements IItemHandler because why not. Also added a field to allow mods that add additional player inventory space to publicly expose them. + + Reduce patch sizes + + Lazy initialization of the item handler for vanilla tiles. + + Minor formatting changes. + + Create a single vanilla chest item handler that will merge with adjacent chests when detected. Added hooks to reset the cached adjacent value when a block update is detected and when a chunk loads. + + Revert "Make InventoryPlayer implements IItemHandler because why not. Also added a field to allow mods that add additional player inventory space to publicly expose them." + + This reverts commit 306d4a37fd0e8c8a0754411c013b750dfe8e2c87. + + Fix furnace derp + + Replace double chest code with a simpler method. + + Vanilla wrappers implement IItemHandlerModifiable (since they are modifiable) + + Minor code cleanups + + Add an onContentsChanged() and onLoad() callback methods.to the default implementation. + + Add slot as a parameter in the callback method. + + Change IItemHandlerModifiable.setStackInSlot() to void, and added a note about not being intended for cross-mod use. + + Improve ItemStackHandler handling of errored NBT. + + Make the stacks array protected. + + Fix a lot of derps in SlotItemHandler. + + Fix derp in ItemStackHandler + + Clarify comments on IItemHandler + + ItemStackHandler no longer caches the stack array in local variable. + + Clean up the Chests code to make intentions clearer + + Vanilla hoppers have their cooldown activated when an item is inserted. Made this behavior part of an item handler (rather than the insertion code) + + Fix mistake in ItemStackHandler + + More documentation of potential edge cases in getStackInSlot() + + Make limit checking more resiliant. + LexManos: Fix J6 compile error in IItemHandler PR. + +Build 1.8.9-11.15.0.1715: + blay09: Fix items being dropped out of a GuiContainer when dealing with a slot outside of the xSize/ySize boundaries. + +Build 1.8.9-11.15.0.1714: + asiekierka: Fix #2388 + +Build 1.8.9-11.15.0.1713: + LexManos: Fix invalid ServerHangWatchdog patch causing it to not apply. + LexManos: + Restore OreDictionary.getOres(String, boolean) and doeOreNameExist(String) functions that went MIA in git merge issue. + Original Commit: https://github.com/MinecraftForge/MinecraftForge/commit/cd3bbfb02c9fcd4ce4bbf00f460dfdd6a386d107 + +Build 1.8.9-11.15.0.1712: + minecrell: Strip console formatting codes for Vanilla log file + +Build 1.8.9-11.15.0.1711: + iLexiconn: + Fixed makeItemStack ignoring stackSize + + Fixes #2376 + +Build 1.8.9-11.15.0.1710: + fry: Fixed error detection login in ModelLoader, reduced the maximum number of printed stack traces to 5 per domain. + +Build 1.8.9-11.15.0.1709: + LexManos: Fix Deobfusication transformer throwing verification errores in Eclipse development environments. + LexManos: Fix forge logging not working correctly in ForgeDev. + +Build 1.8.9-11.15.0.1708: + fry: Correctly handle error caused by missing/malformed bucket model definition file. + +Build 1.8.9-11.15.0.1707: + LexManos: Call deserialze on capabilities in ItemStack.setItem. Closes #2384 + +Build 1.8.9-11.15.0.1706: + LexManos: Fix ItemStacks not getting the parent capability provider from items. Closes #2383 + +Build 1.8.9-11.15.0.1705: + bartek.bok: Allow sleeping without bed + kashike: Skip hang detection on first run of the server hang watchdog + +Build 1.8.9-11.15.0.1703: + fry: Fixed missing model error reporting, made block and item variants sort before loading, to make the splash screen info more useful. + +Build 1.8.9-11.15.0.1702: + cpw: Fix spruce not growing properly + +Build 1.8.9-11.15.0.1701: + cpw: Fixed problem with LAN connections seeing the original ProxyPacket and consuming the first byte. Closes #2373 + +Build 1.8.9-11.15.0.1700: + cpw: Fix shouldRefresh not to be so over-eager about modded TEs. Should fix Packet21 causing a TE reset. + +Build 1.8.9-11.15.0.1699: + LexManos: Clone FML packet indexes if channel is not open. Fixes potential threading issue. + +Build 1.8.9-11.15.0.1698: + bernhard.bonigl: + Default bucket model is empty, allow bucket model without fluid. + This allows capsules, cans, bottles,... to use the same item model for their item variant. Also it's makes much more sense. + +Build 1.8.9-11.15.0.1697: + mezz: Add GuiScreenEvent.BackgroundDrawnEvent + +Build 1.8.9-11.15.0.1696: + cpw: + Fix problem which meant runtime deobf to MCP names wasn't working. SRG named mods located in the mods dir of a dev + environment will now load normally. + +Build 1.8.9-11.15.0.1695: + LexManos: + New Capability system allowing for more manageable world object features. + + When combined with @Optional this should address all issues of soft dependancy on mods/apis. + This also addresses the issue of dynamic functionality in TileEntities/Entities. + + Current capability providers: TileEntity, Entity, ItemStack + + Also added INBTSerializeable, a generic interface for game objects that can be written to/from NBT tags. + + Vanilla capabilities will be coming soon, mostly on request and review. + So start requesting capabiliteis on vanilla/Forge features. + +Build 1.8.9-11.15.0.1694: + LexManos: Fixed GuiWrongMinecraft having wrong Log file name. Closes #2348 + LexManos: Fix jline server console not showing colored text. Closes #2334 + LexManos: Fixed banners not droping the correct item when harvested using modded mechanics. Closes #2258 + +Build 1.8.9-11.15.0.1693: + LexManos: Remove dead code in JarDiscoverer. Closes #2346 + LexManos: Made WrongMinecraftVersionException and ModSortingException a bit easier to read in log files. Closes: #2345 + +Build 1.8.9-11.15.0.1692: + fry: Catch GROUND item transform type with the forge hook too. + +Build 1.8.9-11.15.0.1691: + fry: Implemented face culling for item models, improves performance slightly. Closes #2326 + +Build 1.8.9-11.15.0.1690: + vincent.lee: + Fix visual effect entity persisting longer than it should + + Fix derp + +Build 1.8.9-11.15.0.1689: + LexManos: Fixed issue with WorldServer.getTileEntities when being called with ranges that overlap chunks oddly. Closes #2350 + +Build 1.8.9-11.15.0.1688: + fry: Made block model loading bar more robust, and fixed the count. + +Build 1.8.9-11.15.0.1687: + fry: Added progress bar for the ModelLoader. + +Build 1.8.9-11.15.0.1686: + fry: Model loader improvements: adding custom data/textures to models that don't need them doesn't cause a error now, since it's common to put those in the defaults section of the blockstate json; you can get IModel associated with the variant now - using ModelLoaderRegistry.getModel; MultiLayerModel should now respect transformations applied to it, and respect part transformations. + fry: Derp. + +Build 1.8.9-11.15.0.1684: + cpw: STFU I know how to code. *shouts* get off my lawn! + +Build 1.8.9-11.15.0.1683: + cpw: Make the parent dir tree for the dep extractor + +Build 1.8.9-11.15.0.1682: + fry: Changed default implementation of Block.getExtendedState. Closes #2309. + +Build 1.8.9-11.15.0.1681: + fry: Fixed perspective transformation handling for fluid models, changed inventory fluid model to use unrotated still texture. + fry: Don't crash on exception during loading of item variants from blockstate jsons. + fry: Fixed implementation if IRetexturableModel in ItemLayerModel. Closes #2244. + fry: Java6 + Eclipse + Gradle strike again. + +Build 1.8.9-11.15.0.1677: + fry: Fixed invalid flow vector caching of still fluids. + +Build 1.8.9-11.15.0.1676: + fry: Fixed random offset not working properly for flatly-lit models. + +Build 1.8.9-11.15.0.1675: + cpw: Explicitly close the file. + +Build 1.8.9-11.15.0.1674: + cpw: + Add a simple ContainedDep mechanic- mods can contain other mods or libs, and can specify them using a manifest tag: "ContainedDeps". + This is a space separated (manifest standard) list of jar files that are to be extracted into the version specific directory. + + There's also a special system property "fml.skipContainedDeps" that will allow for runtime skipping of extraction of contained deps (a comma separated list, based on the file name). + +Build 1.8.9-11.15.0.1673: + LexManos: + Added new get/setRegistryName functions to Item and Block. + And helper functions in GameRegistry to allow for registering using those names automatically. + This is to simplify registration and get rid of the horrible hacks users are doing now with 'unlocalised names'. + +Build 1.8.9-11.15.0.1672: + cpw: Move substitution activation after id loading. This should fix the problem of null for existing object. + +Build 1.8.9-11.15.0.1671: + fry: SidedProxy now has sensible default values - nested ClientProxy and ServerProxy classes. + +Build 1.8.9-11.15.0.1670: + mattmess1221: Add links for messages and other commands + +Build 1.8.9-11.15.0.1669: + fry: Reverted Render registration changes due to them working. + +Build 1.8.9-11.15.0.1668: + fry: Fixed RenderingRegistry not working. Closes #2312. + fry: Nobody is left behind. + +Build 1.8.9-11.15.0.1666: + cpw: Fix that the dummy registry entries don't allow clients connecting to servers. Also fix that it repeatedly nags about missing stuff in the world. + +Build 1.8.9-11.15.0.1665: + LexManos: Fix boss health bar rendering when debug overlay is enabled. Closes #2328 + +Build 1.8.9-11.15.0.1664: + LexManos: Allow for default 1.8.8 mods to be loaded. Should be SRG compatible. + LexManos: Fix J6 compile issue with ModelFluid. + LexManos: Swap Mod and Realms button to fix new realms 'notification' icon. + +Build 1.8.9-11.15.0.1663: + fry: Restored transparency to the Forge logo. + +Build 1.8.9-11.15.0.1662: + fry: Updated the forge logo to a higher-quality GIF file. Closes #2276. + +Build 1.8.9-11.15.0.1661: + fry: Fixed broken leaky caching of OBJ models. + fry: Fixed wrong import. + +Build 1.8.9-11.15.0.1659: + fry: Caching of fluid models. Fixes #2145. + +Build 1.8.9-11.15.0.1658: + fry: TESRs registering in preinit don't break pistons anymore. Fixes #2298. + +Build 1.8.9-11.15.0.1657: + fry: Fixed color disabling not working for forge pipeline. Closes #2286. + +Build 1.8.9-11.15.0.1656: + fry: 1.8.9 update + +Build 1.8.8-11.15.0.1655: + mezz: Allow server to access Potion isBadEffect() + cpw: 1.8.8 initial work + cpw: regenerate reference patchset at patches.mcp. These will be used to generate a new patchtree under patches. + cpw: Test of mcp patching + cpw: + Patches and rejected patches. Note: some which had imports are not listed here because they need + to be refactored not to have imports. + Progress: https://gist.github.com/cpw/29695e426e2b122cf8ff + fry: Updated various rendering-related patches and classes to 1.8.8; forge still uses vecmath. + fry: Fix generics and error in the BlockState patch. + fry: FontRenderer + Item patch update; WorldVertexBufferUploader patch derp fix. + fry: IntegratedServer, World, EnumChatFormatting and EnumFacing + fry: WorldProvider, WorldType, WorldServer, WorldServerMulti + fry: EntityAIAttackOnCollide, ServerStatusResponse, MinecraftServer, NetHandlerLoginServer, Vec3, BiomeGenBase, AnvilChunkLoader, ChunkProviderServer, MapGenRavine, MinecraftServer updated; fix in Block, GuiIngameForge; can load the world and play with ~20 more manual error fixes. + fry: BlockOre, BlockRotatedPillar, SoundManager, EntityPlayerSP, GuiScreen, GuiAchievements, GuiContainer, BlockModelRenderer, ContainerEnchantment, Slot updated manually and imports removed; GitSlot patch updated. + cpw: Delete rejects that I initially processed. + cpw: + LoadingScreenRenderer,Minecraft,GuiContainerCreative,PlayerControllerMP,LanguageManager,Locale,SimpleReloadableResourceManager,EntityList,EntityLivingBase,EntityWither,EntityMinecart,EntityPlayerMP + + NethanlderPlayClient patch is now in vanilla. The FMLCommonHandler future exception catcher is not needed anymore, it's in Util. The caching of player profiles is now in vanilla (SkinManager). + fry: Updated FML Gui methods to WorldRenderer API changes. + fry: EntityPlayer patch updated. + fry: GuiButton, GuiChat, GuiCreateWorld, GuiIngameMenu, ServerListEntryNormal, GuiStats rejects updated. + fry: RenderEntityItem, RenderPlayer, RendererLivingEntity, LayerArmorBase, ItemStack rejects fixed; changed Armor Layer hook to catch LayerBipedArmor only. + fry: ItemRenderer, RenderGlobal, StateMap, RenderItem rejects updated. + fry: TileEntity and TileEntityHopper rejects fixed, GuiOverlayDebug patch fixed. + fry: PlayerManager, PlayerProfileCache, ServerConfigurationManager, NetHandlerHandshakeTCP rejects fixed; ItemInWorldManager patch error fixed. + fry: ItemBlock, ItemBow, ItemMonsterPlacer, ItemReed, ItemSign rejects fixed. + fry: Manually updated WorldChunkManager, Chunk and BiomeDecorator patches, removed imports. + fry: TextureMap, TextureManager and Stitcher rejects fixed. + fry: EntityRenderer, StringTranslate rejects fixed. + fry: Overlay patch fix: use the correct block position. + cpw: + Enchantment,EnchantmentHelper,EntityEnderman,EntityZombie,EntityVillager,FurnaceRecipes,RecipeFireworks,RecipeRepairItem,NetworkSystem,S00PacketServerInfo + PotionEffect,StatList,Session,WeightedRandomChestContent,Explosion,ExtendedBlockStorage,SaveHandler. + + All NBT patches seem to have been merged upstream, so removing. The IntegratedServer and MinecraftServer pending queue changes also removed, as fixed upstream. + cpw: WorldGen rejects, lots of them. Couple of small fixes elsewhere. + cpw: Fix a newly missing AT. Remove all CL_ references. OBFID is gone. + cpw: All the patches done? Some code fixups.. It begins. + cpw: A few tweaks, things are starting to work now.. + fry: Model stuff: updated to generics, fixed various warnings, added handling of new perspective types. + cpw: Some generic and other warning cleanups + fry: ExtendedBlockState, Properties generic updates. + cpw: Remove a suppression + cpw: This should be everything needed to separate blocks and items completely. + fry: Implemented interpolation of TRSR transformations; B3D: added interpolation capabilities to B3DState, animated TESR example in ModelAnimationTest (pure TESR right now, no separation inside the example model between the static and dynamic parts right now). + kashike: Use the FMLSecurityManager checkPermission(Permission) method for context-based permission checks. Fixes #2067 + fry: B3D loader: removed 2 redundand null checks, changed constructor args to final to fix (java6?) inner arg error. + fry: Fix holes in generated item models. + fry: Removed face doubles from item models. + minecrell: Add jline-based console with colors and tab-completion + cpw: Fix a typesig that was broken + cpw: Re-add trove and vecmath. Mojang no longer ship them. + cpw: Use the 2.1 snapshot for FG + fry: Fixed forge lighting working incorrectly outside 0x1000000 coordinates. + cpw: Back to srgnames for patches. We should be starting to look OK now. + cpw: Small tweak to the OUT/ERR logger - should skip the Throwable stuffs now. + cpw: + Fix weird patch issue where the this FG commit: https://github.com/MinecraftForge/ForgeGradle/commit/2f0ca9921b961133689d29b807333241010a802d + breaks if the exact end of a line is a srgname. Not ideal, but should work. + cpw: Fix derpy fir trees in the taiga. So many patches. See if we can find any more mistakes?! + fry: Fixed NPE is B3D loader caused by the missing vertex normal; updated the example chest model - it's now has 2 meshes; Updated ModelAnimationDebug - it now uses the new chest model, renders the base with the static world renderer, and only the lid with the TESR. + cpw: Update mappings to 20151122. + LexManos: Update universal manifest for 1.8.8's json. + cpw: Cleanup Fluid deprecations stuff. + cpw: + OMG! Documentation? WUT? I haz lost my mind. + Also, Functional interface for IMC. Senders can send a classname implementing Guava's function, and receivers + will be able to get that function, and do, well, whatever, really. Probably best for those callback type + scenarios, connecting up APIs and stuffs. + cpw: Fix MDK for 1.8.8 using FG2.1 snapshot + cpw: Yeah, amount is NOT deprecated. + cpw: ONE EVENT BUS TO RULE THEM ALL AND IN THE DARKNESS FIRE THEM! + cpw: Deprecate it as well, because hey, it's redundant now. + cpw: Clean up some very long dead code. Bukkit hasn't existed in a very long time now. IASM never worked, and I'm not about to implement it. + cpw: Cleaning up some derpy names + cpw: More cleanups, some documentation, a bunch of deprecations. + lordillyohs: + Remove trailing */ in the build.gradle + + Signed-off-by: Anthony Anderson + cpw: Fix button and lever placement problem. Closes #2204 + cpw: Fix up a couple of patches, affected by the recent update + cpw: + Add .exc for StatList patch + + More tweaking + lumien231: Fixed: The Integrated Server not being stopped when exiting a singleplayer world to the main menu + cpw: Propogate AbortException. Closes #2206. Also fix tracing printstream when printStackTrace is called. + LexManos: Bump version for new Minecraft version. + LexManos: Fixed placing blocks on snow layers with more then one layer. + LexManos: Fixed Large mushrooms generating incorrectly. + LexManos: Removed IItemRenderer class, all functionality is possible with new rendering system. + LexManos: Compiler warnings pass, undeprecated SplashProgress related stuff. + cpw: Giant registry fixup + LexManos: Add chunk loading protection to WorldSever.getTileEntitiesIn, may prevent orphanced chunks and a CME in EntityPlayerMP. Note: The 'max' parameters are NON-inclusive. + cpw: Fix up blockstate rebuild. Closes #2221. Also fix formatting. IDEA has differences. Solved now. + bernhard.bonigl: Add a PotionRegistry to handle dynamic distribution and remapping of Potion IDs + cpw: Fix problem with spam from registry on loading a second world. Empty the staging. + cpw: Some tweaks - GameRegistry is modder facing API, so avoid having MC methods there. Fix a couple of registry bugs. + cpw: Fixup Jline integration + cpw: A few fixes + cpw: Allow entity selectors to select "." in entity names. Closes #2125 + cpw: Be noisy when API is in a coremod. It'll never work and modders should realize that fact. + cpw: + Fix language adapter loading. + + The language adapter is now properly picked up after the mod is loaded + on the classpath, fixing the ClassNotFoundException occurring before. + Also fixed some minor formatting and made it throw a full + RuntimeException on failure. + + Fix up some formatting + cpw: Most requested feature of all time? TileEntity init method called after it's ready to roll. remove all the if (firstTicks) + mark.a.woodman: + Initialize sources list + + Fixes crash NPE thrown by addFile() + cpw: Clean up chunk patch. + liach: Fix typo in `guava` + cpw: Add a flag to the modidremapping event. If the remapevent is because the registry is refreezing, it'll be true. + minecrell: + Improve the console command completer + + - Fix space after command getting removed when completing a + subcommand together with the command prefix + - Add support for completing without input (shows command list) + - Sort command completion results + - Fix console spamming command prefixes after closing the input stream + bernhard.bonigl: Add shouldRender() to Potions that allows to hide them completely in the inventory + LexManos: Remove MCP reference patches. + LexManos: Fixed colored leather armor, and custom armor textures. + fry: Fixed orientations of generated item faces. Fixes #2215. + fry: Workaround for https://github.com/google/guava/issues/738 + bx9j52xd: Fixed that oldLight is not being used. + LexManos: Fixed ModList GUI rendering incorrectly. Closes #2254 + LexManos: Add EMERALD and SILVERFISH to GenerateMinable event. Closes #1158 + LexManos: Deprecate int IDs in FluidRegistry. Modders should only ever use the String name. Also add a 'friendly' exception when attempting to get an ID for a unregistered fluid. Closes #1374 + LexManos: Fix wrong EventType passed for Emerald ore-gen. + AlgorithmX2: + Added doesSideBlockRendering to provide finer grain face culling. + Implemented for BlockStairs and BlockSlab. + cpw: Use ItemStack.hasEffect. closes #2230 + minzmann: Update PotionEffect.java.patch + cpw: Fix derpage when loading a 1.8 world, with persistent state being entirely ignored in that case. + AlgorithmX2: Add getHighlightTip allowing a item to override its displayed renderToolHightlight. + cpw: + A test for issue #1848. Please try this with any mods you can @ 1.8.8, and see if you still get log spam of any kind (not just the + log message from the issue either). + AlgorithmX2: Added addLandingEffects allowing mods to override landing particles, for blocks that require world information to determine textures. + LexManos: Fix enchanting applying the same enchantment multiple times. Closes #2273 + fry: + Preparations for the Animation system. + Changes to the Model API - IModelState now works with Optional. Handling of parts of the model is not optional, and coordinate space/result interpretation is up to the caller. IModel doesn't extend IModelPart by default anymore; MapModelState uses composition to achieve previous functionality, IModelPart implementations are disjoint now. Updated perspective handing to the new API, removed IPerspectiveState (MapModelState is now the same thing). Perspective transforms for the default fluid model. + fry: IModel can now depend on a variant definition (ModelResourceLocation); added MultiLayerModel - simple model that'll render correctly in multiple layers + example of using it. + fry: Fixed java6 errors in previous commit. + fry: Forge pipeline will now take original model lightmap into account, if present. + fry: Delayed quad list resolution in MultiModel, fixes NPE in MultiLayerModel. + fry: LightUtil.pack and .unpack now work correctly with unpacked arrays of size <4. + fry: Fix dependency resolution for models with custom data/textures. + jadran.kotnik: Fix client side commands adding parts of the color codes on autocomplete (prefix "7" and suffix "r"). + fry: Fixed NPE caused by accessing undefined layer in MultiLayerModel. + bernhard.bonigl: + Add a dynamic bucket model that displays the animated liquid contained + Has a config option (default off) that replaces the vanilla buckets with the forge bucket model + + New original bucket textures from mr_hazard + LexManos: + Fixed registry issues that prevented connecting to 1.8 Forge servers. + More precisely: Servers with missing registries default back to frozen version. + Throw descriptive error if we do not have any information. + LexManos: Fixed vanilla bug related to spawning entities on top of fences. Closes #2303 + cpw: Fix the channel handler naming. It now uses the standard netty namer for it, by careful use of cunning reflection. + cpw: Fix up persistent substitution. Should close #2259 + cpw: + Blocks are no longer erased from the registry if the mod isn't present. This means that modded blocks can potentially retain their IDs + even if they are temporarily not present in the game. Currently TileEntity data associated with the block is erased. + cpw: Try and fix registry NPE when substitution is active. + cpw: Capture ItemBlock remaps. + cpw: Actually use the delegate for the itemblock + cpw: Try and make sure active substitutions are immediately available in the block to item map. + fry: Added an ability to register custom item variants, not ending with "#inventory". Should allow grouping multiple item models into 1 blockstate json. + fry: Fixed random block position offset not applying correctly. + LexManos: Fix Button/Torch/Lever placement on stairs and slabs. Closes #2291 + diesieben07: Allow forge-type spawn-eggs to spawn child entities when clicking EntityAgeable + bernhard.bonigl: Add a hook for custom particle spawning for slimes + bernhard.bonigl: + Fix bucket replacement not loading the bucket model by itself if replacing buckets. + This happens when no other mod that uses the bucket model is present. + Also added a simple method for registering the bucket model, should give + modders an idea on how to use the general model. + +Build 1.8.8-11.15.0.1654-1.8.8: + bernhard.bonigl: + Fix bucket replacement not loading the bucket model by itself if replacing buckets. + This happens when no other mod that uses the bucket model is present. + Also added a simple method for registering the bucket model, should give + modders an idea on how to use the general model. + +Build 1.8.8-11.15.0.1653-1.8.8: + bernhard.bonigl: Add a hook for custom particle spawning for slimes + +Build 1.8.8-11.15.0.1652-1.8.8: + diesieben07: Allow forge-type spawn-eggs to spawn child entities when clicking EntityAgeable + +Build 1.8.8-11.15.0.1651-1.8.8: + LexManos: Fix Button/Torch/Lever placement on stairs and slabs. Closes #2291 + +Build 1.8.8-11.15.0.1650-1.8.8: + fry: Fixed random block position offset not applying correctly. + +Build 1.8.8-11.15.0.1649-1.8.8: + fry: Added an ability to register custom item variants, not ending with "#inventory". Should allow grouping multiple item models into 1 blockstate json. + +Build 1.8.8-11.15.0.1647-1.8.8: + cpw: Try and make sure active substitutions are immediately available in the block to item map. + +Build 1.8.8-11.15.0.1646-1.8.8: + cpw: Actually use the delegate for the itemblock + +Build 1.8.8-11.15.0.1645-1.8.8: + cpw: Capture ItemBlock remaps. + +Build 1.8.8-11.15.0.1644-1.8.8: + cpw: Try and fix registry NPE when substitution is active. + +Build 1.8.8-11.15.0.1643-1.8.8: + cpw: + Blocks are no longer erased from the registry if the mod isn't present. This means that modded blocks can potentially retain their IDs + even if they are temporarily not present in the game. Currently TileEntity data associated with the block is erased. + +Build 1.8.8-11.15.0.1642-1.8.8: + cpw: Fix up persistent substitution. Should close #2259 + +Build 1.8.8-11.15.0.1641-1.8.8: + cpw: Fix the channel handler naming. It now uses the standard netty namer for it, by careful use of cunning reflection. + +Build 1.8.8-11.15.0.1640-1.8.8: + LexManos: Fixed vanilla bug related to spawning entities on top of fences. Closes #2303 + +Build 1.8.8-11.15.0.1639-1.8.8: + LexManos: + Fixed registry issues that prevented connecting to 1.8 Forge servers. + More precisely: Servers with missing registries default back to frozen version. + Throw descriptive error if we do not have any information. + +Build 1.8.8-11.15.0.1638-1.8.8: + bernhard.bonigl: + Add a dynamic bucket model that displays the animated liquid contained + Has a config option (default off) that replaces the vanilla buckets with the forge bucket model + + New original bucket textures from mr_hazard + +Build 1.8.8-11.15.0.1637-1.8.8: + fry: Fixed NPE caused by accessing undefined layer in MultiLayerModel. + +Build 1.8.8-11.15.0.1636-1.8.8: + jadran.kotnik: Fix client side commands adding parts of the color codes on autocomplete (prefix "7" and suffix "r"). + +Build 1.8.8-11.15.0.1635-1.8.8: + fry: Fix dependency resolution for models with custom data/textures. + +Build 1.8.8-11.15.0.1634-1.8.8: + fry: LightUtil.pack and .unpack now work correctly with unpacked arrays of size <4. + +Build 1.8.8-11.15.0.1633-1.8.8: + fry: Delayed quad list resolution in MultiModel, fixes NPE in MultiLayerModel. + +Build 1.8.8-11.15.0.1632-1.8.8: + fry: IModel can now depend on a variant definition (ModelResourceLocation); added MultiLayerModel - simple model that'll render correctly in multiple layers + example of using it. + fry: Fixed java6 errors in previous commit. + fry: Forge pipeline will now take original model lightmap into account, if present. + +Build 1.8.8-11.15.0.1630-1.8.8: + LexManos: Fix enchanting applying the same enchantment multiple times. Closes #2273 + fry: + Preparations for the Animation system. + Changes to the Model API - IModelState now works with Optional. Handling of parts of the model is not optional, and coordinate space/result interpretation is up to the caller. IModel doesn't extend IModelPart by default anymore; MapModelState uses composition to achieve previous functionality, IModelPart implementations are disjoint now. Updated perspective handing to the new API, removed IPerspectiveState (MapModelState is now the same thing). Perspective transforms for the default fluid model. + +Build 1.8.8-11.15.0.1628-1.8.8: + AlgorithmX2: Added addLandingEffects allowing mods to override landing particles, for blocks that require world information to determine textures. + +Build 1.8.8-11.15.0.1627-1.8.8: + AlgorithmX2: Add getHighlightTip allowing a item to override its displayed renderToolHightlight. + +Build 1.8.8-11.15.0.1626-1.8.8: + cpw: + A test for issue #1848. Please try this with any mods you can @ 1.8.8, and see if you still get log spam of any kind (not just the + log message from the issue either). + +Build 1.8.8-11.15.0.1625-1.8.8: + minzmann: Update PotionEffect.java.patch + +Build 1.8.8-11.15.0.1624-1.8.8: + cpw: Fix derpage when loading a 1.8 world, with persistent state being entirely ignored in that case. + +Build 1.8.8-11.15.0.1623-1.8.8: + bernhard.bonigl: Add shouldRender() to Potions that allows to hide them completely in the inventory + +Build 1.8.8-11.15.0.1622-1.8.8: + minecrell: + Improve the console command completer + + - Fix space after command getting removed when completing a + subcommand together with the command prefix + - Add support for completing without input (shows command list) + - Sort command completion results + - Fix console spamming command prefixes after closing the input stream + +Build 1.8.8-11.15.0.1621-1.8.8: + cpw: Use ItemStack.hasEffect. closes #2230 + +Build 1.8.8-11.15.0.1620-1.8.8: + liach: Fix typo in `guava` + +Build 1.8.8-11.15.0.1619-1.8.8: + AlgorithmX2: + Added doesSideBlockRendering to provide finer grain face culling. + Implemented for BlockStairs and BlockSlab. + +Build 1.8.8-11.15.0.1618-1.8.8: + LexManos: Fix wrong EventType passed for Emerald ore-gen. + +Build 1.8.8-11.15.0.1617-1.8.8: + LexManos: Deprecate int IDs in FluidRegistry. Modders should only ever use the String name. Also add a 'friendly' exception when attempting to get an ID for a unregistered fluid. Closes #1374 + +Build 1.8.8-11.15.0.1616-1.8.8: + LexManos: Add EMERALD and SILVERFISH to GenerateMinable event. Closes #1158 + +Build 1.8.8-11.15.0.1615-1.8.8: + LexManos: Fixed ModList GUI rendering incorrectly. Closes #2254 + +Build 1.7.10-10.13.4.1614-1.7.10: + LexManos: Fix dispensers equipping armor on players in the wrong slot Closes #1649 + +Build 1.8.8-11.15.0.1613-1.8.8: + bx9j52xd: Fixed that oldLight is not being used. + +Build 1.8.8-11.15.0.1612-1.8.8: + fry: Workaround for https://github.com/google/guava/issues/738 + +Build 1.8.8-11.15.0.1611-1.8.8: + fry: Fixed orientations of generated item faces. Fixes #2215. + +Build 1.8.8-11.15.0.1610-1.8.8: + LexManos: Remove MCP reference patches. + LexManos: Fixed colored leather armor, and custom armor textures. + +Build 1.8.8-11.15.0.1609-1.8.8: + cpw: Add a flag to the modidremapping event. If the remapevent is because the registry is refreezing, it'll be true. + +Build 1.8.8-11.15.0.1608-1.8.8: + cpw: Clean up chunk patch. + +Build 1.8.8-11.15.0.1607-1.8.8: + mark.a.woodman: + Initialize sources list + + Fixes crash NPE thrown by addFile() + +Build 1.8.8-11.15.0.1606-1.8.8: + cpw: Most requested feature of all time? TileEntity init method called after it's ready to roll. remove all the if (firstTicks) + +Build 1.8.8-11.15.0.1605-1.8.8: + cpw: + Fix language adapter loading. + + The language adapter is now properly picked up after the mod is loaded + on the classpath, fixing the ClassNotFoundException occurring before. + Also fixed some minor formatting and made it throw a full + RuntimeException on failure. + + Fix up some formatting + +Build 1.8.8-11.15.0.1604-1.8.8: + cpw: Be noisy when API is in a coremod. It'll never work and modders should realize that fact. + +Build 1.8.8-11.15.0.1603-1.8.8: + mezz: Allow server to access Potion isBadEffect() + +Build 1.8.8-11.15.0.1602-1.8.8: + kashike: Use the FMLSecurityManager checkPermission(Permission) method for context-based permission checks. Fixes #2067 + +Build 1.8.8-11.15.0.1601-1.8.8: + cpw: Allow entity selectors to select "." in entity names. Closes #2125 + +Build 1.8.8-11.15.0.1600-1.8.8: + minecrell: Add jline-based console with colors and tab-completion + bernhard.bonigl: Add a PotionRegistry to handle dynamic distribution and remapping of Potion IDs + cpw: Some tweaks - GameRegistry is modder facing API, so avoid having MC methods there. Fix a couple of registry bugs. + cpw: Fixup Jline integration + cpw: A few fixes + +Build 1.8.8-11.15.0.1596-1.8.8: + cpw: Fix problem with spam from registry on loading a second world. Empty the staging. + +Build 1.8.8-11.15.0.1595-1.8.8: + lumien231: Fixed: The Integrated Server not being stopped when exiting a singleplayer world to the main menu + +Build 1.8.8-11.15.0.1594-1.8.8: + LexManos: Add chunk loading protection to WorldSever.getTileEntitiesIn, may prevent orphanced chunks and a CME in EntityPlayerMP. Note: The 'max' parameters are NON-inclusive. + cpw: Fix up blockstate rebuild. Closes #2221. Also fix formatting. IDEA has differences. Solved now. + +Build 1.8.8-11.15.0.1592-1.8.8: + cpw: Giant registry fixup + +Build 1.8.8-11.15.0.1591-1.8.8: + LexManos: Bump version for new Minecraft version. + LexManos: Fixed placing blocks on snow layers with more then one layer. + LexManos: Fixed Large mushrooms generating incorrectly. + LexManos: Removed IItemRenderer class, all functionality is possible with new rendering system. + LexManos: Compiler warnings pass, undeprecated SplashProgress related stuff. + +Build 1.8.8-11.14.4.1590-1.8.8: + cpw: Propogate AbortException. Closes #2206. Also fix tracing printstream when printStackTrace is called. + +Build 1.8.8-11.14.4.1589-1.8.8: + cpw: Fix up a couple of patches, affected by the recent update + cpw: + Add .exc for StatList patch + + More tweaking + +Build 1.8.8-11.14.4.1588-1.8.8: + cpw: Fix button and lever placement problem. Closes #2204 + +Build 1.8.8-11.14.4.1587-1.8.8: + lordillyohs: + Remove trailing */ in the build.gradle + + Signed-off-by: Anthony Anderson + +Build 1.8.8-11.14.4.1586-1.8.8: + cpw: Cleaning up some derpy names + cpw: More cleanups, some documentation, a bunch of deprecations. + +Build 1.8.8-11.14.4.1585-1.8.8: + cpw: Deprecate it as well, because hey, it's redundant now. + cpw: Clean up some very long dead code. Bukkit hasn't existed in a very long time now. IASM never worked, and I'm not about to implement it. + +Build 1.8.8-11.14.4.1584-1.8.8: + cpw: ONE EVENT BUS TO RULE THEM ALL AND IN THE DARKNESS FIRE THEM! + +Build 1.8.8-11.14.4.1583-1.8.8: + cpw: Fix MDK for 1.8.8 using FG2.1 snapshot + cpw: Yeah, amount is NOT deprecated. + +Build 1.8.8-11.14.4.1582-1.8.8: + cpw: + OMG! Documentation? WUT? I haz lost my mind. + Also, Functional interface for IMC. Senders can send a classname implementing Guava's function, and receivers + will be able to get that function, and do, well, whatever, really. Probably best for those callback type + scenarios, connecting up APIs and stuffs. + +Build 1.8.8-11.14.4.1581-1.8.8: + cpw: Cleanup Fluid deprecations stuff. + +Build 1.8.8-11.14.4.1580-1.8.8: + LexManos: Update universal manifest for 1.8.8's json. + +Build 1.8.8-11.14.4.1579-1.8.8: + fry: Fixed NPE is B3D loader caused by the missing vertex normal; updated the example chest model - it's now has 2 meshes; Updated ModelAnimationDebug - it now uses the new chest model, renders the base with the static world renderer, and only the lid with the TESR. + LexManos: Fix incorrect position passes to Block.getExplosionResistance from entities. + LexManos: Moved client side Block.onBlockDestroyed to after Item.onBlockDestroyed to match server order. + LexManos: Enable the normal ModList GUI in game. Use GL_SCISSOR to support the transparent in-game GUI. + Choonster.2010: BiomeManager: Fix off-by-one errors + LexManos: Fix bold font rendering, Unicode is 2x pixel density of normal. + LexManos: Fix invalid position passed to isAir/getLight in World.playAmbientSound + fry: Fixed forge lighting working incorrectly outside 0x1000000 coordinates. + fry: Implemented interpolation of TRSR transformations; B3D: added interpolation capabilities to B3DState, animated TESR example in ModelAnimationTest (pure TESR right now, no separation inside the example model between the static and dynamic parts right now). + fry: B3D loader: removed 2 redundand null checks, changed constructor args to final to fix (java6?) inner arg error. + fry: Fix holes in generated item models. + fry: Removed face doubles from item models. + fry: Fixed forge lighting working incorrectly outside 0x1000000 coordinates. + cpw: Update mappings to 20151122. + +Build 1.8-11.14.4.1577: + fry: Implemented interpolation of TRSR transformations; B3D: added interpolation capabilities to B3DState, animated TESR example in ModelAnimationTest (pure TESR right now, no separation inside the example model between the static and dynamic parts right now). + fry: B3D loader: removed 2 redundand null checks, changed constructor args to final to fix (java6?) inner arg error. + fry: Fix holes in generated item models. + fry: Removed face doubles from item models. + fry: Fixed forge lighting working incorrectly outside 0x1000000 coordinates. + +Build 1.8.8-11.14.4.1576-1.8.8: + cpw: Fix derpy fir trees in the taiga. So many patches. See if we can find any more mistakes?! + +Build 1.8.8-11.14.4.1575-1.8.8: + cpw: Small tweak to the OUT/ERR logger - should skip the Throwable stuffs now. + cpw: + Fix weird patch issue where the this FG commit: https://github.com/MinecraftForge/ForgeGradle/commit/2f0ca9921b961133689d29b807333241010a802d + breaks if the exact end of a line is a srgname. Not ideal, but should work. + +Build 1.8-11.14.4.1572: + LexManos: Fix invalid position passed to isAir/getLight in World.playAmbientSound + +Build 1.8-11.14.4.1571: + Choonster.2010: BiomeManager: Fix off-by-one errors + +Build 1.8-11.14.4.1570: + LexManos: Fix bold font rendering, Unicode is 2x pixel density of normal. + +Build 1.8-11.14.4.1569: + LexManos: Enable the normal ModList GUI in game. Use GL_SCISSOR to support the transparent in-game GUI. + +Build 1.8-11.14.4.1568: + LexManos: Fix incorrect position passes to Block.getExplosionResistance from entities. + LexManos: Moved client side Block.onBlockDestroyed to after Item.onBlockDestroyed to match server order. + +Build 1.7.10-10.13.4.1566-1.7.10: + scott: Add an event hook to allow overriding of fuels recognized by vanilla fuel handling. + +Build 1.8-11.14.4.1565: + lumien231: Fix Client Login Issue when logging into a non existent dimension + +Build 1.7.10-10.13.4.1564-1.7.10: + LexManos: Fixed skulls not placing on fences like vanilla {Vanilla is buggy -.-} Closes #2185 + +Build 1.8-11.14.4.1563: + LexManos: Bump version for Recomended Build. + +Build 1.8-11.14.3.1562: + LexManos: + Merge pull request #2179 from arideus101/patch-1 + + Fixed issue where custom colored armor wouldn't be colored. (reverted from commit dee0b2084b519419bbf97d8ad177204830ea2b07) + +Build 1.8-11.14.3.1561: + jasondoyle528: Allows Custom Armor Coloring to be done easily + +Build 1.8-11.14.3.1560: + gabizou: + Fix a possible NPE when checking supertypes of interfaces. Closes #2176. + + Signed-off-by: Gabriel Harris-Rouquette + +Build 1.8-11.14.3.1559: + bjoern: + Fix possible crash in EventBus + + There is currently no way to check if an event handler has been registered or not. + But when trying to unregister a not-registered event handler, Minecraft crashes with a NullPointerException. + This is a simple fix to prevent such crashes. + cpw: Fix substitutions for recipes and oredict recipes. Should mean that substitutions start working properly. + cpw: + OreDictionary will warn if there's an invalid ore being registered now, rather than just + using -1 and doing weird things with the list as a result. + cpw: Two more corner cases in the oredictionary. Should work for all cases now. + cpw: + Fix firing the remap event. It always fires now, and additionally fires when the registry reverts to frozen. + Most mods refer to the gameregistry for ids they care about, so this shouldn't affect anything significantly, + but if your mod was dependent on their being content in the remap event, and only acting on that content, + empty content means it's "reverted to frozen" state - the state at the start of the game. + +Build 1.7.10-10.13.4.1558-1.7.10: + cpw: + Fix firing the remap event. It always fires now, and additionally fires when the registry reverts to frozen. + Most mods refer to the gameregistry for ids they care about, so this shouldn't affect anything significantly, + but if your mod was dependent on their being content in the remap event, and only acting on that content, + empty content means it's "reverted to frozen" state - the state at the start of the game. + +Build 1.7.10-10.13.4.1557-1.7.10: + cpw: Two more corner cases in the oredictionary. Should work for all cases now. + +Build 1.8-11.14.3.1556: + LexManos: Fixed Open url confirm screen not showing URL. + LexManos: Fixed Stronghold Library not having anything in it's chests. + +Build 1.8-11.14.3.1555: + diesieben07: Fix GameData.findBlock + +Build 1.8-11.14.3.1554: + fry: Fixed anaglyph transformation not being applied in the forge lighting fully. + +Build 1.8-11.14.3.1553: + fry: Provide ItemCameraTransforms for vanilla models when possible. + +Build 1.8-11.14.3.1552: + fry: OBJ loader: reworked texture resolution: keys now have to start with #, like every other model loader; models without explicit library now work, remapping is possible by using the key "#OBJModel.Default.Texture.Name"; in addition to remapping by material name, remapping by texture name works too, like in other model formats. + +Build 1.8-11.14.3.1551: + fry: Performace fix for item rendering. + +Build 1.8-11.14.3.1550: + Choonster.2010: + Fix texture error message for broken textures + + -- Fixes #2100 + -- Iterates over badTextureDomains instead of missingTextures.keySet() + as a domain can have broken textures without any missing textures + +Build 1.8-11.14.3.1549: + fry: Obj loader: fix vertices shared between faces having the same attributed (uvs/normals). + the.f1repl4ce: Fixed a bug that caused the config option name to overlap with the selectable values when using GuiConfigEntries.SelectValueEntry, fixes #2114 + fry: OBJ model: use original vertex material when defining face. + fry: Fixed block color multiplier not being cached properly in the forge renderer, performance improvement. + LexManos: Merge FML and Forge lang file, and update crowdin project. + LexManos: + Redesign the ModList GUI to use a scrolling list for the main body content. + Allowing for larger information to be displayed. + URLs are auto-detected and now clickable. + Mod Logos are now centered, it looks better. + LexManos: + Introduce a new centralized version checking system. + Using the @Mod annotation mods can opt-in to a centrally controlled update system. + This is PURELY a notification system and will NOT automatically download any updates. + The End User can control which mods check for updates and disabel the system entirely using the Forge Config and GUI. + Format for the json the URL must point to is described here: https://gist.github.com/LexManos/7aacb9aa991330523884 + +Build 1.8-11.14.3.1543: + fry: Fix color multiplier applied incorrectly for items. + fry: OBJ loader: fixed another whitespace-related issue; removed unused "modifyUVs" property for now; added the "flip-v" property to switch between OpenGL-style and DirextX-style model UVs; fixed normals - they are now correct in-world, still a bit strange for the items; fixed normals a little bit for B3D models too. + +Build 1.7.10-10.13.4.1541-1.7.10: + cpw: + OreDictionary will warn if there's an invalid ore being registered now, rather than just + using -1 and doing weird things with the list as a result. + +Build 1.7.10-10.13.4.1539-1.7.10: + diesieben07: Fix CME when entities are spawned from EntityJoinWorldEvent + bernhard.bonigl: Fix Potion IDs above 127 + Abrar Syed: Update FG version to 2.0.2 + fry: Changed how the forge lighting system handles holey models for opaque blocks; it now mimics vanilla behaviour, which allows light to pass through them. + fry: Fix for the previous commit - transparent blocks were handled improperly. + glstillman: OBJLoader: Quick bandages to support/fix the new way that face/vertex normals are calculated, a very quick bandage to patch TextureCoordinates for the time being, and the Parser now uses a Pattern to split strings on whitespace instead of only splitting on " ". + cpw: Fix substitutions for recipes and oredict recipes. Should mean that substitutions start working properly. + +Build 1.8-11.14.3.1532: + fry: Fixed normal calculation for vanilla models, fixed the grass darkening and simular issues. + fry: More lighting fixes, flat lighting now works correctly for grass and torches. + +Build 1.8-11.14.3.1530: + fry: Fixed piston rendering (WorldRenderer offset wasn't applied); fixed TESR being registered too early in one of the debug mods. + +Build 1.8-11.14.3.1529: + glstillman: Fixed a bug with item model loading that would occur if ModelBakery.addVariantName() was called with the same string location parameter for 2 different items, and the string pointed to a location that didn't exist, where ModelLoader.loadAnyModel() would substitute the blockdefinition in for the item model, but wouldn't remove the original input location from the loadingModels list, which would cause the location from the second call to throw an IllegalStateException even though that location now has a model. + fry: + Perspective awareness for vanilla and multi models, fixes #2148. + Improved error handling in MultiModel. + fry: Fixed generic bug in MultiModel + fry: Fixed AO being applied to OBJ model transparency, and OBJ loader trying to force the loading of the builtin white texture. + fry: Provide a IModel for "builtin/generated", fixes #2147 + fry: Fixed another generic issue in MultiModel. + +Build 1.8-11.14.3.1525: + fry: Small fix for reworked classic lighting + +Build 1.8-11.14.3.1524: + fry: Added OBJ loader for the ModelLoaderRegistry system. + +Build 1.8-11.14.3.1523: + fry: + Model pipeline system. + Should replace all ad-hoc quad generation methods in forge, and make IBakedModel -> WorldRenderer data transfer faster. Added IVertexConsumer + helper classes; lighting that works correctly for non-axis-aligned faces using the new infrastructure. Changed smooth lighting algorithm, now it should work correctly for everything. + New block lighter can be disabled in the forge config options. + fry: Added back in the lost class + +Build 1.8-11.14.3.1521: + simonbarnes1: + Add Guava and Apache to LaunchClassLoader exclusion list on server + + Move exclusions to common place. Less likely to get out of sync + +Build 1.8-11.14.3.1520: + bk1325: Add PlayerSetSpawnEvent + +Build 1.8-11.14.3.1519: + fry: '#' is now added automatically to the beginning of the texture names in B3D models, and the remapping is expected via the blockstate JSON, since it's more reasonable than adding it to the file name in the modelling program or matching the resource location with the filename. + +Build 1.8-11.14.3.1518: + fry: Fixes Attributes.transform affecting only 1 vertex. + +Build 1.7.10-10.13.4.1517-1.7.10: + bjoern: + Fix possible crash in EventBus + + There is currently no way to check if an event handler has been registered or not. + But when trying to unregister a not-registered event handler, Minecraft crashes with a NullPointerException. + This is a simple fix to prevent such crashes. + +Build 1.8-11.14.3.1516: + luacs1998: Fix a possible crash in EventBus + +Build 1.8-11.14.3.1515: + rubensworks: Fix dispenser action for modded spawn eggs + +Build 1.8-11.14.3.1514: + LexManos: Update Gradle wrapper to 2.7 + LexManos: Fix entity count being incorrect for spawning logic. Now filter out 'persistant' entities. + +Build 1.8-11.14.3.1513: + foka_12: Disallow conflicting furnace recipes + +Build 1.8-11.14.3.1512: + fry: Workaround for MinecraftForge/ForgeGradle#256 + +Build 1.8-11.14.3.1511: + cpw: + FMLNetworkHandler.openGui should not try and open a GUI on a FakePlayer. + Fixes #2082 and probably dozens of mod errors. Also, side benefit of the + merged codebase! FML code can ref Forge code! + +Build 1.8-11.14.3.1510: + laci200270: Update FMLSecurityManager.java + cpw: Format a bit better + +Build 1.8-11.14.3.1509: + fry: Much requested temporary hack for items and TESRs. Context: #1582, #1597, #1713, #2058 and others. + +Build 1.8-11.14.3.1508: + vorquel: Fix faulty Channel name + +Build 1.8-11.14.3.1507: + simonbarnes1: Use already provided profile for the player's own skin + +Build 1.8-11.14.3.1506: + cpw: + More cleanup of the default eclipse workspace. The project is now called "MDKExample" not "Minecraft". + The project tree is now contemporary, instead of a copy from 1.5.x era MC. The launches are cleaned up, and refer to + a better default "runDir" of "run" rather than "eclipse".. Updating to FG2.0.1 which will contain relevant binary fixes. + +Build 1.8-11.14.3.1505: + cpw: Fix eclipse workspace inside the mdk - don't run it through the tokenconverter. Also add in CREDITS-fml.txt to the MDK - it's still required. + +Build 1.8-11.14.3.1504: + LexManos: + Fixed issue where config folder would not be created before SplashProgress tried to read from it. + Default macs to disable the new loading screen due to to many macs having issues. + Users can enable it again by editing their config. + Catch and gracefully handle more errors when starting up the Splash Screen. + +Build 1.8-11.14.3.1503: + diesieben07: Re-introduce RenderBlockOverlayEvent, seems to have been missed during 1.8 update + Abrar Syed: removed broken and duplicate AT lines + Abrar Syed: added hardcoded fml version file + Abrar Syed: DeobfuscationData no longer required at dev time + Abrar Syed: removed old unnecessary stuff + Abrar Syed: Added FG2 buildscript + updated for Gradle 2.4 + Abrar Syed: added jenkins compat tasks + Abrar Syed: fixed local-building fail with changelog + Abrar Syed: updated installed gradle. not finished + Abrar Syed: fixed deployment credentials + cpw: FML is no more. FML has ceased to be. FML's expired and gone to meet its maker. FML's a stiff! Bereft of life, FML rests in peace. + cpw: Vestigal fml-ectomy. + cpw: + FML's metabolic processes are now history. FML's off the twig. FML's kicked the bucket, FML's shuffled off this mortal coil, + run down the curtain and joined the bleedin' choir invisible!! THIS IS AN EX-PROJECT! + Abrar Syed: added MDK package + cpw: Fix MDK task - it now runs. + cpw: The final nail in the coffin. BYE! + cpw: + Trying to fix the MDK to include gradle wrapper, but the gradle-wrapper.jar is + corrupted. @AbrarSyed can you take a look? + cpw: + Fix packaging the gradle wrapper properly. There is still a problem with + the MDK- it fails to run setupDecompWorkspace. + + Filed an issue at ForgeGradle, since this seems to be something FG2 shouldn't + be doing, but is? + + https://github.com/MinecraftForge/ForgeGradle/issues/235 + cpw: Remove patches + cpw: Fix ciWriteBuildNumber task. Ugly, but it works. + cpw: Fix crowdin task. Good luck jenkins, lets roll! + cpw: Fix crowdin again. Run, jenkins, for god's sake, run! + LexManos: Update gradle wrapper and fix changelog task. + +Build 1.8-11.14.3.1502: + cpw: ObjectHolder works great, but it should be a lot less spammy about failed lookups. They're usually mod options. + cpw: Actually rebuild the fluidNames each rebuild, don't just try and force changes in. Should fix #1973 + cpw: + Wake up the FluidRegistry before any mods start loading. Should stop mods claiming to own water or lava (depending on who accessed + FluidRegistry first) + cpw: Be a little bit more helpful when the ObjectHolder misses. Should help figure out what is going in in #2006 + cpw: Cherry pick some changes from 1.8 for inner class discovery, also fix the negativecache. Closes #1872 + +Build 1.8-11.14.3.1501: + LexManos: Fix placing skulls on fence posts. Closes #2055 + +Build 1.8-11.14.3.1500: + starbuck: Fix harvest logic running in addition to shearable logic + +Build 1.8-11.14.3.1499: + glstillman: Fixed a bug with ExtendedBlockStates containing at least one IProperty and one IUnlistedProperty not allowing blocks to be placed. + +Build 1.8-11.14.3.1498: + liach: Add an EnumHelper hook and fixed an issue + +Build 1.8-11.14.3.1497: + simonbarnes1: Fix placing signs with NBT prompting for text + +Build 1.8-11.14.3.1496: + Zaggy1024: + Fixed a Forge blockstates json removing models causing an NPE in the loader. + Fixed the deep clone of a V1 Variant not cloning the submodels properly. + +Build 1.8-11.14.3.1495: + clienthax: Signed-off-by: Clienthax + +Build 1.8-11.14.3.1494: + rubensworks: Make EnumFacing events available server-side + +Build 1.8-11.14.3.1493: + rubensworks: Fix source block check for BlockFluidClassic + +Build 1.7.10-10.13.4.1492-1.7.10: + cpw: Cherry pick some changes from 1.8 for inner class discovery, also fix the negativecache. Closes #1872 + +Build 1.8-11.14.3.1491: + diesieben07: Allow the new entity eggs to be created via middle-click + +Build 1.7.10-10.13.4.1490-1.7.10: + cpw: Actually rebuild the fluidNames each rebuild, don't just try and force changes in. Should fix #1973 + cpw: + Wake up the FluidRegistry before any mods start loading. Should stop mods claiming to own water or lava (depending on who accessed + FluidRegistry first) + cpw: Be a little bit more helpful when the ObjectHolder misses. Should help figure out what is going in in #2006 + +Build 1.8-11.14.3.1487: + fry: Custom transformations in forge blockstate json. + +Build 1.8-11.14.3.1486: + LexManos: Fixed ItemMonsterPlacer.getEggInfo missing return. Closes #1975 + +Build 1.8-11.14.3.1485: + jadran.kotnik: Fixed error GUIs showing a white screen and replaced a rogue direct GL call. + +Build 1.8-11.14.3.1484: + izooDee5: Fix particle texture of the generated item models. + +Build 1.8-11.14.3.1483: + bernhard.bonigl: Fix StateMap always mapping properties to the "minecraft" domain instead of the mods, causing it to not find BlockState definitions. + +Build 1.8-11.14.3.1482: + LexManos: Add debug for max texture size and output when Texture Atlas can not stitch all textures. + +Build 1.7.10-10.13.4.1481-1.7.10: + cpw: ObjectHolder works great, but it should be a lot less spammy about failed lookups. They're usually mod options. + +Build 1.8-11.14.3.1480: + LexManos: More descripotive error if Patcher is passed invalid data for vanilla classes. + +Build 1.8-11.14.3.1479: + fry: Fixed perspective transformations for item models. + fry: Vanilla models can now use custom textures. Fixes #1962 + fry: There's no Map.getOrDefault in java6. + +Build 1.8-11.14.3.1476: + LexManos: Fix AT for Block constructor. + +Build 1.8-11.14.3.1475: + fry: Added ItemLayerModel - less awkward, simpler and faster version of ItemModelGenerator. + +Build 1.8-11.14.3.1474: + LexManos: Throw more descriptive errors when mods attempt to register invalid global entity IDs. + LexManos: Include the thread state in the potential error handleing for SplashProgress. + LexManos: Fixed Wavefront Object Importer reading files with integer values. Closes #1651, #1654 + LexManos: Create config folder in SplashProgress if it does not exist. + LexManos: Add the stitching allocation stage to loading screen. + LexManos: + Make TextureMap for items and blocks skip the first pass of loading/stitching textures. + Should decrease loading times for large packs. + May cause issues with some mods so use -Dfml.skipFirstTextureLoad=false to disable. + LexManos: Add TextureManager to loading screen. + LexManos: Time each bar in the loading screen and print it to the log, useful information to see where most time is spent in loading. + cpw: + Mods that are extracted to the mods dir by unzipping or whatever will now cause the game to crash. Too much info is in the META-INF now, + and more will be being added. Extracting to the mods dir just completely breaks that. + +Build 1.8-11.14.3.1473: + jamioflan: + Added CameraSetup sub-event for camera angles + + Allows players to alter yaw and pitch of renderViewEntity, but more importantly, adds the ability to roll the view. + + Added camera roll hook + +Build 1.7.10-10.13.4.1472-1.7.10: + michafla: fix logic for guessing mesa tag in biome dict + cpw: + Mods that are extracted to the mods dir by unzipping or whatever will now cause the game to crash. Too much info is in the META-INF now, + and more will be being added. Extracting to the mods dir just completely breaks that. + +Build 1.7.10-10.13.4.1470-1.7.10: + LexManos: Add TextureManager to loading screen. + LexManos: Time each bar in the loading screen and print it to the log, useful information to see where most time is spent in loading. + +Build 1.7.10-10.13.4.1469-1.7.10: + LexManos: Create config folder in SplashProgress if it does not exist. + LexManos: Add the stitching allocation stage to loading screen. + LexManos: + Make TextureMap for items and blocks skip the first pass of loading/stitching textures. + Should decrease loading times for large packs. + May cause issues with some mods so use -Dfml.skipFirstTextureLoad=false to disable. + +Build 1.8-11.14.3.1468: + LexManos: Patch line number update. Ignore this. + LexManos: + New system in EntityRegistry to allow modders to register spawn eggs. + For entites that do not use the global ID system. + {Which no mod entity should} + Vanilla spawn eggs will now detect a 'entity_name' entry in it's NBT data and use that for spawning/rendering. + +Build 1.8-11.14.3.1467: + foka_12: Change permission levels on ore recipes parameters + +Build 1.8-11.14.3.1466: + foka_12: + Fixed NPE when calling canBrew + + Oversight on my part, + + If the ingredient doesn't return true in Item.isPotionIngredient, Items.potionitem.getEffects(stack) returns null, causing an NPE to be thrown later on. + + This invalidates #1947. + +Build 1.8-11.14.3.1465: + LexManos: Use Guava instead of Nio for J6 compatibility. + +Build 1.8-11.14.3.1464: + fry: Added fluid renderer. + +Build 1.8-11.14.3.1463: + LexManos: Make Item.shouldCauseReequipAnimation is bit more precise and copy over the new item for rendering even if the animation is diabled. + +Build 1.8-11.14.3.1462: + LexManos: Add vanilla block rotation support back in for certain blocks that were missed in 1.8 update. Closes #1903 + +Build 1.8-11.14.3.1461: + xxmicloxx: Bugfix for B3DLoader + +Build 1.8-11.14.3.1460: + Daniel: + Fix incorrect block position in BlockReed canPlaceBlockAt + + block.canSustainPlant is called on the wrong block position. It should be called on the block below (the 'soil' block). + +Build 1.8-11.14.3.1459: + mezz: Add GuiScreenEvents for keyboard and mouse input + +Build 1.8-11.14.3.1458: + t.tomkins: + Player sensitive version of Block.getPickBlock + + Block.getPickBlock was patched in 1.7 but was overlooked in 1.8. + + Closes: https://github.com/MinecraftForge/MinecraftForge/issues/1709 + LexManos: Add Item.shouldCauseReequipAnimation to allow modders more control over the 'Reequip' animation. + +Build 1.8-11.14.3.1457: + LexManos: Fixed compile issues with irtimaled's PR. + +Build 1.7.10-10.13.4.1456-1.7.10: + irtimaled: + Copy fortress.dat from vanilla location + + Fixes #1747 + + If the dat file isn't in the dimension specific folder but is present in the vanilla data folder then copy it over. + LexManos: Make FML Gui classes use GlStateManager. Closes FML#615 + LexManos: Fixed Wavefront Object Importer reading files with integer values. Closes #1651, #1654 + +Build 1.8-11.14.3.1453: + LexManos: Cleanup code format in LayerBreakingTest. + LexManos: Fixup model loading errors not being printed by making ICustomModelLoader.loadModel propogate IOExceptions as needed. + +Build 1.7.10-10.13.4.1452-1.7.10: + LexManos: Include the thread state in the potential error handleing for SplashProgress. + +Build 1.7.10-10.13.4.1451-1.7.10: + LexManos: Throw more descriptive errors when mods attempt to register invalid global entity IDs. + +Build 1.8-11.14.3.1450: + LexManos: Bump version for new RB. + LexManos: Cleanup some spammy output. + LexManos: Quiet ClassPatchManager debug spam by default. Reenable using -Dfml.debugClassPatchManager=true. + LexManos: Quiet FMLControlledNamespacedRegistry debug spam by default. Reenable using -Dfml.debugRegistryEntries=true. + LexManos: Quiet CrashReport class pre-loading debug, no flag to re-enable. + LexManos: Cleanup mod signature data table. Easily seperating those mods with signatures vs those with none. + LexManos: Cleanup mod state dump to be easier to read by displaying the states in abreviation and placing them before the mod info. + +Build 1.8-11.14.3.1449: + clarsson: Fixing two IndexOutBoundsExceptions from the BiomeDictionary + +Build 1.7.10-10.13.4.1448-1.7.10: + LexManos: Cleanup mod state dump to be easier to read by displaying the states in abreviation and placing them before the mod info. + +Build 1.7.10-10.13.4.1447-1.7.10: + LexManos: Cleanup some spammy output. + LexManos: Quiet ClassPatchManager debug spam by default. Reenable using -Dfml.debugClassPatchManager=true. + LexManos: Quiet FMLControlledNamespacedRegistry debug spam by default. Reenable using -Dfml.debugRegistryEntries=true. + LexManos: Quiet CrashReport class pre-loading debug, no flag to re-enable. + LexManos: Cleanup mod signature data table. Easily seperating those mods with signatures vs those with none. + +Build 1.8-11.14.3.1446: + LexManos: Copy over parent's modelSet value in variants as well. + LexManos: Bump version for new RB + +Build 1.7.10-10.13.4.1445-1.7.10: + LexManos: Bump version for new RB. + +Build 1.8-11.14.2.1444: + cpw: + Fix up the client/server fluid race condition that could cause the game to bail when an SSP game connects. + There's still a teeny gap, but it's MUCH less prominent than it was before. + +Build 1.8-11.14.2.1443: + lumien231: Added LivingExperienceDropsEvent to change the amount of experience an entity drops + +Build 1.8-11.14.2.1442: + jcoleman350: Added ItemMap type check to item frames and ItemRenderer, enabling vanilla style rendering for custom maps + +Build 1.8-11.14.2.1441: + LexManos: Redefine removal value in IRetextureableModel from null to empty string {""} due to ImmutibleMap not allowing null Values. Closes #1927 + +Build 1.8-11.14.2.1440: + foka_12: Added a brewing registry system + +Build 1.8-11.14.2.1439: + LexManos: Limit Sign text to 384 json characters and strip control codes. This is 1.8.7's Sign fix. Thanks Searge. + LexManos: Remove worlds from WorldBorder when unloaded tol prevent memory leak, Closes #1923 + LexManos: Missed patch for sign fix. + +Build 1.8-11.14.2.1437: + cpw: + Attempt to synchronize the state for vanilla client completions and quit the handler if the vanilla + thread has already setup the connection. Should fix #1924 + +Build 1.8-11.14.2.1436: + LexManos: Change custom payload lock to be buffer itself incase multiple packets use the same backend buffer. Closes #1908 + +Build 1.8-11.14.2.1435: + Fuami.cake: + Added Breaking Animation for Smart Models, Checking each layer. + Added Layered Smart Render Test. + +Build 1.8-11.14.2.1434: + LexManos: Update README.txt + +Build 1.8-11.14.2.1433: + fry: Fixed missing variant logging; added the possibility to specify the item variant in the blockstate json. + fry: fixed AT missing for getModelBlockDefinition + fry: + B3D Improvements + - fixed keyframe transformation application + - textures are now resolved the same way as in vanilla models + - added the ability to use forge blockstate texture information + - removed unused code from the B3D example + +Build 1.8-11.14.2.1431: + fry: Fixed partial variant detection in the forge blockstate loader. + +Build 1.8-11.14.2.1430: + LexManos: Mitigate potential issue with users requesting lots of server status information by caching ServerStatus json. + +Build 1.8-11.14.2.1429: + clienthax: + Add missing forge patch from 1.8 port + https://github.com/MinecraftForge/MinecraftForge/blob/1.7.10/patches/minecraft/net/minecraft/client/Minecraft.java.patch#L88 + +Build 1.7.10-10.13.3.1428-1.7.10: + cpw: + Fix up the client/server fluid race condition that could cause the game to bail when an SSP game connects. + There's still a teeny gap, but it's MUCH less prominent than it was before. + +Build 1.8-11.14.2.1427: + LexManos: + Hook BlockState's Json loading to add support for simplified Forge format. + See https://github.com/MinecraftForge/MinecraftForge/pull/1885 for more details. + +Build 1.8-11.14.2.1426: + cpw: + Attempt to disable the new splash screen if there are errors detected finishing up. Print a slightly more helpful error message. + + (cherry picked from commit e3211eec0469dc6717943010d584207b7abdb1e0) + + Conflicts: + fml/src/main/java/cpw/mods/fml/client/SplashProgress.java + cpw: + Finish loading screen before going fullscreen. Closes MinecraftForge/FML#662 + + (cherry picked from commit 19d7e16fa6a28c5665de1ed6e50d8699e865bff2) + + Conflicts: + fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch + cpw: So we can't print a lot of unicode in the splash screen, so restrict to a hard subset we know we CAN print, closes #1910 + LexManos: Fixed missing import in last merge. + +Build 1.7.10-10.13.3.1424-1.7.10: + cpw: So we can't print a lot of unicode in the splash screen, so restrict to a hard subset we know we CAN print, closes #1910 + +Build 1.8-11.14.2.1423: + AlgorithmX2: Allow placing item frames on Solid Block Faces (isSideSolid) + +Build 1.7.10-10.13.3.1422-1.7.10: + cpw: + Attempt to disable the new splash screen if there are errors detected finishing up. Print a slightly more helpful error message. + + (cherry picked from commit e3211eec0469dc6717943010d584207b7abdb1e0) + + Conflicts: + fml/src/main/java/cpw/mods/fml/client/SplashProgress.java + cpw: + Finish loading screen before going fullscreen. Closes MinecraftForge/FML#662 + + (cherry picked from commit 19d7e16fa6a28c5665de1ed6e50d8699e865bff2) + + Conflicts: + fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch + +Build 1.8-11.14.2.1421: + cpw: + MinecraftForge/FML@12ccf9cf49b76140841cdc5a459422ae4781de1a Rather than try to fall back to the backup level.dat in case of weirdness in the ID map, just fail hard. There is probably a serious modder derp in this case and there's nothing FML can do to recover the situation except avoid making it worse. + MinecraftForge/FML@e8cd368da30661ed2898fff232e2db787edcbdcc It's an IllegalState not an IllegalArgument *sigh* + MinecraftForge/FML@2be9c743424c92f8799a6af1d59d60edd65e6bf0 And fix itemblocks being removed, leaving behind a residual block. This is a legitimate action - use the missing mapping event to let the mod tell us about it + MinecraftForge/FML@7d8804cf656081d1570068f52e9bfc7140b21a65 You can't setAction to BLOCKONLY + MinecraftForge/FML@c73861efe67594ee9995bc93744cab06bd6647d1 Cherry-pick 01aaa7dc97480b381ca0d192ec65016d7baeb747 Fix mods defined via --mods or --modListFile launch args not being searched for coremods. #560 + MinecraftForge/FML@94c45b48c1265e7c4f60f591d413fa545787d354 Fix json cache crash, handle the file much more cleanly. Probably an MC JIRA since it's a vanilla bug. Closes #619 + cpw: + Forge really should have always supported the concept of an "exact spawn". Individual world providers can still + change this behaviour of course, but for default maps it makes sense to support it as a config option. + cpw: + Removed fluidID from ItemStack. + + This fixes a rather huge issue where FluidStacks on the client could be desynced if a modder was unaware of it. + + This is a breaking change but can be mitigated with a transformer to the getter getFluidID(). + + Signed-off-by: King Lemming + cpw: Add in a fluidid transformer + cpw: Fix formatting + cpw: + Allow for duplicate Fluid Blocks. It's annoying to be sure but just as with the OreDictionary, we'll have to handle it. + + Signed-off-by: King Lemming + cpw: + You shouldn't be creating FluidStacks from unregistered Fluids. Warn clearly on failed registrations, and make a useful log message for failed fluidstack + creations. Should help a lot with tracking down broken mods that are doing this wrongly. + LexManos: MinecraftForge/FML@31cf2a9cab6d1977d31436220d9612eaa13d4e0f Remove J7 only constructor in EnhancedRuntimeException, J6 compiling compatibility restored. + LexManos: Restore binary compatibility issues in FluidRegistry caused by recent changes. + me: + Fix FluidRegsitry.registerFluid + + FluidRegistry: + ```java + static BiMap fluids = HashBiMap.create(); + static BiMap fluidIDs = HashBiMap.create(); + ... + public static boolean registerFluid(Fluid fluid) + { + if (fluidIDs.containsKey(fluid.getName())) + ^^^^^^^ + ``` + There is definitely should be fluids instead fluidIDs. This mistake broke many mods. + kinglemming: + Fixes #1782 + + Signed-off-by: King Lemming + kinglemming: + Fixes FluidContainerRegistry properly - no more corner case where client/server mods disagree. + + Also clarifies the 2x Fluid registration error message somewhat. + + Signed-off-by: King Lemming + kinglemming: + Adds a warning to the FluidContainerRegistry when a mod does something stupid! Also denies the registration. + + Signed-off-by: King Lemming + cpw: + MinecraftForge/FML@ce791cb1f2cf983ef77b1e5c4028ddefab394062 Rework EventSubscriptionTransformer to bake @Cancelable and @HasResult values, should increase EventBus performance even more by removing logic from Event constructors. + MinecraftForge/FML@852710962a9b6d7c8e2ca188c715eebb2da44c2a Clean up some dead code + cpw: MinecraftForge/FML@be5ec06e3144d55a03d125f3ce364eade3771f4f Cleaning up the missing resource stack spam, and condensing the information into a usefully understandable format. + cpw: MinecraftForge/FML@0da1263ff9ede99267c03728a1c823b8056d5e44 Enhance error output for bad textures a bit more and try and capture more types of error.. + cpw: + Fluids are now tracked internally by mod. This allows for the server and the world to specify a "default" + in the case of a possible alternative fluid implementation. If you always called registerFluid, things + should work pretty seamlessly, but if you didn't (gating with an isFluidRegistered check for example) + you should change to register anyway. This way, even if you're not default in the overall instance, you may + become default if you're the only mod present on a server, for example, or in a world save. + + This should radically decrease the mixups caused by mod load ordering problems, and other issues around fluid + tracking. + cpw: Fix NPE - Closes #1794 + cpw: And handle the null case in the constructor itself. Closes #1794 (again) + cpw: + MinecraftForge/FML@dfce4cd8d023a546c4c21405db182b8ddcd38633 Allow registering custom language adapters. + MinecraftForge/FML@9fecd72cf0bd483ae7bc2ce821ae6b2f5e5b9c65 Some tidyup of the PR + MinecraftForge/FML@10ac2a4fd972e923a60d23d10e8f297b8584f565 Fix itemCtorArgs javadoc in registerBlock + MinecraftForge/FML@86f70d37a40bbeaf7c389a14adcd8311ba5584df Patch TracingPrintStream to handle Kotlin IO. + kinglemming: + Adjusts OreDictionary to prevent invalid registrations. + Getting Ore Names for a non-existent ore will no longer automatically add that Name to the list nor generate an ID. + + Tweaks a warning message in the FluidContainerRegistry. No functionality change. + + Signed-off-by: King Lemming + LexManos: + Revert KL's change, requesting a ore WILL register it. + + Registering like this and returning a new empty list allows for modders to register their recipes and such without requiring to be executed after someone actually adds an item. If handled properly this allows for more flexible load orders, and more responsive code. + kinglemming: + Adds some new Ore querying functionality. + + Also attempts to size initial Hashmaps in a logical manner. + + Signed-off-by: King Lemming + cpw: + Fixed NBTSizeTracker missing a lot of data being read. Also made new NBT object allocation claim 32-bits in the size tracker. + + (cherry picked from commit de066a86da281d381b0e3ab9e83682720327049c) + + Conflicts: + patches/minecraft/net/minecraft/nbt/CompressedStreamTools.java.patch + patches/minecraft/net/minecraft/nbt/NBTTagList.java.patch + cpw: Verify that the fluid registry doesn't contain "junk" fluids thru reflection. + cpw: MinecraftForge/FML@8f9e3a7e30c8cc436dcb8d94b18b4634e0376339 Exceptions during construction phase should not propogate and cause an immediate crash. Closes #638 + cpw: Change logging to avoid the String.format bug. Closes #1809 + cpw: Actually use the override constraint in ticket requests. Closes #1802 + cpw: + Reformat ItemArmor$ArmorMaterial.getBaseItem to use an if/then/else structure. The switch + causes the generation of an internal class which may derp custom armor addition. + Closes #1799 + cpw: Make FluidStack hold a delegate for the fluid. This can then float based on what is "live" at present. + cpw: Fix static initializer derp. + cpw: Replace the OLD fluid in the fluidID map, not the new one.. + cpw: + Expose the fluid that a block was constructed with, useful for 'non-default' + configuration of fluidblocks. Shouldn't be used outside of this purpose. + cpw: MinecraftForge/FML@d14d1a8fea4c9242c944079ab8e4cdd516dfce4c Update to use the inherited jar format. Simplifies a lot.. + cpw: + MinecraftForge/FML@a39482c4b7ac2883f821619b47ff31e0b6e74b29 Splash screen implementation + MinecraftForge/FML@01fea095cdcd80c2ae9f0ebfd1c72242b3f2dbf8 Merge branch '1.7.10-load-progress' of github.com:RainWarrior/FML into 1.7.10 + MinecraftForge/FML@364b4bbbb0d4d168f9a63fa62a09e4e2fa213039 Call some loader stuffs + MinecraftForge/FML@61a891280d15f9f17e28bf86a427f32de5a8983e Make sure to close the splash screen if there's gonna be an error display + fry: + MinecraftForge/FML@5785a9c9e8d76b91a03ed1f9791aeee1cb7ea00b Fix up multiple injections of cmdline files via versionspecificmoddir. Closes #645 + MinecraftForge/FML@bd117be9c3e3919f3c29538cde80e3eb8fa48368 Correctly track exceptions thrown in the loading screen rendering thread + cpw: + MinecraftForge/FML@36688e781aae67fb1e4e7047acf689edeeac7ddb Add in resource reloading to the bar. Tidy up some of the labels a bit. + MinecraftForge/FML@a1dc465a55612ecdd44e6cde3adc0f1d53c6d97b More progress bar action! + MinecraftForge/FML@bfcbf4ef4366fd3d8bfd20adafb63a857bb0dd53 More progress bar hooks + MinecraftForge/FML@a6670c415ee97e771020921e00773c4c15e7512e Thread errors should be correctly displayed in the crash report now + MinecraftForge/FML@9a16d26186d27029cae32a19c09ddf48f7cba22e fixed bar text positioning + MinecraftForge/FML@0059c630281b7105c0532d2dba1bec27cf0323b2 Track mipmaps and texture upload + MinecraftForge/FML@ef5f809752e87e369235e98a63027e9347185cd9 Fix broken log message in vanilla. + cpw: + MinecraftForge/FML@4fe7b469b5ba156d4a786cd9e105b18cca7c271a Loading screen: logo rotation is now optional; initial support for animated textures - animation rate is fixed for now. + MinecraftForge/FML@31ae43590a2ba771d69b6c6513bcd5fe87ae8f8f Fix trying to close the screen during error. + cpw: MinecraftForge/FML@94821fac98e64d9b8ad7434ed23a621850a8e11c Add a config file that lets you add additional soft dependencies at runtime - injectedDependencies.json + cpw: MinecraftForge/FML@2ed00c4da0ee76eb15e28eb8ee2c07a3096155c2 Splash progress screen will not load in the presence of optifine anymore. + cpw: MinecraftForge/FML@dda431353953457608c38aacb060ef82ddc88883 Revert "Merge pull request #650 from luacs1998/1.7.10" This undoes the seriously broken change from Sponge to support Mixins, that breaks a wide variety of coremods. Given the widespread incompatibility it introduces, it won't be re-added at 1.7.10. + fry: + Updated FML: + MinecraftForge/FML@2ed00c4da0ee76eb15e28eb8ee2c07a3096155c2 Splash progress screen will not load in the presence of optifine anymore. + MinecraftForge/FML@adcf2247c69f68415033a3c0b2c527053733514c Loading screen: moved config file to the standard config directory; added the option to load textures from the custom resource pack + MinecraftForge/FML@91338433fa74e782e237643632de2cc5e17ee280 Add classloader exclusion for ASM + MinecraftForge/FML@7c10b93a2ded2799d41b73b67a2766c31e992d8a Synchronize the available libraries. Turns out we've been forcing a newer apache commons-lang(3.2.1) for a long time, also sync the dev guava - we've been forcing 17 for a long time too. Bumping commons-lang to 3.3.2 since that's what Mojang are shipping with 1.8. It has no observable ill effects Closes MinecraftForge/FML#651 + MinecraftForge/FML@8ccfa24764a3f4854f5334c0da1224286175e13b Merge pull request MinecraftForge/FML#650 from luacs1998/1.7.10 + MinecraftForge/FML@b2650a0bdb7d69010a55de518e76591a6c417e87 Optifine can tell us when they're ready for the new splash screen. + MinecraftForge/FML@02a5a58a1cbb25cd3baecf1535950e4780b7810f Fix the ordering of the messages, so they make sense now. + MinecraftForge/FML@dda431353953457608c38aacb060ef82ddc88883 Revert "Merge pull request MinecraftForge/FML#650 from luacs1998/1.7.10" This undoes the seriously broken change from Sponge to support Mixins, that breaks a wide variety of coremods. Given the widespread incompatibility it introduces, it won't be re-added at 1.7.10. + MinecraftForge/FML@5dbb481732bf4bcf8b0c5c02806051a933e6587e Eliminated texture name allocation race condition + MinecraftForge/FML@450b82ca0e13cf889a42eeb198b67115a4851031 Updated default forge logo to animated gif; reverted config folder resolution to Minecraft class due to Loader not being initialized at the point it's needed + cpw: MinecraftForge/FML@0b84b6aa297bdf6ab9f010e340f286442cb242dc Expose the state of the loader + cpw: + Attempt to fix the slow loading problem. Instead of forcing the main thread to wait around + on every call to processWindowMessages, we will simply skip it, if the mutex is already + claimed by the display thread. This should fix slow loading issues seen by some with + the new loading screen. + cpw: Hardcode the FML version in-game as a specific value. + cpw: Strip control codes in progress bar messages. They cause crashes sometimes. + cpw: + Clean up transformers a bit. Can't use COMPUTE_FRAMES even though it's required - the game refuses to even + run if I do. Note for j8: when we force Java8 classes, all coremods will need a thorough overhaul - the + current way we do things is not sustainable when Java8 becomes the universal norm. + cpw: + Add in an ItemStackHolder - a way to inject ItemStacks without having to have complex lookup code everywhere. + + Example: https://gist.github.com/cpw/9af398451a20459ac263 + cpw: Bump minor version # to 2 because of the fluid changes (mirroring what happening in 1.7.10) + +Build 1.7.10-10.13.3.1420-1.7.10: + cpw: + Add in an ItemStackHolder - a way to inject ItemStacks without having to have complex lookup code everywhere. + + Example: https://gist.github.com/cpw/9af398451a20459ac263 + +Build 1.8-11.14.1.1419: + LexManos: Fixed damage reduction rate of vanilla armor incorrectly scaling with armor's current durability. + +Build 1.8-11.14.1.1418: + AlgorithmX2: Fix Partial Face Lighting on Top/Bottom Faces ; Vanilla MC-80148 + +Build 1.8-11.14.1.1417: + LexManos: Force netty downgrade on dedicated server to match client. Netty bug: https://github.com/netty/netty/issues/2302 Closes #1848 + +Build 1.8-11.14.1.1416: + LexManos: Fixed command exploit with C12 + +Build 1.8-11.14.1.1415: + LexManos: Fixes MC-75630 - Exploit with signs and command blocks + +Build 1.8-11.14.1.1414: + LexManos: Finish loading screen before going fullscreen. Closes MinecraftForge/FML#662 + +Build 1.8-11.14.1.1413: + LexManos: Loosen up ServerChatEvent to support IChatComponent Closes #1893 + LexManos: Cleanup a lot of spammy output. Everything hidden behind environment flags now. Scale anvil image down 50% + LexManos: Attempt to disable the new splash screen if there are errors detected finishing up. Print a slightly more helpful error message. + +Build 1.8-11.14.1.1412: + me: Add true support for unicode fonts + +Build 1.8-11.14.1.1411: + diesieben07: Fix crash when texture loading throws RuntimeException without message + +Build 1.8-11.14.1.1410: + xxt1g3lxx.xxt1g3lxx: Changed forge command tab completion to use getListOfStringsMatchingLastWord() + +Build 1.8-11.14.1.1409: + xxt1g3lxx.xxt1g3lxx: Added tab completion + +Build 1.7.10-10.13.3.1408-1.7.10: + cpw: Strip control codes in progress bar messages. They cause crashes sometimes. + cpw: + Clean up transformers a bit. Can't use COMPUTE_FRAMES even though it's required - the game refuses to even + run if I do. Note for j8: when we force Java8 classes, all coremods will need a thorough overhaul - the + current way we do things is not sustainable when Java8 becomes the universal norm. + +Build 1.7.10-10.13.3.1407-1.7.10: + cpw: Hardcode the FML version in-game as a specific value. + +Build 1.7.10-10.13.3.1406-1.7.10: + cpw: Merged FML into Forge's repo. FML is no longer developed seperatly. + +Build 1.8-11.14.1.1405: + cpw: Merged FML into Forge's repo. FML is no longer developed seperatly. + +Build 1.8-11.14.1.1404: + tmtravlrsmail: + Initialized the Nether Fortress chest loot + + Forced the nether fortress chest loot to initialize in ChestGenHooks + like the other types. + + Changed tabs to spaces. Silly Eclipse. + +Build 1.7.10-10.13.3.1403-1.7.10: + fry: + Updated FML: + MinecraftForge/FML@2ed00c4da0ee76eb15e28eb8ee2c07a3096155c2 Splash progress screen will not load in the presence of optifine anymore. + MinecraftForge/FML@adcf2247c69f68415033a3c0b2c527053733514c Loading screen: moved config file to the standard config directory; added the option to load textures from the custom resource pack + MinecraftForge/FML@91338433fa74e782e237643632de2cc5e17ee280 Add classloader exclusion for ASM + MinecraftForge/FML@7c10b93a2ded2799d41b73b67a2766c31e992d8a Synchronize the available libraries. Turns out we've been forcing a newer apache commons-lang(3.2.1) for a long time, also sync the dev guava - we've been forcing 17 for a long time too. Bumping commons-lang to 3.3.2 since that's what Mojang are shipping with 1.8. It has no observable ill effects Closes MinecraftForge/FML#651 + MinecraftForge/FML@8ccfa24764a3f4854f5334c0da1224286175e13b Merge pull request MinecraftForge/FML#650 from luacs1998/1.7.10 + MinecraftForge/FML@b2650a0bdb7d69010a55de518e76591a6c417e87 Optifine can tell us when they're ready for the new splash screen. + MinecraftForge/FML@02a5a58a1cbb25cd3baecf1535950e4780b7810f Fix the ordering of the messages, so they make sense now. + MinecraftForge/FML@dda431353953457608c38aacb060ef82ddc88883 Revert "Merge pull request MinecraftForge/FML#650 from luacs1998/1.7.10" This undoes the seriously broken change from Sponge to support Mixins, that breaks a wide variety of coremods. Given the widespread incompatibility it introduces, it won't be re-added at 1.7.10. + MinecraftForge/FML@5dbb481732bf4bcf8b0c5c02806051a933e6587e Eliminated texture name allocation race condition + MinecraftForge/FML@450b82ca0e13cf889a42eeb198b67115a4851031 Updated default forge logo to animated gif; reverted config folder resolution to Minecraft class due to Loader not being initialized at the point it's needed + cpw: MinecraftForge/FML@0b84b6aa297bdf6ab9f010e340f286442cb242dc Expose the state of the loader + +Build 1.8-11.14.1.1402: + silfadur: Added hook for IPerspectiveAwareModel in RenderItem.renderItemIntoGUI for ItemCameraTransforms.TransformType.GUI + +Build 1.7.10-10.13.3.1401-1710ls: + fry: + Updated FML: + MinecraftForge/FML@2ed00c4da0ee76eb15e28eb8ee2c07a3096155c2 Splash progress screen will not load in the presence of optifine anymore. + MinecraftForge/FML@adcf2247c69f68415033a3c0b2c527053733514c Loading screen: moved config file to the standard config directory; added the option to load textures from the custom resource pack + MinecraftForge/FML@91338433fa74e782e237643632de2cc5e17ee280 Add classloader exclusion for ASM + MinecraftForge/FML@7c10b93a2ded2799d41b73b67a2766c31e992d8a Synchronize the available libraries. Turns out we've been forcing a newer apache commons-lang(3.2.1) for a long time, also sync the dev guava - we've been forcing 17 for a long time too. Bumping commons-lang to 3.3.2 since that's what Mojang are shipping with 1.8. It has no observable ill effects Closes MinecraftForge/FML#651 + MinecraftForge/FML@8ccfa24764a3f4854f5334c0da1224286175e13b Merge pull request MinecraftForge/FML#650 from luacs1998/1.7.10 + MinecraftForge/FML@b2650a0bdb7d69010a55de518e76591a6c417e87 Optifine can tell us when they're ready for the new splash screen. + MinecraftForge/FML@02a5a58a1cbb25cd3baecf1535950e4780b7810f Fix the ordering of the messages, so they make sense now. + MinecraftForge/FML@dda431353953457608c38aacb060ef82ddc88883 Revert "Merge pull request MinecraftForge/FML#650 from luacs1998/1.7.10" This undoes the seriously broken change from Sponge to support Mixins, that breaks a wide variety of coremods. Given the widespread incompatibility it introduces, it won't be re-added at 1.7.10. + MinecraftForge/FML@5dbb481732bf4bcf8b0c5c02806051a933e6587e Eliminated texture name allocation race condition + MinecraftForge/FML@450b82ca0e13cf889a42eeb198b67115a4851031 Updated default forge logo to animated gif; reverted config folder resolution to Minecraft class due to Loader not being initialized at the point it's needed + +Build 1.7.10-10.13.3.1400-1.7.10: + cpw: MinecraftForge/FML@dda431353953457608c38aacb060ef82ddc88883 Revert "Merge pull request #650 from luacs1998/1.7.10" This undoes the seriously broken change from Sponge to support Mixins, that breaks a wide variety of coremods. Given the widespread incompatibility it introduces, it won't be re-added at 1.7.10. + +Build 1.7.10-10.13.3.1399-1.7.10: + cpw: + MinecraftForge/FML@a39482c4b7ac2883f821619b47ff31e0b6e74b29 Splash screen implementation + MinecraftForge/FML@01fea095cdcd80c2ae9f0ebfd1c72242b3f2dbf8 Merge branch '1.7.10-load-progress' of github.com:RainWarrior/FML into 1.7.10 + MinecraftForge/FML@364b4bbbb0d4d168f9a63fa62a09e4e2fa213039 Call some loader stuffs + MinecraftForge/FML@61a891280d15f9f17e28bf86a427f32de5a8983e Make sure to close the splash screen if there's gonna be an error display + fry: + MinecraftForge/FML@5785a9c9e8d76b91a03ed1f9791aeee1cb7ea00b Fix up multiple injections of cmdline files via versionspecificmoddir. Closes #645 + MinecraftForge/FML@bd117be9c3e3919f3c29538cde80e3eb8fa48368 Correctly track exceptions thrown in the loading screen rendering thread + cpw: + MinecraftForge/FML@36688e781aae67fb1e4e7047acf689edeeac7ddb Add in resource reloading to the bar. Tidy up some of the labels a bit. + MinecraftForge/FML@a1dc465a55612ecdd44e6cde3adc0f1d53c6d97b More progress bar action! + MinecraftForge/FML@bfcbf4ef4366fd3d8bfd20adafb63a857bb0dd53 More progress bar hooks + MinecraftForge/FML@a6670c415ee97e771020921e00773c4c15e7512e Thread errors should be correctly displayed in the crash report now + MinecraftForge/FML@9a16d26186d27029cae32a19c09ddf48f7cba22e fixed bar text positioning + MinecraftForge/FML@0059c630281b7105c0532d2dba1bec27cf0323b2 Track mipmaps and texture upload + MinecraftForge/FML@ef5f809752e87e369235e98a63027e9347185cd9 Fix broken log message in vanilla. + cpw: + MinecraftForge/FML@4fe7b469b5ba156d4a786cd9e105b18cca7c271a Loading screen: logo rotation is now optional; initial support for animated textures - animation rate is fixed for now. + MinecraftForge/FML@31ae43590a2ba771d69b6c6513bcd5fe87ae8f8f Fix trying to close the screen during error. + cpw: MinecraftForge/FML@94821fac98e64d9b8ad7434ed23a621850a8e11c Add a config file that lets you add additional soft dependencies at runtime - injectedDependencies.json + cpw: MinecraftForge/FML@2ed00c4da0ee76eb15e28eb8ee2c07a3096155c2 Splash progress screen will not load in the presence of optifine anymore. + +Build 1.8-11.14.1.1398: + Zaggy1024: Fixed a bug which caused the light level not to update when a block implements Block.getLightValue(IBlockAccess, BlockPos) to change the light value for different block states. + +Build 1.8-11.14.1.1397: + Parker Young: Fixes MC-52974: Host's skin doesn't load in LAN + +Build 1.8-11.14.1.1396: + Zaggy1024: Removed @SideOnly(Side.CLIENT) from EnumWorldBlockLayer. + +Build 1.7.10-10.13.3.1395-1710ls: + cpw: MinecraftForge/FML@94821fac98e64d9b8ad7434ed23a621850a8e11c Add a config file that lets you add additional soft dependencies at runtime - injectedDependencies.json + +Build 1.7.10-10.13.3.1394-1710ls: + cpw: + MinecraftForge/FML@4fe7b469b5ba156d4a786cd9e105b18cca7c271a Loading screen: logo rotation is now optional; initial support for animated textures - animation rate is fixed for now. + MinecraftForge/FML@31ae43590a2ba771d69b6c6513bcd5fe87ae8f8f Fix trying to close the screen during error. + +Build 1.7.10-10.13.3.1393-1710ls: + cpw: + MinecraftForge/FML@36688e781aae67fb1e4e7047acf689edeeac7ddb Add in resource reloading to the bar. Tidy up some of the labels a bit. + MinecraftForge/FML@a1dc465a55612ecdd44e6cde3adc0f1d53c6d97b More progress bar action! + MinecraftForge/FML@bfcbf4ef4366fd3d8bfd20adafb63a857bb0dd53 More progress bar hooks + MinecraftForge/FML@a6670c415ee97e771020921e00773c4c15e7512e Thread errors should be correctly displayed in the crash report now + MinecraftForge/FML@9a16d26186d27029cae32a19c09ddf48f7cba22e fixed bar text positioning + MinecraftForge/FML@0059c630281b7105c0532d2dba1bec27cf0323b2 Track mipmaps and texture upload + MinecraftForge/FML@ef5f809752e87e369235e98a63027e9347185cd9 Fix broken log message in vanilla. + +Build 1.8-11.14.1.1392: + LexManos: Cleanup RenderEntityItem patch, fixes Z-fighting issue in EntityItems. Closes #1824 + +Build 1.7.10-10.13.3.1391-1710ls: + fry: + MinecraftForge/FML@5785a9c9e8d76b91a03ed1f9791aeee1cb7ea00b Fix up multiple injections of cmdline files via versionspecificmoddir. Closes #645 + MinecraftForge/FML@bd117be9c3e3919f3c29538cde80e3eb8fa48368 Correctly track exceptions thrown in the loading screen rendering thread + +Build 1.8-11.14.1.1390: + jadran.kotnik: + Extracted the creation of RegionRenderCache into a method. + Classes extending RegionRenderCache can change the behavior of the cache, allowing to visually change blocks (schematics etc). + +Build 1.7.10-10.13.3.1388-1.7.10: + cpw: MinecraftForge/FML@d14d1a8fea4c9242c944079ab8e4cdd516dfce4c Update to use the inherited jar format. Simplifies a lot.. + +Build 1.7.10-10.13.3.1385-1.7.10: + cpw: + Expose the fluid that a block was constructed with, useful for 'non-default' + configuration of fluidblocks. Shouldn't be used outside of this purpose. + +Build 1.7.10-10.13.3.1384-1.7.10: + cpw: Replace the OLD fluid in the fluidID map, not the new one.. + +Build 1.7.10-10.13.3.1383-1.7.10: + cpw: Fix static initializer derp. + +Build 1.7.10-10.13.3.1382-1.7.10: + cpw: Make FluidStack hold a delegate for the fluid. This can then float based on what is "live" at present. + +Build 1.7.10-10.13.3.1381-1.7.10: + cpw: + Reformat ItemArmor$ArmorMaterial.getBaseItem to use an if/then/else structure. The switch + causes the generation of an internal class which may derp custom armor addition. + Closes #1799 + +Build 1.7.10-10.13.3.1380-1.7.10: + cpw: Actually use the override constraint in ticket requests. Closes #1802 + +Build 1.7.10-10.13.3.1379-1.7.10: + cpw: Change logging to avoid the String.format bug. Closes #1809 + +Build 1.7.10-10.13.3.1378-1.7.10: + cpw: MinecraftForge/FML@8f9e3a7e30c8cc436dcb8d94b18b4634e0376339 Exceptions during construction phase should not propogate and cause an immediate crash. Closes #638 + +Build 1.7.10-10.13.3.1377-1.7.10: + cpw: Verify that the fluid registry doesn't contain "junk" fluids thru reflection. + +Build 1.7.10-10.13.3.1376-1.7.10: + cpw: + Fixed NBTSizeTracker missing a lot of data being read. Also made new NBT object allocation claim 32-bits in the size tracker. + + (cherry picked from commit de066a86da281d381b0e3ab9e83682720327049c) + + Conflicts: + patches/minecraft/net/minecraft/nbt/CompressedStreamTools.java.patch + patches/minecraft/net/minecraft/nbt/NBTTagList.java.patch + +Build 1.8-11.14.1.1375: + LexManos: Fixed NBTSizeTracker missing a lot of data being read. Also made new NBT object allocation claim 32-bits in the size tracker. + +Build 1.7.10-10.13.3.1374-1.7.10: + kinglemming: + Adds some new Ore querying functionality. + + Also attempts to size initial Hashmaps in a logical manner. + + Signed-off-by: King Lemming + +Build 1.7.10-10.13.3.1373-1.7.10: + LexManos: + Revert KL's change, requesting a ore WILL register it. + + Registering like this and returning a new empty list allows for modders to register their recipes and such without requiring to be executed after someone actually adds an item. If handled properly this allows for more flexible load orders, and more responsive code. + +Build 1.7.10-10.13.3.1372-1.7.10: + kinglemming: + Adjusts OreDictionary to prevent invalid registrations. + Getting Ore Names for a non-existent ore will no longer automatically add that Name to the list nor generate an ID. + + Tweaks a warning message in the FluidContainerRegistry. No functionality change. + + Signed-off-by: King Lemming + +Build 1.8-11.14.1.1371: + cpw: + MinecraftForge/FML@888e489394e52abdfb349fbfbd7f8e153b5af124 Allow registering custom language adapters. + MinecraftForge/FML@906f94ca143f756f40404fde38af32b2481d0673 Some tidyup of the PR + MinecraftForge/FML@1c025f18433df868859022eea8e6d198444736de Patch TracingPrintStream to handle Kotlin IO. + +Build 1.7.10-10.13.3.1370-1.7.10: + cpw: + MinecraftForge/FML@dfce4cd8d023a546c4c21405db182b8ddcd38633 Allow registering custom language adapters. + MinecraftForge/FML@9fecd72cf0bd483ae7bc2ce821ae6b2f5e5b9c65 Some tidyup of the PR + MinecraftForge/FML@10ac2a4fd972e923a60d23d10e8f297b8584f565 Fix itemCtorArgs javadoc in registerBlock + MinecraftForge/FML@86f70d37a40bbeaf7c389a14adcd8311ba5584df Patch TracingPrintStream to handle Kotlin IO. + +Build 1.7.10-10.13.3.1369-1.7.10: + cpw: And handle the null case in the constructor itself. Closes #1794 (again) + +Build 1.7.10-10.13.3.1368-1.7.10: + cpw: Fix NPE - Closes #1794 + +Build 1.7.10-10.13.3.1367-1.7.10: + cpw: + Fluids are now tracked internally by mod. This allows for the server and the world to specify a "default" + in the case of a possible alternative fluid implementation. If you always called registerFluid, things + should work pretty seamlessly, but if you didn't (gating with an isFluidRegistered check for example) + you should change to register anyway. This way, even if you're not default in the overall instance, you may + become default if you're the only mod present on a server, for example, or in a world save. + + This should radically decrease the mixups caused by mod load ordering problems, and other issues around fluid + tracking. + +Build 1.7.10-10.13.3.1366-1.7.10: + cpw: MinecraftForge/FML@0da1263ff9ede99267c03728a1c823b8056d5e44 Enhance error output for bad textures a bit more and try and capture more types of error.. + +Build 1.7.10-10.13.3.1365-1.7.10: + cpw: MinecraftForge/FML@be5ec06e3144d55a03d125f3ce364eade3771f4f Cleaning up the missing resource stack spam, and condensing the information into a usefully understandable format. + +Build 1.7.10-10.13.3.1364-1.7.10: + cpw: + MinecraftForge/FML@ce791cb1f2cf983ef77b1e5c4028ddefab394062 Rework EventSubscriptionTransformer to bake @Cancelable and @HasResult values, should increase EventBus performance even more by removing logic from Event constructors. + MinecraftForge/FML@852710962a9b6d7c8e2ca188c715eebb2da44c2a Clean up some dead code + +Build 1.7.10-10.13.3.1363-1.7.10: + kinglemming: + Adds a warning to the FluidContainerRegistry when a mod does something stupid! Also denies the registration. + + Signed-off-by: King Lemming + +Build 1.7.10-10.13.3.1362-1.7.10: + kinglemming: + Fixes FluidContainerRegistry properly - no more corner case where client/server mods disagree. + + Also clarifies the 2x Fluid registration error message somewhat. + + Signed-off-by: King Lemming + +Build 1.8-11.14.1.1361: + LexManos: MinecraftForge/FML@4a753227adb805d29f3bf245c3f8427193c35544 Rework EventSubscriptionTransformer to bake @Cancelable and @HasResult values, should increase EventBus performance even more by removing logic from Event constructors. + +Build 1.7.10-10.13.3.1360-1.7.10: + kinglemming: + Fixes #1782 + + Signed-off-by: King Lemming + +Build 1.8-11.14.1.1359: + Abrar Syed: changed run configs to GradleStarts + +Build 1.7.10-10.13.3.1358-1.7.10: + me: + Fix FluidRegsitry.registerFluid + + FluidRegistry: + ```java + static BiMap fluids = HashBiMap.create(); + static BiMap fluidIDs = HashBiMap.create(); + ... + public static boolean registerFluid(Fluid fluid) + { + if (fluidIDs.containsKey(fluid.getName())) + ^^^^^^^ + ``` + There is definitely should be fluids instead fluidIDs. This mistake broke many mods. + +Build 1.8-11.14.1.1357: + LexManos: + Updated FML: + MinecraftForge/FML@c8160311d580f2dfccdf796a5243e16844787cb6 Stop IllegalFormatConversionException thrown if @Mod has flagged client-only or server-only + MinecraftForge/FML@9a894952afb526436649f608f7af5992b97f044c Merge pull request #627 from GotoLink/patch-1 + MinecraftForge/FML@40faac64520d1a197f08eaa9a0f850e7df43359a Remove J7 only constructor in EnhancedRuntimeException, J6 compiling compatibility restored. + +Build 1.7.10-10.13.3.1356-1.7.10: + LexManos: MinecraftForge/FML@31cf2a9cab6d1977d31436220d9612eaa13d4e0f Remove J7 only constructor in EnhancedRuntimeException, J6 compiling compatibility restored. + LexManos: Restore binary compatibility issues in FluidRegistry caused by recent changes. + +Build 1.7.10-10.13.3.1355-1.7.10: + cpw: + Removed fluidID from ItemStack. + + This fixes a rather huge issue where FluidStacks on the client could be desynced if a modder was unaware of it. + + This is a breaking change but can be mitigated with a transformer to the getter getFluidID(). + + Signed-off-by: King Lemming + cpw: Add in a fluidid transformer + cpw: Fix formatting + cpw: + Allow for duplicate Fluid Blocks. It's annoying to be sure but just as with the OreDictionary, we'll have to handle it. + + Signed-off-by: King Lemming + cpw: + You shouldn't be creating FluidStacks from unregistered Fluids. Warn clearly on failed registrations, and make a useful log message for failed fluidstack + creations. Should help a lot with tracking down broken mods that are doing this wrongly. + +Build 1.8-11.14.1.1354: + ohai.iChun: Readded but deprecated the old RenderPlayerEvent that were deleted. Sorry, Lex. + +Build 1.8-11.14.1.1353: + ohai.iChun: + Reimplement RenderPlayerEvent that was removed in the port to 1.8 from 1.7.10. + RenderPlayerEvent.Specials was removed because the special effects are done in the LayerRenderer now. + +Build 1.7.10-10.13.2.1352-1.7.10: + cpw: + Forge really should have always supported the concept of an "exact spawn". Individual world providers can still + change this behaviour of course, but for default maps it makes sense to support it as a config option. + +Build 1.7.10-10.13.2.1351-1.7.10: + cpw: + MinecraftForge/FML@12ccf9cf49b76140841cdc5a459422ae4781de1a Rather than try to fall back to the backup level.dat in case of weirdness in the ID map, just fail hard. There is probably a serious modder derp in this case and there's nothing FML can do to recover the situation except avoid making it worse. + MinecraftForge/FML@e8cd368da30661ed2898fff232e2db787edcbdcc It's an IllegalState not an IllegalArgument *sigh* + MinecraftForge/FML@2be9c743424c92f8799a6af1d59d60edd65e6bf0 And fix itemblocks being removed, leaving behind a residual block. This is a legitimate action - use the missing mapping event to let the mod tell us about it + MinecraftForge/FML@7d8804cf656081d1570068f52e9bfc7140b21a65 You can't setAction to BLOCKONLY + MinecraftForge/FML@c73861efe67594ee9995bc93744cab06bd6647d1 Cherry-pick 01aaa7dc97480b381ca0d192ec65016d7baeb747 Fix mods defined via --mods or --modListFile launch args not being searched for coremods. #560 + MinecraftForge/FML@94c45b48c1265e7c4f60f591d413fa545787d354 Fix json cache crash, handle the file much more cleanly. Probably an MC JIRA since it's a vanilla bug. Closes #619 + +Build 1.8-11.14.1.1350: + LexManos: + Updated FML: + MinecraftForge/FML@1de3bf733aef754f15de55006b1750376871feb0 Fix FML's package for net.miencraftforge on maven. Fixes uploading of new builds. Note: 1.7.10 builds are bug fixes only while FML/Forge for 1.8 stabelizes. + MinecraftForge/FML@05ecefb53857ecc1dc52d4a577ed593c26da9659 Update to ASM5 for Java 8 support + MinecraftForge/FML@1112c455b9758c38eab385f48578bad17c0180f9 Merge pull request #595 from Grinch/master + LexManos: Fixed potential NPEs in Structure code caused by componenets not being able to load. + cpw: + MinecraftForge/FML@6b0ae369eb9b8cf89eb9d53fe997a6e5ef222093 Try and improve performance of the registry by avoiding superType.cast. + MinecraftForge/FML@dfebcafd49550b8c3f90c6c028ef0d7f3a13e607 Something I meant to add a long time ago, but it got overlooked. My apologies. Presend the (int) dimension ID in the serverhello packet. This should be 100% backward compatible with existing servers but bumping a server to this version will allow clients with this version as well to now login in dimensions outside the byte range. Probably fixes a bunch of mods that add dimensions. + MinecraftForge/FML@6011419fa055c1375d05189f9bf0d86705c9c0ec Clean up my patch. Terrible person I am.. + MinecraftForge/FML@c6bbd0e82de3d8f7993d70aa7be3f883b3afbc47 Forgot that I need a noarg ctor. I'm so rusty. + MinecraftForge/FML@6edc1635de163c41b6b5dfe02bee13d6a9c5aa4d Need to load the dimension from disk - do it without filling out the player so that the normal player loading (including events) works properly + cpw: + MinecraftForge/FML@4ca6f6e19f3c3147fcf48c58669f55478a9a1345 What a dumb oversight. One needs to copy the active substitution set to the active gamedata. Doesn't work well otherwise. + MinecraftForge/FML@6f6cec96be73b4c94999cf60dc00741f3f3c2cc2 Substitutions need to be activated when they're registered, otherwise they won't appear in world, ever. + MinecraftForge/FML@13ac015f0c36b8e2091ae332c556be315429f4c8 Change iterator behaviour for the registry - include substitutions in the standard iterator, so that vanilla MC methods visit them (so they can get textures etc). The fml special one only visits the absolute set, used mostly for sanity checking and serialization. + LexManos: + MinecraftForge/FML@24cb4a42c4e4bddde95c0e49d1f8b8bcc20c626d Enhance output of common FML errors in crash reports and server GUI. + Force load anonymous minecraft classes used in crash reports. This prevents some crashes being hiddedn behind class definiton exceptions. + cpw: Experimental "fix" for the weird rendering in the Acheivements screen. Thanks skyboy for spotting this. + cpw: + Comment on previous commit fix - it worked. Thanks to skyboy and tterrag for investigating and verifying. + A chest as an acheivement icon will recreate the original problem, for note. + cpw: + Update FML - merge the 1.7.10 changes in to forge @ 1.8. Wow git is (sorta) AWESOME! + + MinecraftForge/FML@6b0ae369eb9b8cf89eb9d53fe997a6e5ef222093 Try and improve performance of the registry by avoiding superType.cast. + MinecraftForge/FML@dfebcafd49550b8c3f90c6c028ef0d7f3a13e607 Something I meant to add a long time ago, but it got overlooked. My apologies. Presend the (int) dimension ID in the serverhello packet. This should be 100% backward compatible with existing servers but bumping a server to this version will allow clients with this version as well to now login in dimensions outside the byte range. Probably fixes a bunch of mods that add dimensions. + MinecraftForge/FML@6011419fa055c1375d05189f9bf0d86705c9c0ec Clean up my patch. Terrible person I am.. + MinecraftForge/FML@c6bbd0e82de3d8f7993d70aa7be3f883b3afbc47 Forgot that I need a noarg ctor. I'm so rusty. + MinecraftForge/FML@6edc1635de163c41b6b5dfe02bee13d6a9c5aa4d Need to load the dimension from disk - do it without filling out the player so that the normal player loading (including events) works properly + MinecraftForge/FML@4ca6f6e19f3c3147fcf48c58669f55478a9a1345 What a dumb oversight. One needs to copy the active substitution set to the active gamedata. Doesn't work well otherwise. + MinecraftForge/FML@6f6cec96be73b4c94999cf60dc00741f3f3c2cc2 Substitutions need to be activated when they're registered, otherwise they won't appear in world, ever. + MinecraftForge/FML@13ac015f0c36b8e2091ae332c556be315429f4c8 Change iterator behaviour for the registry - include substitutions in the standard iterator, so that vanilla MC methods visit them (so they can get textures etc). The fml special one only visits the absolute set, used mostly for sanity checking and serialization. + MinecraftForge/FML@24cb4a42c4e4bddde95c0e49d1f8b8bcc20c626d Enhance output of common FML errors in crash reports and server GUI. + MinecraftForge/FML@12ccf9cf49b76140841cdc5a459422ae4781de1a Rather than try to fall back to the backup level.dat in case of weirdness in the ID map, just fail hard. There is probably a serious modder derp in this case and there's nothing FML can do to recover the situation except avoid making it worse. + MinecraftForge/FML@e8cd368da30661ed2898fff232e2db787edcbdcc It's an IllegalState not an IllegalArgument *sigh* + MinecraftForge/FML@2be9c743424c92f8799a6af1d59d60edd65e6bf0 And fix itemblocks being removed, leaving behind a residual block. This is a legitimate action - use the missing mapping event to let the mod tell us about it + MinecraftForge/FML@7d8804cf656081d1570068f52e9bfc7140b21a65 You can't setAction to BLOCKONLY + MinecraftForge/FML@13df640d9d4516219b07778edd76efd2643019f6 Pull in a lot of the FML tweaks from 1.7 to 1.8 + MinecraftForge/FML@447beaa99ec828fb83796185d07c72ea28b056c9 Merge remote-tracking branch 'origin/1.7.10' + +Build 1.8-11.14.1.1349: + cpw: + MinecraftForge/FML@2afd55ab825fad3b07073c474cdb96b348701084 Fix scala mods, Closes #621 + MinecraftForge/FML@c541b08ef68161f437eeb7b22eabe27b20eebf55 Merge pull request #622 from diesieben07/scala-fix + MinecraftForge/FML@d5021417dd10f36dc3d1b68e4975eb91f7f46e68 Forgot the register handling bit. Registration should work now.. + MinecraftForge/FML@5a65c6568699acaade8243040d8552b1f2e2e28f OK, this is finally actually working, I think... + +Build 1.8-11.14.1.1348: + fry: Fixed mipmapping not being enabled by expanding 1x1 texture + +Build 1.7.10-10.13.2.1347-1.7.10: + cpw: + Comment on previous commit fix - it worked. Thanks to skyboy and tterrag for investigating and verifying. + A chest as an acheivement icon will recreate the original problem, for note. + +Build 1.7.10-10.13.2.1346-1.7.10: + cpw: Experimental "fix" for the weird rendering in the Acheivements screen. Thanks skyboy for spotting this. + +Build 1.8-11.14.1.1344: + LexManos: + Updated FML: + MinecraftForge/FML@2a268cd5664b6562a4bf2a953a6a93fd8e111bd2 Improve mod list GUI, add sort and search + MinecraftForge/FML@951fc2d9fd7e7970c86accb1be095a24f7bfaf18 First attempt at making FMLControlledRegistry something a bit more generic than just blocks/items. + MinecraftForge/FML@410582222d9ba15d42dc47db0d3d6a84aeac2d22 Merge pull request #614 from tterrag1098/betterModList + MinecraftForge/FML@ba0b176430cdbc3573643a6e21d47013cfd1f0e0 Fix ModDiscoverer ignoring inner classes. + MinecraftForge/FML@9cc313eab9939724786f833f511a87c9957dbc72 Merge pull request #617 from diesieben07/innerclass-disc + MinecraftForge/FML@01aaa7dc97480b381ca0d192ec65016d7baeb747 Fix mods defined via --mods or --modListFile launch args not being searched for coremods. #560 + MinecraftForge/FML@8cecc47b85db68e8e69f45641b1d843509dbe71d Merge pull request #620 from killjoy1221/extra-coremod-fix + MinecraftForge/FML@38d9a5f444815810dec3607f5b3b7ff1ac513d4c Enhance output of common FML errors in crash reports and server + + Force load anonymous minecraft classes used in crash reports. This prevents some crashes being hiddedn behind class definiton exceptions.GUI. + +Build 1.7.10-10.13.2.1343-1.7.10: + LexManos: + MinecraftForge/FML@24cb4a42c4e4bddde95c0e49d1f8b8bcc20c626d Enhance output of common FML errors in crash reports and server GUI. + Force load anonymous minecraft classes used in crash reports. This prevents some crashes being hiddedn behind class definiton exceptions. + +Build 1.7.10-10.13.2.1342-1.7.10: + cpw: + MinecraftForge/FML@4ca6f6e19f3c3147fcf48c58669f55478a9a1345 What a dumb oversight. One needs to copy the active substitution set to the active gamedata. Doesn't work well otherwise. + MinecraftForge/FML@6f6cec96be73b4c94999cf60dc00741f3f3c2cc2 Substitutions need to be activated when they're registered, otherwise they won't appear in world, ever. + MinecraftForge/FML@13ac015f0c36b8e2091ae332c556be315429f4c8 Change iterator behaviour for the registry - include substitutions in the standard iterator, so that vanilla MC methods visit them (so they can get textures etc). The fml special one only visits the absolute set, used mostly for sanity checking and serialization. + +Build 1.8-11.14.1.1341: + simonbarnes1: + Add getTileData() to TileEntity + + - The same idea as Entity.getEntityData() + +Build 1.7.10-10.13.2.1340-1.7.10: + cpw: + MinecraftForge/FML@6b0ae369eb9b8cf89eb9d53fe997a6e5ef222093 Try and improve performance of the registry by avoiding superType.cast. + MinecraftForge/FML@dfebcafd49550b8c3f90c6c028ef0d7f3a13e607 Something I meant to add a long time ago, but it got overlooked. My apologies. Presend the (int) dimension ID in the serverhello packet. This should be 100% backward compatible with existing servers but bumping a server to this version will allow clients with this version as well to now login in dimensions outside the byte range. Probably fixes a bunch of mods that add dimensions. + MinecraftForge/FML@6011419fa055c1375d05189f9bf0d86705c9c0ec Clean up my patch. Terrible person I am.. + MinecraftForge/FML@c6bbd0e82de3d8f7993d70aa7be3f883b3afbc47 Forgot that I need a noarg ctor. I'm so rusty. + MinecraftForge/FML@6edc1635de163c41b6b5dfe02bee13d6a9c5aa4d Need to load the dimension from disk - do it without filling out the player so that the normal player loading (including events) works properly + +Build 1.8-11.14.1.1339: + erlend: Added newVolume and newPitch to PlaySoundAtEntityEvent. Deprecated ForgeEventFactory.onPlaySoundAt, added replacement ForgeEventFactory.onPlaySoundAtEntity. + +Build 1.8-11.14.1.1338: + Geforce132: -Added EntityMountEvent. + +Build 1.8-11.14.1.1337: + diesieben07: Fix jukebox message being too low with forge + +Build 1.8-11.14.1.1336: + LexManos: + Updated FML: + MinecraftForge/FML@3e7ae47f8f5d642b256adbe8b3395bb40daf85da Fix Event Bus Access Issues + MinecraftForge/FML@c8e2a5f377ddf8a35cceda6a14697dbe8cad4ca8 Fixed WorldInfo properties not loaded + MinecraftForge/FML@7f96b2c69ab8a2ed07b5b786b3d679ea4c509121 Fix Debug packet logger on local memory connections. + +Build 1.8-11.14.1.1335: + robin: remove translation and add a note for contributors + +Build 1.8-11.14.1.1334: + erju01: Fixed enchanting table applying secondary enchs. + +Build 1.8-11.14.1.1333: + mnmiller1: Add NeighborNotiftyEvent. + +Build 1.8-11.14.1.1332: + tmtravlrsmail: + Added Nether Fortress chest to the ChestGenHooks + + I tried to follow the directions on + + https://github.com/MinecraftForge/MinecraftForge/wiki/If-you-want-to-contribute-to-Forge + + as best as I could. =) + + If anything is wrong, let me know and I'll change it! + clienthax: + Current spawner implementation checks the EntitySpawnPlacementRegistry hashmap to check where a entity should spawn + as there is no way to modify this without the use of reflection or a AT, you can not specify where you want your entity to spawn + adding this helper method will allow developers to specify where they want their entity to spawn. + + Signed-off-by: Clienthax + + Update EntitySpawnPlacementRegistry.java.patch + LexManos: Fix compile error in ClientHax's PR. + +Build 1.8-11.14.1.1329: + fry: Hopefully fix NPE during baking of empty vanilla item models + +Build 1.8-11.14.1.1328: + LexManos: Fire WorldEvent.Load for Client worlds. Closes #1719 + +Build 1.8-11.14.1.1327: + LexManos: Make Container.mergeItemStack respect Slot.isValidItem Closes #1630 + +Build 1.8-11.14.1.1326: + LexManos: Fix JukeBoxes not storing the inserted record. All TE's in minecraft are in net.minecraft.tileentity EXCEPT JukeBoxes. Closes #1633 Closes #1714 + +Build 1.8-11.14.1.1325: + LexManos: Fix NPEs in last commit. + +Build 1.8-11.14.1.1324: + LexManos: + Updated FML: + MinecraftForge/FML@c9cf3136c265b2e8e46eab102b2310a9312b8cfb New @Mod properties to define which environment to load the mod on. + clientSideOnly will only be loaded in the Client environment. + serverSideOnly will only be loaded in the Dedicated server environment. + Combine with acceptedMinecraftVersions to prevent users from loading the mod in the incorrect environment. + +Build 1.8-11.14.1.1323: + LexManos: + Updated FML: + MinecraftForge/FML@5eff40897545c9e6f597a202bc9e86c3b07761ad Filter more known libraries from potential mod canidates. + MinecraftForge/FML@feb4c436db27a249dd5190023edd38cb5884e90b Quiet ClassPatchManager debug spam by default. Reenable using -Dfml.debugClassPatchManager=true. + MinecraftForge/FML@41e806fa950839bf901ebf9c18d0c632a7c5538c Fix double decoding of UTF8 characters in lang files. + +Build 1.8-11.14.1.1322: + LexManos: Fixed using items on the wrong block client side caused by iChuns eyeheight update. + +Build 1.8-11.14.1.1321: + ohai.iChun: Reimplement variable eyeHeight for players which was removed in the 1.7 to 1.8 port. + +Build 1.8-11.14.1.1320: + fry: Removed event bus call from the ModelLoader + +Build 1.8-11.14.1.1319: + matthewprenger: Add the ability to add prefixes and suffixes to the player's display name. + LexManos: Add safty to URL detection in chat. Closes #1712 + +Build 1.8-11.14.1.1318: + fry: Added a default white texture; Fixed B3DLoader crashing when the brush has empty texture specified + fry: RenderItem can now use baked quad color + +Build 1.8-11.14.1.1317: + Parker Young: + Added ATs for EnumFacing + + This publics the VALUES array and HORIZONTALS array in EnumFacing, thus giving modders access to these arrays, much like ForgeDirection had. + +Build 1.8-11.14.1.1316: + fry: Attributes.put (de)normalization now works as intended + +Build 1.8-11.14.1.1315: + LexManos: Hold a weak reference to the Minecraft fake player object. Closes #1705 + +Build 1.8-11.14.1.1314: + matthewprenger: Minor tweak to UsernameCache to also cache usernames of offline players. + +Build 1.8-11.14.1.1313: + fry: Updated FML + +Build 1.8-11.14.1.1312: + fry: ModelRotation.getMatrix() now returns the correct matrix; fixed the application of custom transformations to vanilla models; fixed application of transformations to B3D models; fixed the culling of rotated vanilla models + +Build 1.8-11.14.1.1311: + fry: Alternative models work once again + +Build 1.8-11.14.1.1310: + fry: Updated FML + +Build 1.8-11.14.1.1309: + fry: fix ModelLoader.setCustomModelResourceLocation not storing same item with different metadata values + +Build 1.8-11.14.1.1308: + LexManos: Fixed debugging Dedicated server in Forge Dev workspace. + LexManos: Fixed being kicked from the server while swimming. + fry: + fixed NPE during loading of B3D models without textures/brushes. + changed default B3D color to have full opacity. + fry: Reworked vanilla texture resolution, hopefully fixes NPE bug in FaceBakery + fry: made renderLayer ThreadLocal, now it should hold correct value for use inside custom baked models + LexManos: Try a maven mirrior to fix build issues. + +Build 1.7.10-10.13.2.1307-1.7.10: + LexManos: Fixed potential NPEs in Structure code caused by componenets not being able to load. + +Build 1.8-11.14.1.1306: + LexManos: Fixed potential NPEs in Structure code caused by componenets not being able to load. Closes #1686 + +Build 1.8-11.14.1.1305: + LexManos: Fixed InitMapGenEvent's fire order so values are used. And added OCEAN_MONUMENT type. Closes #1681 + LexManos: Fixed BlockBush and BlockCrops not respecting custom soils. Closes #1683 + +Build 1.8-11.14.1.1303: + fry: Restore binary backwards compatibility + +Build 1.8-11.14.1.1302: + fry: ModelBakeEvent now has ModelLoader as an argument instead of ModelBakery; Added various static hooks to ModelLoader to allow registering model-related information before it's needed (prevents file-not-found errors on first baking pass); ModelLoader waits until ModelBakeEvent is done before showing any missing model exceptions; It's now possible to define models completely in-code (as illustrated by ModelBakeEventDebug). + +Build 1.8-11.14.1.1301: + LexManos: Bump version to 11.14.1 for next development cycle. + +Build 1.8-11.14.0.1299: + fry: Fixed tracking of UV locking state. Closes #1679 + +Build 1.8-11.14.0.1298: + LexManos: Fixed ItemFrames not having a model. Closes #1678 + LexManos: Updated FML: MinecraftForge/FML@22c9656196dbbea8ed983663d536c3ca272d7282 Reset S->C CustomPayload data after Write, allowing the same packet to be written multiple times. + +Build 1.8-11.14.0.1297: + LexManos: Fixed domain support in ArmorMaterial texture name. Closes #1675 + LexManos: Fixed Buttons not dropping anything when broken. Closes #1676 + +Build 1.8-11.14.0.1296: + LexManos: + Initial update to 1.8, Super beta. Most rendering related hooks are out due to major changes in 1.8. + + Some notes: + Almost all int x, int y, int z parameters have been changed to BlockPos class + ForgeDirection has been removed, replaced by net.minecraft.util.EnumFacing. + All FML classes have moved from packet cpw.mods.fml to net.minecraftforge.fml + Fluid Rendering has been disabled for the time being, to be re-evaulated and a test mod created for it. + Minecraft now uses a Model based system for rendering blocks and Items. The intention is to expand the model format to better suit modder's needed once it is evaulated. + As such, The model loaders from Forge have been removed, to be replaced by expanding vanilla's model format. + Metadata has been extracted out in Minecraft to IBlockState, which holds a list of properties instead of magic number metadata. DO NOT listen to the fearmongering, you can do EVERYTHING with block states you could previously with metadata. + Stencil Bits are disabled entirely by for the main Display, Modders must enable and recreate the FrameBuffer if they wish to use Stencil Bits. + LexManos: Fix local variable conflict in Forge patch and latest MCP mappings. + LexManos: Fix fog colors, Closes #1524 + LexManos: Fix acedential inversion causing some tress to not have leaves. Closes #1522 + LexManos: Fix creative picking a CommandBlock minecart returning wrong item. Closes #1523 + LexManos: Fixed crash with caomparators due to wrong position. Closes #1512 + LexManos: Fix inverted logic preventing blocks from breaking. + LexManos: Fix Entityies not taking damage correctly. Closes #1511 + LexManos: Fix wrong state being passed to Block.getDrops + LexManos: Fix potential NPE in Block.isToolEffective + LexManos: Update RecipeSorter for new 1.8 recipies. + LexManos: Fix destroy particles not being added. Closes #1528 + LexManos: Fix debug screen not showing grey background. Closes #1529 + LexManos: Fix not being able to place blocks in liquids, and related issues. + LexManos: + Updated FML: + MinecraftForge/FML@36644e97714b46dbbb24416febdde1332a3e753c Finalize modded handshakes in the World tick thread. Prevents potential CMEs when login event takes to long to fire. + LexManos: Fix interacting with entities. + LexManos: Fixed Entity extended properties init order. Closes #1532 + LexManos: Fixed Entities not being able to climb ladders, Closes #1535 + LexManos: Fixed snow layers not being able to stack more then twice. Closes #1534 + LexManos: Fix BlockPane's connection detection. + LexManos: Fixed vanilla bug where top part of double plants would flicker a tifferent texture before dissapearing. + LexManos: Fix NPE with BlockSnapshots that caused items with TileEntities to be used up in creative mode. + LexManos: Fixed vanilla issue where exceptions in World tasks would not be logged. + LexManos: Fixed blocks not breaking properly when instantly destroied. + LexManos: Fix stickey pistons not retracting properly. + LexManos: + Updated FML: + MinecraftForge/FML@9c8ca4a4e3c4acc4980535e5c60da169b75a7810 Unlink banner block and item id. Mojang should of matched these up but they didn't -.- + MinecraftForge/FML@84a101f344b8fc21de1201fde717fbcbcba2aa79 Update Dev mcp mappings to 11-30 snapshot. + LexManos: Remove debug patch I left in. + LexManos: Fix finding of spawn location for mobs. Closes #1546 + LexManos: Only call blockBreak when block itself changes, not just meta. Fixes bottles poping out of brewing stands. + fry: Added model bake event (allows mods to insert custom baked models, much like TextureStitchEvent allows to load custom textures), ISmartBlock/ItemModel (ability form models to react to block/item states), Block.getExtendedState, support for unlisted properties in block states. Includes example implementation of http://imgur.com/a/FyyJX + LexManos: Added Explosion Start and Detonate events to control explosion. + LexManos: Fixed bug in ServerConfigurationManager.transferPlayerToDimension where it would send the old dimension's information. + LexManos: Add "sand" to the OreDictionary + LexManos: Cleanup deprecated code, and TODOs in OreDictionary. Down-typed things from ArrayList to List. Asking for the ores with a null stack will now throw an Exception. + LexManos: Added CreateSpawnPosition event. + LexManos: Add LivingHealEvent called from EntityLivingBase.heal() + LexManos: Added PotionBrewEvent.Pre/Post. To allow for modification and cancelation of Brewing. + LexManos: Add quartz_ore tool init, more mojang special casing -.- + LexManos: Changed ToolMaterial's repair material to ItemStack version to allow metadata sensitive versions. + LexManos: Improved Control of Enchantment.canApplyTogether() in Mod Enchantments, allowing both enchantments to determine if they can apply together. + LexManos: Expand PlayerWakupEvent to expose the three parameters passed into EntityPlayer.wakeUp. + LexManos: Unbind Shaped/Shapeless Ore Recipies from Array list to normal List. + LexManos: Fixed NPE thrown when brewing event is fired and not all slots are filled. Closes #1564 + LexManos: Make daylight sensor recipe use ore dictionary wooden slabs Closes #1565 + LexManos: Fix missed patch causing Dispensed Armor to go into the wrong slot. Closes #1560 + LexManos: Fixed log spam when breaking DoublePlants. Closes #1555 + LexManos: Fix texture stitcher not using all avalible spaces. + LexManos: Fix EnumHelper for new ArmorTexture argument. + LexManos: Untie ItemModelMesher from using Item Ids internally by implementing our own simple mechanics using Trove. + LexManos: Fix userdev for new BlockState change. + LexManos: MinecraftForge/FML@e3785c28930a218cf9374458c67c34e7fba17922 Ensure that EntitySpawn and OpenGUI packets are handled in the world thread. Also log all errors that are thrown in FutureTasks. + LexManos: Remove our changes to Stitcher slot allocation. + LexManos: Fix incorrect logic in world change clumping. + LexManos: MinecraftForge/FML@5a4d362293fe70e1421d1f22c4a195944731d6ba Finish removing marker in mapping entry names. FMLMissingMappingsEvent/FMLModIdMappingEvent should fire with correct names now. + jadran.kotnik: Fixed messages not being added to the chat history and ClientCommandHandler not being called when sleeping. + LexManos: Fix BlockSnapshots not firing correctly due to patch mixup in 1.8 update. Closes #1591 + palechip: Fix Scoreboard rendering for the sidebar. + LexManos: Removed exclusion of white stained glass recipes in ore dictionary. + LexManos: Added chests to the ore dictionary. + LexManos: Fix crafting of non-oak fences/gates. + LexManos: Fix MC-30864 (sending web links in chat) + LexManos: Fix recipies for stone variants. + Chicken-Bones: Allow blocks to render in multiple layers + lumien231: Fixes #1603: Moving the start of the update thread to the pre init of the forge mod container + LexManos: Fix potential NPE when loading a single player world where you were saved in a unloaded dimension. Closes #1575 + LexManos: Call World.init from DimensionManager.initDimension Closes #1551 + LexManos: Made Chunk.fillBlock respect TileEntity.shouldRefresh. + LexManos: Fix value passed for Item.getModel useRemaining argument. Closes #1623 + LexManos: Silently eat exceptions when getting a TE's rendering bounding box, this 'fixes' Bukkit servers screwing up world data and causing clients to crash. + jadran.kotnik: Fixed NPE when canceling ClientChatRecievedEvent. Fixes #1644 + Parker Young: Re-enabled Icon setting for Fluids + LexManos: + Updated FML: + MinecraftForge/FML@a55e4124531119f1c9c023cff74cfa09b49ef0e0 Save the mod list of players in their NetworkDispatcher (Make it accessable for mods) + MinecraftForge/FML@69d479d46ae658c5a5c2c00081be3df38e38c748 Fixed getEffectiveSide() for Netty Server threads + MinecraftForge/FML@0f9a33cf14165ddd424a7d82c2178cf5854bf32f Exclude only log4j2 queue from class loader + jadran.kotnik: Don't skip the first line when rendering (debug) text. + fry: + Added model loader registry + + Entry point: ModelLoaderRegistry + loader interface: ICustomModelLoader + custom model: IModel + + ModelLoader is responsible for splicing into vanilla model system. + (you probably don't need to use it directly) + + Interop with vanilla models isn't great yet + (vanilla models can't refer to custom ones as parents), will improve in + the future. + + Includes loader for B3D models, with animation support + (net.minecraftforge.client.model.b3d). + Blender export plugin with compatible coordinate system: + https://github.com/RainWarrior/B3DExport + + OBJ loader is being written, will be included at some point in the + future. For now you can convert OBJ to B3D via blender, or wait. + techStackLp: + Closes #1552 + + Set the destination block the to the fluid. + In the previous code the destination block was still Air and would would + cause a crash because air doesn't have a property for LEVEL + fry: Removed leftover debug messages + LexManos: + Updated FML: + MinecraftForge/FML@d00feb58c762b0bbc506d79faf1ce40bc96732e9 Remove debug code that was causing console spam in Forge. + MinecraftForge/FML@1de3bf733aef754f15de55006b1750376871feb0 Fix FML's package for net.miencraftforge on maven. Fixes uploading of new builds. Note: 1.7.10 builds are bug fixes only while FML/Forge for 1.8 stabelizes. + MinecraftForge/FML@05ecefb53857ecc1dc52d4a577ed593c26da9659 Update to ASM5 for Java 8 support + MinecraftForge/FML@1112c455b9758c38eab385f48578bad17c0180f9 Merge pull request #595 from Grinch/master + MinecraftForge/FML@9c3013e02af1bd2f724d34a30e0b880b6e131645 Merge remote-tracking branch 'origin/1.8' + +Build 1.8-11.14.0.1295-1.8: + fry: Removed leftover debug messages + +Build 1.8-11.14.0.1294-1.8: + techStackLp: + Closes #1552 + + Set the destination block the to the fluid. + In the previous code the destination block was still Air and would would + cause a crash because air doesn't have a property for LEVEL + +Build 1.8-11.14.0.1293-1.8: + jadran.kotnik: Don't skip the first line when rendering (debug) text. + +Build 1.8-11.14.0.1292-1.8: + fry: + Added model loader registry + + Entry point: ModelLoaderRegistry + loader interface: ICustomModelLoader + custom model: IModel + + ModelLoader is responsible for splicing into vanilla model system. + (you probably don't need to use it directly) + + Interop with vanilla models isn't great yet + (vanilla models can't refer to custom ones as parents), will improve in + the future. + + Includes loader for B3D models, with animation support + (net.minecraftforge.client.model.b3d). + Blender export plugin with compatible coordinate system: + https://github.com/RainWarrior/B3DExport + + OBJ loader is being written, will be included at some point in the + future. For now you can convert OBJ to B3D via blender, or wait. + +Build 1.7.10-10.13.2.1291: + lukastenbrink: + Fix fluid tanks incorrectly reading NBT when empty + + If the Empty flag was set, the tank would not correctly read the data, keeping the outdated FluidStack instead. This is especially relevant with updatable TileFluidHandler TEs. + +Build 1.8-11.14.0.1290-1.8: + LexManos: + Updated FML: + MinecraftForge/FML@a55e4124531119f1c9c023cff74cfa09b49ef0e0 Save the mod list of players in their NetworkDispatcher (Make it accessable for mods) + MinecraftForge/FML@69d479d46ae658c5a5c2c00081be3df38e38c748 Fixed getEffectiveSide() for Netty Server threads + MinecraftForge/FML@0f9a33cf14165ddd424a7d82c2178cf5854bf32f Exclude only log4j2 queue from class loader + +Build 1.8-11.14.0.1289-1.8: + Parker Young: Re-enabled Icon setting for Fluids + +Build 1.8-11.14.0.1288-1.8: + jadran.kotnik: Fixed NPE when canceling ClientChatRecievedEvent. Fixes #1644 + +Build 1.8-11.14.0.1287-1.8: + LexManos: Silently eat exceptions when getting a TE's rendering bounding box, this 'fixes' Bukkit servers screwing up world data and causing clients to crash. + +Build 1.7.10-10.13.2.1286: + asiekierka: fix shouldRefresh being too broad in tile entity update + +Build 1.8-11.14.0.1285-1.8: + Chicken-Bones: Allow blocks to render in multiple layers + +Build 1.7.10-10.13.2.1284: + lumien231: Fix versionCheck config option + +Build 1.7.10-10.13.2.1283: + CovertJaguar: Bulk Chunk Data packets should also check TileEntity.shouldRefresh(). + +Build 1.8-11.14.0.1282-1.8: + LexManos: Fix potential NPE when loading a single player world where you were saved in a unloaded dimension. Closes #1575 + LexManos: Call World.init from DimensionManager.initDimension Closes #1551 + LexManos: Made Chunk.fillBlock respect TileEntity.shouldRefresh. + LexManos: Fix value passed for Item.getModel useRemaining argument. Closes #1623 + +Build 1.8-11.14.0.1281-1.8: + lumien231: Fixes #1603: Moving the start of the update thread to the pre init of the forge mod container + +Build 1.8-11.14.0.1280-1.8: + LexManos: Fix recipies for stone variants. + +Build 1.8-11.14.0.1279-1.8: + palechip: Fix Scoreboard rendering for the sidebar. + +Build 1.8-11.14.0.1278-1.8: + LexManos: Removed exclusion of white stained glass recipes in ore dictionary. + LexManos: Added chests to the ore dictionary. + LexManos: Fix crafting of non-oak fences/gates. + LexManos: Fix MC-30864 (sending web links in chat) + +Build 1.7.10-10.13.2.1277: + mattmess1221: Fix MC-30864 (sending web links in chat) + +Build 1.7.10-10.13.2.1276: + clashsoft: Fix Stained Glass pane rendering issues + +Build 1.7.10-10.13.2.1275: + Kittychanley: Removed exclusion of white stained glass recipes in ore dictionary. Closes #1502 & #1481 + +Build 1.8-11.14.0.1274-1.8: + LexManos: Fix BlockSnapshots not firing correctly due to patch mixup in 1.8 update. Closes #1591 + +Build 1.8-11.14.0.1273-1.8: + jadran.kotnik: Fixed messages not being added to the chat history and ClientCommandHandler not being called when sleeping. + +Build 1.7.10-10.13.2.1272: + jadran.kotnik: Fixed messages not being added to the chat history and ClientCommandHandler not being called when sleeping. + +Build 1.8-11.14.0.1271-1.8: + LexManos: Fix incorrect logic in world change clumping. + LexManos: MinecraftForge/FML@5a4d362293fe70e1421d1f22c4a195944731d6ba Finish removing marker in mapping entry names. FMLMissingMappingsEvent/FMLModIdMappingEvent should fire with correct names now. + +Build 1.7.10-10.13.2.1270: + LexManos: Remove our changes to Stitcher slot allocation. + LexManos: Fix incorrect logic in world change clumping. + +Build 1.8-11.14.0.1269-1.8: + LexManos: MinecraftForge/FML@e3785c28930a218cf9374458c67c34e7fba17922 Ensure that EntitySpawn and OpenGUI packets are handled in the world thread. Also log all errors that are thrown in FutureTasks. + LexManos: Remove our changes to Stitcher slot allocation. + +Build 1.8-11.14.0.1268-1.8: + LexManos: Fix userdev for new BlockState change. + +Build 1.8-11.14.0.1267-1.8: + fry: Added model bake event (allows mods to insert custom baked models, much like TextureStitchEvent allows to load custom textures), ISmartBlock/ItemModel (ability form models to react to block/item states), Block.getExtendedState, support for unlisted properties in block states. Includes example implementation of http://imgur.com/a/FyyJX + +Build 1.8-11.14.0.1266-1.8: + LexManos: Untie ItemModelMesher from using Item Ids internally by implementing our own simple mechanics using Trove. + +Build 1.8-11.14.0.1265-1.8: + LexManos: Fix texture stitcher not using all avalible spaces. + LexManos: Fix EnumHelper for new ArmorTexture argument. + +Build 1.7.10-10.13.2.1264: + LexManos: Fix texture stitcher not using all avalible spaces. Closes #1557 + +Build 1.7.10-10.13.2.1263: + LexManos: Fixed NPE thrown when brewing event is fired and not all slots are filled. + +Build 1.8-11.14.0.1262-1.8: + LexManos: Fixed NPE thrown when brewing event is fired and not all slots are filled. Closes #1564 + LexManos: Make daylight sensor recipe use ore dictionary wooden slabs Closes #1565 + LexManos: Fix missed patch causing Dispensed Armor to go into the wrong slot. Closes #1560 + LexManos: Fixed log spam when breaking DoublePlants. Closes #1555 + +Build 1.8-11.14.0.1261-1.8: + LexManos: Unbind Shaped/Shapeless Ore Recipies from Array list to normal List. + +Build 1.8-11.14.0.1259-1.8: + LexManos: Add quartz_ore tool init, more mojang special casing -.- + LexManos: Changed ToolMaterial's repair material to ItemStack version to allow metadata sensitive versions. + LexManos: Improved Control of Enchantment.canApplyTogether() in Mod Enchantments, allowing both enchantments to determine if they can apply together. + LexManos: Expand PlayerWakupEvent to expose the three parameters passed into EntityPlayer.wakeUp. + +Build 1.7.10-10.13.2.1258: + LexManos: Add quartz_ore tool init, more mojang special casing -.- Closes #1333 and Closes #1335 + LexManos: Fix invalid argument being passed to Block.isNormalCube from World.updateNeighbors. Closes #1339 and Closes #1346 + LexManos: Changed ToolMaterial's repair material to ItemStack version to allow metadata sensitive versions. Closes #1355 + LexManos: Improved Control of Enchantment.canApplyTogether() in Mod Enchantments, allowing both enchantments to determine if they can apply together. Closes #1434 + LexManos: Expand PlayerWakupEvent to expose the three parameters passed into EntityPlayer.wakeUp. Closes #1486 + +Build 1.8-11.14.0.1257-1.8: + LexManos: Fixed bug in ServerConfigurationManager.transferPlayerToDimension where it would send the old dimension's information. + LexManos: Add "sand" to the OreDictionary + LexManos: Cleanup deprecated code, and TODOs in OreDictionary. Down-typed things from ArrayList to List. Asking for the ores with a null stack will now throw an Exception. + LexManos: Added CreateSpawnPosition event. + LexManos: Add LivingHealEvent called from EntityLivingBase.heal() + LexManos: Added PotionBrewEvent.Pre/Post. To allow for modification and cancelation of Brewing. + +Build 1.7.10-10.13.2.1256: + LexManos: Fixed bug in ServerConfigurationManager.transferPlayerToDimension where it would send the old dimension's information. Closes #1548 + LexManos: Add "sand" to the OreDictionary Closes #1487 + LexManos: Added CreateSpawnPosition event Closes #1053 + LexManos: Add LivingHealEvent called from EntityLivingBase.heal() Closes #1282 + LexManos: Added PotionBrewEvent.Pre/Post. To allow for modification and cancelation of Brewing. Closes #1248 + +Build 1.8-11.14.0.1255-1.8: + LexManos: Added Explosion Start and Detonate events to control explosion. + +Build 1.7.10-10.13.2.1254: + LexManos: Added Explosion Start and Detonate events to control explosion. Closes #1469 + +Build 1.7.10-10.13.2.1253: + draco18s: + Update RenderBlockFluid.java + + Added tessellator calls to render the block's back faces, so that the liquid properly renders when the player is immersed in the fluid. + +Build 1.8-11.14.0.1252-1.8: + LexManos: Fix finding of spawn location for mobs. Closes #1546 + LexManos: Only call blockBreak when block itself changes, not just meta. Fixes bottles poping out of brewing stands. + +Build 1.8-11.14.0.1251-1.8: + LexManos: + Updated FML: + MinecraftForge/FML@9c8ca4a4e3c4acc4980535e5c60da169b75a7810 Unlink banner block and item id. Mojang should of matched these up but they didn't -.- + MinecraftForge/FML@84a101f344b8fc21de1201fde717fbcbcba2aa79 Update Dev mcp mappings to 11-30 snapshot. + LexManos: Remove debug patch I left in. + +Build 1.8-11.14.0.1249-1.8: + LexManos: Fix stickey pistons not retracting properly. + +Build 1.8-11.14.0.1248-1.8: + LexManos: Fixed vanilla bug where top part of double plants would flicker a tifferent texture before dissapearing. + LexManos: Fix NPE with BlockSnapshots that caused items with TileEntities to be used up in creative mode. + LexManos: Fixed vanilla issue where exceptions in World tasks would not be logged. + LexManos: Fixed blocks not breaking properly when instantly destroied. + +Build 1.8-11.14.0.1247-1.8: + LexManos: Fix BlockPane's connection detection. + +Build 1.8-11.14.0.1246-1.8: + LexManos: Fixed Entity extended properties init order. Closes #1532 + LexManos: Fixed Entities not being able to climb ladders, Closes #1535 + LexManos: Fixed snow layers not being able to stack more then twice. Closes #1534 + +Build 1.8-11.14.0.1245-1.8: + LexManos: Fix interacting with entities. + +Build 1.8-11.14.0.1244-1.8: + LexManos: Fix debug screen not showing grey background. Closes #1529 + LexManos: Fix not being able to place blocks in liquids, and related issues. + LexManos: + Updated FML: + MinecraftForge/FML@36644e97714b46dbbb24416febdde1332a3e753c Finalize modded handshakes in the World tick thread. Prevents potential CMEs when login event takes to long to fire. + +Build 1.8-11.14.0.1243-1.8: + LexManos: Fix potential NPE in Block.isToolEffective + LexManos: Update RecipeSorter for new 1.8 recipies. + LexManos: Fix destroy particles not being added. Closes #1528 + +Build 1.8-11.14.0.1242-1.8: + LexManos: Fixed crash with caomparators due to wrong position. Closes #1512 + LexManos: Fix inverted logic preventing blocks from breaking. + LexManos: Fix Entityies not taking damage correctly. Closes #1511 + LexManos: Fix wrong state being passed to Block.getDrops + +Build 1.8-11.14.0.1241-1.8: + LexManos: Fix fog colors, Closes #1524 + LexManos: Fix acedential inversion causing some tress to not have leaves. Closes #1522 + LexManos: Fix creative picking a CommandBlock minecart returning wrong item. Closes #1523 + +Build 1.7.10-10.13.2.1240: + LexManos: Fix creative picking a CommandBlock minecart returning wrong item. Closes #1523 + +Build 1.8-11.14.0.1239-1.8: + LexManos: Fix local variable conflict in Forge patch and latest MCP mappings. + +Build 1.7.10-10.13.2.1236: + xcompwiz: + Fixes client-side fake rain + + Changes the updateWeather function in WorldServer to only send the + weather info to players in the correct dimension, rather than all + players on the server. This is what causes the client-side rain, as the + client believes that it has started raining locally, rather than in + another dimension. + +Build 1.7.10-10.13.2.1235: + oliver.kahrmann: + Modify WavefrontObject to allow '.' in group object names + + Blender names objects with .001 ir .002 when separating vertices or duplicating objects and the importer would crash on them. This fixes the regex to allow dots in the name. + +Build 1.7.10-10.13.2.1234: + LexManos: Player sensitive version of Block.getPickBlock Closes #1348 + +Build 1.7.10-10.13.2.1233: + LexManos: Fix slots being black due to vanilla blending leakage Forge fixes. Closes #1325 & #1242 + +Build 1.7.10-10.13.2.1232: + luacs1998: + Create CONTRIBUTING.md + + Simple file (which github will show for those making PRs) containing guidelines for making PRs. + Feel free to comment if you want/need anything added. I can pull the same thing to FML too if you'd like, Lex. + luacs1998: + Update CONTRIBUTING.md + + Add link to wiki page on contributing + +Build 1.7.10-10.13.2.1231: + Adubbz: Fixed desert list initialization. Fixes #1447 + +Build 1.7.10-10.13.2.1230: + LexManos: Fix logic error in Blodd's Snapshot capture that caused blocks to not be updated to the client. Closes #1451 + LexManos: Bump version for new RB. + +Build 1.7.10-10.13.1.1229: + Abrar Syed: implemented crowdin support + matthewprenger: Add username cache for determining a player's last known username + azanor1: + Fix for biome weights under 10 + + This solves the problem where custom mod biomes with weights under 10 + not being generated in the world. + + Cleaned up the code and made the patch smaller + +Build 1.7.10-10.13.1.1226: + LexManos: Compleetly disable stencil bits unless told not to by using the -Dforge.forceDisplayStencil=true flag. Should solve the 'menu in bottom corner' issue with Intel Integrated graphics cards. + +Build 1.7.10-10.13.1.1225: + Parker Young: Added PlayerWakeUpEvent + +Build 1.7.10-10.13.1.1224: + Adubbz: Fixed biome weights not working with non multiples of 10 + +Build 1.7.10-10.13.1.1223: + LexManos: Fix vanilla lighting issue and blending issues in achievements gui. Closes #1445 + +Build 1.7.10-10.13.1.1222: + LexManos: MinecraftForge/FML@d00feb58c762b0bbc506d79faf1ce40bc96732e9 Remove debug code that was causing console spam in Forge. + +Build 1.7.10-10.13.1.1221: + LexManos: Disable by default the Display Stencil bits. Keep FBO bits. Acording to Mumfery and ChickenBones, it should not be nessasary and should solve the 1/4 main menu issue. Use -Dforge.forceDisplayStencil=true to enable old behavior. + +Build 1.7.10-10.13.1.1220: + jadran.kotnik: Prevent client only commands from bleeding through to the server. + +Build 1.7.10-10.13.1.1219: + bloodshot: + Added PlaceEvent and MultiPlaceEvent which fires before placing a block. + + Before calling "ItemStack.tryPlaceItemInWorld", a recording flag is turned on for + setBlock to capture a blocksnapshot for each block that attempts to be placed. + + If 1 block is captured, a "BlockEvent.PlaceEvent" is fired to notify mods. + If 2 or more blocks are captured, a "BlockEvent.PlaceEvent" is fired first with the first block + captured followed by a "BlockEvent.MultiPlaceEvent" with all captured blocks. This extra event + is required for items that have the ability to place 2 or more blocks such as a BlockBed. + + If either event is cancelled, the recorded block snapshot(s), item stacksize, and item meta will + revert back to the captured snapshot(s). + If the events are not cancelled, a notification will be sent to clients and block physics will be updated. + + What this means for mods is Forge will be able to capture all player block placement automatically and fire + a PlaceEvent and/or MultiPlaceEvent. + If for whatever reason your mod does not use the standard placement methods then you will need to fire the + appropriate placement events in order to notify mods/servers. + + This commit also includes a new utility class called BlockSnapshot which is serializable. This new class is used in conjunction with + both PlaceEvent and MultiPlaceEvent in order to record a snapshot of block space before it is altered. This + allows us to restore the block(s) if an event is cancelled. The class also provides the ability to restore a snapshot + to any location using the restoreToLocation method. This should be helpful to many mods that are looking to be able + to capture block data then restore it to back to any location required. + +Build 1.7.10-10.13.1.1217: + cpw: + GIANT FML UPDATE! Bump forge revision number, and fix patches for ItemStack changes. More to come on this branch I expect. + + MinecraftForge/FML@7c5cf219042581545b6073de4e947448ffa10879 Implement STDOUT/STDERR redirection. + MinecraftForge/FML@bc78e31cb7ad4eda6e5faa173cd6b21e70a2c444 added support for \n in tooltip strings added \n test tooltip localization fixed int/double conversion error in slider entry added test slider scenario that highlighted conversion error + MinecraftForge/FML@a2908e5c596bb5502bf455d468d2b1ead0520f55 Clean up a bunch of compiler warnings. + MinecraftForge/FML@7f67523d870ae150071c67b002597542eb206725 Update realms to 1.3.2 + MinecraftForge/FML@73f23c24b85240458f352f248e885684aaff4743 Merge branch 'std-redir' of github.com:Emberwalker/FML + MinecraftForge/FML@1c6b25df740a64c94d9ba05dd7e4412515abf5bb If an IO exception comes from the datawatcher, spew it all over the console don't discard it silently. Should stop pixelmon blaming forge for their mistakes. + MinecraftForge/FML@e77da9eb2f5c58a494ed100dd4c1dd1a0c341dbf And fix the read side too, incase someone is trying to bitbang and failing. + MinecraftForge/FML@305d8950c9332c7a7f290db05e6f18ef328016e2 Make LogContext optional. This can be useful for debugging mod issues, but Apache's implementation in log4j2 is responsible for a very significant % of the overall runtime. Quite frankly this is shockingly bad performance from what is supposed to be a high performance logging framework. Anyway, until we can figure out if we can fix it, we're turning it off by default. + MinecraftForge/FML@bdfca1c8ed463a6053526c7a46a990007711e3d0 Make more noise when people screw up mod downloading and put .jar.zip in their mod folders. + MinecraftForge/FML@21084941127fc882d9968316a8f0669531e484df Add a custom version range factory method. Should hush skyboy's complaints. Closes #486 + MinecraftForge/FML@7c1e6aaa40704001231e602ceaedfa21a5df1edf Add a delegate to every item and block. this should help with renaming fun stuffs. Also, fix all the tabs from my previous commits. *sigh* + MinecraftForge/FML@61fcb4df06dc968fcc31d3e4e524e574acfdbb3b Tweak Itemstack patch to always delegate to the method call. Set the field, so it's in sync. + MinecraftForge/FML@eb8c5ab146f2eb3ad3833d40607da97831278ffb Fix nested directory for language resources. Closes MinecraftForge#1264 + MinecraftForge/FML@7c05e5f70d5387512d0bee33ef99510ee5aac739 Default collections, so that we don't crash if useDependencyInfo is true. Closes #485 + MinecraftForge/FML@9729fe23326a3d4f6b03e60b5cdaf78a484b3657 Kill net.minecraft.src warning. It hasn't served a purpose in a long time now. Closes #313 + MinecraftForge/FML@21e875ef22eef6068ccd6df1bd71cf58cba48eed AllowPlayerLogins only after the server has completed the core init tasks. Closes #372 + MinecraftForge/FML@46cfeade80ae60ad2d8cdb40c5fdfdaeeaf16d00 Add a constructor to CustomModLoadingDisplayException. Closes #387 + MinecraftForge/FML@a6eab2683a15a0cceca7a0ded6095b746cdd017b Update README.txt + MinecraftForge/FML@f75838461cf6d9c5010cbfd2d9ef5ceec03268d7 Last part is the itemstack transformer. Itemstacks should now only be loosely coupled with the items within. + MinecraftForge/FML@51f24e9e6d1bee371cf23cdfd0071de7c5175417 First draft of add alias. It is probably not properly persistent atm. + MinecraftForge/FML@2a4c6424709b20ce1e9bda0d85ce7fac47d157c2 Finally fix stupid NPE error caused by FML trying to parse the super of Object in IDEA envs. + MinecraftForge/FML@c1b1417ee168523154a0edae68c3180814eab1c7 FML now supports passing a json formatted modlist as an argument, as well as a comma separated argument list. These facilitate modpacks mostly, by meaning you don't need to duplicate mods. The modlist is arranged in the maven style, with mods referenced maven-like. + MinecraftForge/FML@3d42cda2a2cf5b24e7a25537d883260857b2107a Build.Gradle Patch + MinecraftForge/FML@20c7add8455cd16a4551ed13336a9ad4f9770cd1 Merge pull request #484 from bspkrs/master + MinecraftForge/FML@26ed4b992eb6341d52d12fb6735415ab8e3c501d Clear button list on FML fatal error screens. The hidden cancel button should not be there. Closes #497 + MinecraftForge/FML@ebe4f5c5e297d5d59ce57138810627a9c7a1b412 Merge pull request #494 from AntonBoch1244/patch-1 + MinecraftForge/FML@ad0da05f5c78d7f3c35a331e993dd6e679fc7ac9 Fix the ItemStack transformer to find the method and field so it works with srg and mcp naming. + MinecraftForge/FML@65d380181a84d35a78791e1bc3c7712cd90506f6 Extend timeout for client to 5 seconds. Should fix Forge #1322 + MinecraftForge/FML@45486a0b6dfca65c4d1dd23176d4c9d13d46b6f5 Fix almost invisible NPE in TerminalTransformer when loading a non-existant class + MinecraftForge/FML@13da3efce07653732971837709ccf4de7e4c5c8e Allow a clean way to exit the game without big ugly warnings, but with logging information available if needed. Closes #496 + MinecraftForge/FML@fda305edfea15ba2015cede72327703f273f74e3 Some more tidying up of the exit handling + MinecraftForge/FML@b087f60c3379d0767247e51cbc3f7c631fe97a08 More cleanup of exit handling, also add a couple more noise classes to the list of things ignored. + MinecraftForge/FML@d6358a466b4614cfc35b403d756fe3ef550ebf50 Cleanup override warnings + MinecraftForge/FML@af7a58b9e50dbacf63cf4b5009abc52301609e1f Update to legacylauncher 1.10 and asm 5.0.3 + MinecraftForge/FML@e6d00440a612c235013f3f92f1756811139a6de0 ItemStack swapping + MinecraftForge/FML@8597e45a0e417948db483006aa54e899f28b05ac Fix NPE from a boolean + MinecraftForge/FML@b9b9daa8a9d1cac8550561f31f118589abc0c30a Fix ups from feedback. + MinecraftForge/FML@d89165021f33fbffb4563d86b30bd261506c6ea6 Mark the promise a success in the outbound handler. + MinecraftForge/FML@2e5ccf7988385d38b964c615776f23a1718f5c27 Update for launchwrapper 1.11. Fixes java 6 compatibility. + MinecraftForge/FML@641250d8536bad3af5a036b70dae94097176b420 Fix java 8u20. Closes #501 and a bunch of other bugs too. + MinecraftForge/FML@292be72639feded03ced26d9a06a98159f7a95b7 Allow client handshake to be reset by server to support BungeeCord. + MinecraftForge/FML@092873fbe5baaee53bee67d26d2fc6d3d003f095 Merge branch 'bungeecord' of github.com:bloodmc/FML + MinecraftForge/FML@134f2f8e8865a91292386a3738bb45bad0477a4b Fix bug with entityspawn - if the entity doesn't extend livingbase, it fails to write a headyaw byte, and everything will be derped for that packet. + MinecraftForge/FML@4852de81e02e2b6c6d006abe20d8497499fdf51f Wrap the server description box a little bit shorter. Stops the overlapping. Closes #489 + cpw: + MinecraftForge/FML@4ce3e73bfe36c02b10f504f93eff1bc94d640e32 Add overloaded version of SimpleNetworkWrapper#registerMessage that takes the MessageHandler instance directly, allowing to specify the same handler for multiple messages. + MinecraftForge/FML@cbe2ccbda461ec0ecf4d776fcd19ab31930cc3f1 Add in ModType to the jar manifest. If it's present, and doesn't have value "FML" it will be skipped from the modloading cycle. This should let liteloader mods have a .jar extension. + MinecraftForge/FML@37cf0174fc62a842d132b2c2cc31e477acfba205 OK, lets make that a csv list. It'll let you be liteloader and fml in one jar file! + MinecraftForge/FML@0475b15eb1a7c35bf4959f1af40606e6ee8a9d03 Change the mods and modListFile argument handling a bit. Other tweakers will get a chance at looking at them now - they're only removed right before launch. + MinecraftForge/FML@abeac06a2e9bf8825b058fa35291165b4d1f1fb3 Two new features. ModLists can have a "parent" mod list. Circularity will result in a crash, so be careful. Mods specified in a child will override ones from a parent (using the maven group:name:classifier triple to identify - ignoring the version component) + MinecraftForge/FML@7fcfedcfef9b5fd85cd1c17aa2013fca1bacd871 Canonicalized file paths in modListFile handling with the minecraftDirectory. + MinecraftForge/FML@633fce19d4b367aed56d79e916f17296842f675c Make Keyevent also fire for key releases + MinecraftForge/FML@57ba2339b630afa22c0fdf060bf28edbf7b34d0f Merge branch 'keyup-event' of github.com:diesieben07/FML + MinecraftForge/FML@1ff048062c7f122731619258a9e5a68a6111d5dd Merge branch 'simple-netw-improve' of github.com:diesieben07/FML + cpw: MinecraftForge/FML@dc02d56195606d3ba2f1c5036fc8c0ddb67c843f Fix derp with ModType annotation. mods should load again now.. + diesieben07: Added Item#isBeaconpayment + cpw: + MinecraftForge/FML@7ab69aff2e19b349e457c1b5fcab8b3b01d22af2 Clean up import + MinecraftForge/FML@c5a90bd456230b201522c268dd9bc5e80a0b57be Is vanilla possible with this mod load, side tests. + MinecraftForge/FML@cad11f3165505e6d725411a9fc2c2ee8362f5827 Allow injecting alternative container types. This is the core support code for allowing sponge plugins! + michafla: + check for IFluidBlock (in addition to Material.liquid) when + determining render height so that non-liquids (gases) render correctly + kat.swales: Fixed Clientside GameProfile UUID being null on offline mode + cpw: + MinecraftForge/FML@63b64482e6dd4c3e2226ec002ceee549045c35ed Add jsr305 dev-time dependancy for Nullable/Nonnull annotations. Unneeded at runtime. + MinecraftForge/FML@5365f5ea3e90ec85552bdb7f1f1237c51b4ea493 Add IEventExceptionHandler for EventBus to allow special handeling exceptions that are fired while running an event. Events now track what 'phase' they are in during the execution process. Each EventPriority is a 'phase'. An exception is thrown if the event attempts to set its phase to a previous one. + +Build 1.7.10-10.13.1.1216-new: + kat.swales: Fixed Clientside GameProfile UUID being null on offline mode + +Build 1.7.10-10.13.1.1215-new: + michafla: + check for IFluidBlock (in addition to Material.liquid) when + determining render height so that non-liquids (gases) render correctly + +Build 1.7.10-10.13.1.1214-new: + cpw: + MinecraftForge/FML@7ab69aff2e19b349e457c1b5fcab8b3b01d22af2 Clean up import + MinecraftForge/FML@c5a90bd456230b201522c268dd9bc5e80a0b57be Is vanilla possible with this mod load, side tests. + MinecraftForge/FML@cad11f3165505e6d725411a9fc2c2ee8362f5827 Allow injecting alternative container types. This is the core support code for allowing sponge plugins! + +Build 1.7.10-10.13.1.1213-new: + diesieben07: Added Item#isBeaconpayment + +Build 1.7.10-10.13.1.1212-new: + cpw: MinecraftForge/FML@dc02d56195606d3ba2f1c5036fc8c0ddb67c843f Fix derp with ModType annotation. mods should load again now.. + +Build 1.7.10-10.13.1.1211-new: + cpw: + MinecraftForge/FML@4ce3e73bfe36c02b10f504f93eff1bc94d640e32 Add overloaded version of SimpleNetworkWrapper#registerMessage that takes the MessageHandler instance directly, allowing to specify the same handler for multiple messages. + MinecraftForge/FML@cbe2ccbda461ec0ecf4d776fcd19ab31930cc3f1 Add in ModType to the jar manifest. If it's present, and doesn't have value "FML" it will be skipped from the modloading cycle. This should let liteloader mods have a .jar extension. + MinecraftForge/FML@37cf0174fc62a842d132b2c2cc31e477acfba205 OK, lets make that a csv list. It'll let you be liteloader and fml in one jar file! + MinecraftForge/FML@0475b15eb1a7c35bf4959f1af40606e6ee8a9d03 Change the mods and modListFile argument handling a bit. Other tweakers will get a chance at looking at them now - they're only removed right before launch. + MinecraftForge/FML@abeac06a2e9bf8825b058fa35291165b4d1f1fb3 Two new features. ModLists can have a "parent" mod list. Circularity will result in a crash, so be careful. Mods specified in a child will override ones from a parent (using the maven group:name:classifier triple to identify - ignoring the version component) + MinecraftForge/FML@7fcfedcfef9b5fd85cd1c17aa2013fca1bacd871 Canonicalized file paths in modListFile handling with the minecraftDirectory. + MinecraftForge/FML@633fce19d4b367aed56d79e916f17296842f675c Make Keyevent also fire for key releases + MinecraftForge/FML@57ba2339b630afa22c0fdf060bf28edbf7b34d0f Merge branch 'keyup-event' of github.com:diesieben07/FML + MinecraftForge/FML@1ff048062c7f122731619258a9e5a68a6111d5dd Merge branch 'simple-netw-improve' of github.com:diesieben07/FML + +Build 1.7.10-10.13.0.1208: + zlyfire.martin: + Update README.txt + + Add in reference to running setupDecompWorkspace to get decompiled classes + +Build 1.7.10-10.13.0.1207: + bernhard.bonigl: Write the correct default value for StringList comments in the config + +Build 1.7.10-10.13.0.1206: + LexManos: Fix AIOOB in BiomeDictionary. Closes #1326 + +Build 1.7.10-10.13.0.1205: + cpw: + Attempt to properly resolve this daft metadata and TE nonsense. This might be mod impacting, if you maintain a reference to a TE via neighbour update calls - you + might see two TEs for a single setblock where previously you saw one. This is a phantom TE being created by badly written neighbour triggers - I'm looking at you + redstone. + + Anyway, with luck, this'll close a slew of bugs across Forge, IC2, MFR, TE, RC. Yeah, fun times. Thanks to LexManos, skyboy and KingLemming for helping figure this + issue out. Quite frankly, from now on, issues with phantom TEs will be mods behaving badly. Modders will need to adapt. + +Build 1.7.10-10.13.0.1204: + LexManos: Fix invalid math in GuiContainerCreative. + +Build 1.7.10-10.13.0.1203: + porcariadagata: Add ItemStack sensitive version of getItemEnchantability + +Build 1.7.10-10.13.0.1202: + LexManos: Add ability for creative tabs that have search bars to customize the text box's width, and prevent the default set of enchanted books from being displayed in those tabs. Closes #1303 Closes #1301 + +Build 1.7.10-10.13.0.1201: + abab9579: + Skylight Hooks for Minecraft Forge + + Mainly for solar/lunar eclipse. + +Build 1.7.10-10.13.0.1200: + JeanGlassmaker: Adds getLocalizedName and getUnlocalizedName to FluidStack + +Build 1.7.10-10.13.0.1199: + vazkii: Fixed items with more than 2 render passes rendering weird in first person + LexManos: Fix patch screwup in Skyboy's Fishing PR -.- + LexManos: Fix metadata for every permutation -.- Closes #1294 + t.tomkins: + Legacy Liquid Load Fix + + nbt.getString("FluidName") no longer returns null, it returns an empty string. + + This patch allows legacy liquids to be resolved once again. + +Build 1.7.10-10.13.0.1198: + DemoXin: + * Added AT for ContainerRepair.stackSizeToBeUsedInRepair (Now public) + * Added ability to AnvilUpdateEvent to alter stackSizeToBeUsedInRepair (vanilla behavior is now reproducable) + * Added AnvilRepairEvent, fired when the player removes an ItemStack from the output slot of ContainerRepair, and allows the chance to damage the anvil to be altered. + +Build 1.7.10-10.13.0.1197: + skyboy026: Add FishingHooks + skyboy026: Update FishingHooks + skyboy026: Add EntityFishHook AT + +Build 1.7.10-10.13.0.1195: + rwtema: Fixed ItemFluidContainer always draining the maximum amount, regardless of the amount remaining. + +Build 1.7.10-10.13.0.1194: + LexManos: Closes #1280 + +Build 1.7.10-10.13.0.1191: + LexManos: Fixed bug that allowed duplication of Fluids with redstone dust. Closes #1279 + +Build 1.7.10-10.13.0.1190: + idont: - Added drainFluidContainer() and getContainerCapacity() helper methods. + +Build 1.7.10-10.13.0.1189: + Adubbz: Added an event for fog rendering + +Build 1.7.10-10.13.0.1188: + cpw: + Revert old light amortization patch. It seems to be breaking chunk sending pretty badly when more + than a couple of people are online. Tests indicate it is not useful anymore. + cpw: MinecraftForge/FML@3231db9376766d619f942b6a526718daa3c68038 Sorta revert 908491d5e7ac26becdac938f38cc90d6b9d73ce1 but merge assets into the map, rather than force overwriting. Fixes skyboy's comment. + +Build 1.7.10-10.13.0.1187: + LexManos: + Updated FML: + MinecraftForge/FML@53887ac59cec8f747e21fd251f94d5a438a69114 Hacky interm solution to #1207 to buy me time to re-write FML's network protocol. + +Build 1.7.10-10.13.0.1186: + LexManos: Fixed NPE that happens sometimes when exiting the game witout fully loading a world {main a dev-time thing} + LexManos: Made skulls respect Block.isReplaceable when placing, also prevented them from deleting blocks when placed at certain angels. Closes #1233 + +Build 1.7.10-10.13.0.1185: + LexManos: + Updated FML: + MinecraftForge/FML@9d40b761974f10ec2b5868a992260792f8a98e5d Don't scan ObjectHolders if there was an error already, derpitude will ensure. + MinecraftForge/FML@76538c1781d6d6a1e4134fb317af99e6f13b46cc Add a terminal transformer and tweaker. + MinecraftForge/FML@aec9228845e50107112bd1f8693f9b4729694c8b Add ExitVisitor to the TerminalTransformer that finds and intercepts any calls to Runtime.exit or System.exit. + MinecraftForge/FML@908491d5e7ac26becdac938f38cc90d6b9d73ce1 Move LaunguageRegistry call above normal asset loading to allow resource packs to override mod's language systems. + MinecraftForge/FML@d13295e28113a1c310d5bbb90ebfe241fefabe02 Fix FMLAT manifest AccessTransformers, class loader fun! + +Build 1.7.10-10.13.0.1184: + Tyler Hancock: + Changed exception message for duplicate enchantment ids to contain the + class path for both enchantments along with the enchantmnet id that has + been duplicated. + +Build 1.7.10-10.13.0.1183: + bspkrs: + Fixed missing assignment of constructor arg (thanks @Lunatrius) + + I must have edited this out when I was cleaning up my formatting commit spam. + +Build 1.7.10-10.13.0.1182: + vincent_a_lee: + Fix comment derp (+1 squashed commits) + + Squashed commits: + + [52c40bc] Fix experience orbs spawning at 32x coordinates clientside + + Add // FORGE comment + + Add // FORGE comment to clarify the purpose of the change + +Build 1.7.10-10.13.0.1181: + vincent_a_lee: + Fix chat opacity + + Add // FORGE comment + + As per convention, add // FORGE comment to clarify the purpose of the change + +Build 1.7.10-10.13.0.1180: + LexManos: + Updated FML: + MinecraftForge/FML@ab52901b8b47a525e2719cf280327e97bad7f91e Force preferIPv4Stack to true early in the load chain to combat netty loopback issues. + MinecraftForge/FML@11893fbbb76569417a415ae794494b8c1150a716 Add system property to skip doing world backups when game registry changes. This is SEVERLY ill-advised, if you do this DO NOT ask for any support. + MinecraftForge/FML@fdb6b34b8fc3f1e0c6beb7bfb940a01a309f1603 Update authlib and realms to latest json data. + MinecraftForge/FML@b3a74882b4d0d704d7061b9d896febb59ab0c269 added slider controls for numerics. default control is textbox, but slider can be used as a custom list entry class. fixed constructor javadocs in GuiConfig + MinecraftForge/FML@7c6d1f7568885ff677e34692ff87b1f0826dfd48 Merge pull request #468 from bspkrs/master + MinecraftForge/FML@692d955c1a5b6d0b8601ae88632ef42136d37393 Update tweaker login to use authlib. + MinecraftForge/FML@c2119eb1c1246ba37304d9e565b4430ed7056db1 Update realms library to 1.3.1, and implement network latch when connecting to Realms. Tested and working. + +Build 1.7.10-10.13.0.1179: + cpw: Add a system property for the stencil, in case config is not available.. + +Build 1.7.10-10.13.0.1178: + the.country.gamer: + RenderBlockOverlayEvent patch + + Fixes skewed XYZ parameters + +Build 1.7.10-10.13.0.1177: + LexManos: Fixed Enchantment.addToBookList Closes #1160 + +Build 1.7.10-10.13.0.1176: + LexManos: Add ability for modders to designate custom biome types. And remove note about automatically registering. Closes #1167 + +Build 1.7.10-10.13.0.1175: + diesieben07: Added hook for custom PotionEffect rendering in the inventory + +Build 1.7.10-10.13.0.1174: + the.country.gamer: + Added RenderBlockOverlayEvent.java + + Adds a Forge event which controls whether an overlay is rendered. + Overlays include: First-person fire, Block (when inside a block) + and water when a player is inside a water block. + + Patched for easier manipulation of event + + Fixed for Lex + + To be squashed + + Removed Contructor + + Added block XYZ parameters + + TODO, the second block overlay event’s XYZ might not be correct + Adubbz: Enhanced the Biome Dictionary with tags based on temperature, vegetation, moisture, trees and others + +Build 1.7.10-10.13.0.1172: + LexManos: Made EmeraldOre respect isReplaceableOreGen. Closes #1157 + LexManos: Added World to ChunkProviderEvent.ReplaceBiomeBlocks, and exposed metadata to End and Nether generation events. Close #1201 + +Build 1.7.10-10.13.0.1171: + tterrag1098: + Add AchievementEvent + + Allows modders to react to players receiving achievements, and cancel + them. + + Fix indentation + + More shortening + + Down to one line... + + Remove newline + +Build 1.7.10-10.13.0.1170: + LexManos: STENCIL buffer and DEPTH buffer, attempt a fix for GL errors. + +Build 1.7.10-10.13.0.1169: + alex grabriel: Added Javadoc comments for Forge Event documentation. + +Build 1.7.10-10.13.0.1168: + LexManos: MinecraftForge/FML@ac994e178a3533aa3c2ad8359aef9e5852c27a72 Scala people test your shit. + +Build 1.7.10-10.13.0.1167: + LexManos: Remove the BLEND enable in rendering damage bars. And exclicitly fix blend states in some GUI elements. + +Build 1.7.10-10.13.0.1166: + cpw: + MinecraftForge/FML@3ee86d0f3e47249030ba2309386f9120025e95c1 updated gradle wrapper to gradle 2.0 + MinecraftForge/FML@627ae73ea655277617912df48b03288ecc79ffea Merge pull request #464 from AbrarSyed/upgradle + MinecraftForge/FML@ee38c1b3f4642c567612f88070d7f9d651994aab Fix unneeded cast causing crash in new Config GUI system. + MinecraftForge/FML@eb92c35a2fa49a0fbe35a33e31cfb58e0674f78e updated run configs for GradleStart/Server classes + MinecraftForge/FML@70dcf80410a6d12c00300c00522582ee49ac4cc8 Merge pull request #465 from AbrarSyed/upgradle + MinecraftForge/FML@0ebdbe77a2b3503db43d36aec50c98ffb8366e20 Updated Scala to latest stable + MinecraftForge/FML@ddba18e6e33a9d9c5b113b1bfc0bfc82803b2607 Merge branch 'patch-1' of github.com:Soaryn/FML into scalaupdate + MinecraftForge/FML@220a37660b2656136c634b435afee6a915fc88fe Update realms to 1.2.9 + MinecraftForge/FML@abd7d0969bed5ce3d766f52b921c2b44e8ba87d2 Merge branch 'scalaupdate' + +Build 1.7.10-10.13.0.1162: + foka_12: + Added FluidStack sensitive version for Fluid's localised name + + Would be helpful for determining names for more complex FluidStacks (with tag compounds for example) + +Build 1.7.2-10.12.2.1161-mc172: + bspkrs: dupe quotes fix for category names + +Build 1.7.10-10.13.0.1160: + Gerard Bruwn: Add RenderItemInFrameEvent + +Build 1.7.10-10.13.0.1159: + LexManos: Fixed issue where Fire's 'fizz' would not play for the person who extinguished the fire. + +Build 1.7.10-10.13.0.1158: + ohai.iChun: Fixed inverted params in FogDensity use + +Build 1.7.10-10.13.0.1157: + LexManos: Add config option to disable attempting to creat screen with Stencil Bits. + LexManos: Add config option to specify the default spawn fuzz factor for the overworld. Closes #1190 + +Build 1.7.10-10.13.0.1156: + LexManos: Fix creative inventory tabs not blending base don items rendered. Closes #1179 + +Build 1.7.10-10.13.0.1153: + bloodshot: + Fixed wrong method call in ChunkIOProvider. + + When a chunk fails to load async, we fallback to the original sync method. + In this case, it was calling the async method twice which ended up causing + a stackoverflow. + +Build 1.7.10-10.13.0.1152: + cpw: MinecraftForge/FML@db219fb287b14fea5148ecdbf07d8ff08704c66a API is now able to "provide" and "own" itself. Useful for libraries without a Mod in them. To go along with this, you can now require an API, with a version, in your mod dependency string + +Build 1.7.10-10.13.0.1151: + bspkrs: fixed compounding quotes issue with category names that require quotes when save is called more than once + +Build 1.7.10-10.13.0.1150: + LexManos: Update to 1.7.10-pre4. + LexManos: Fix flower pots not droping the items that are inside them. + cpw: MinecraftForge/FML@06ab104c9ab798af6d2726e02a238211ff8124e1 Force the descriptors to the right type for the field they're referencing. Fixes the sand issue + cpw: MinecraftForge/FML@e1529845384f4935b7c11d4d36d25db51c0b9a31 Add support for mod access transformers without a coremod requirement. Use the "FMLAT" manifest attribute, with a space separate list of files that live in the 'META-INF' directory. They should conform to standard AT formatting. + cpw: + MinecraftForge/FML@5d6dc5dce37e488188d6fc468c16e8a6183a3610 Fix up other exit points. Should stop process hangs for clean exits. + MinecraftForge/FML@8a240ec3c7e4cf4c57beabdfe9bd408e57de1bdc Merge branch 'master' into mc179 + MinecraftForge/FML@0cd5ef6bb71cda1ef6add892d1247148bf1ecc15 Fix NPE when no FMLAT is defined + cpw: + MinecraftForge/FML@701d98eafa4d55144b166d26030818baa9b2f680 Added config GUI system + MinecraftForge/FML@50164db5c13c85636c7fda0e13bae1fc0aedc745 Merge branch 'master' of github.com:bspkrs/FML into bspkrsgui + MinecraftForge/FML@7eb36a1481aea9f68fa46bc199195769b27d904b Merge branch 'bspkrsgui' + MinecraftForge/FML@96a7e14a45404449fb72af6d2d5e1efd30003318 Merge branch 'master' into mc179 + MinecraftForge/FML@f45f18b1d71e1c1d12582faa337a19e73ed5fb18 Fix accessing guava from transformers + MinecraftForge/FML@8f7adced471951c798cfa6844b0abc176c93d19b Fix library issue. mojang auth requests newer libs, so we get them at dev time. But the mojang json doesn't refer them at runtime. So there's a lib mismatch. Fortunately all are available at mojang, so we can update the json. + cpw: Fix new method with Side.CLIENT when it shouldn't have it. Closes a bunch of reports of problems. + cpw: Clean patch cruft. + cpw: Fix mcp release number + luacs1998: + Update mc version string + + Or was I not supposed to? + cpw: Fix API incompatibilities. Should mean mods will work with new config changes. + cpw: + Update to MC 1.7.10, bump to 10.13.0 + + MinecraftForge/FML@bc420dcb0b086899e2aaa218a6f5bd7e91091a90 Fix Eclipse launching attribute + MinecraftForge/FML@1e0134a1ca97a1107ebbe604e5318e6f350fe9c4 Merge pull request #455 from rumickon/feature + MinecraftForge/FML@1c5db211afc9962fedb7fd8450abc45d07807634 Update for release 1.7.10 + MinecraftForge/FML@79a0c5e55905f0f08471d026b744a563ea421236 Merge branch 'mc179' + +Build 1.7.10_pre4-10.12.2.1149-prerelease: + cpw: Fix API incompatibilities. Should mean mods will work with new config changes. + +Build 1.7.10_pre4-10.12.2.1148-prerelease: + luacs1998: + Update mc version string + + Or was I not supposed to? + +Build 1.7.2-10.12.2.1147: + cpw: Fix API incompatibilities. Should mean mods will work with new config changes. + +Build 1.7.10_pre4-10.12.2.1146-prerelease: + bspkrs: + Added support for new FML config GUI classes + refactored lots of stuff based on comments + + added Configuration.load() exception handling and logging + cpw: MinecraftForge/FML@5d6dc5dce37e488188d6fc468c16e8a6183a3610 Fix up other exit points. Should stop process hangs for clean exits. + cpw: + MinecraftForge/FML@701d98eafa4d55144b166d26030818baa9b2f680 Added config GUI system + MinecraftForge/FML@50164db5c13c85636c7fda0e13bae1fc0aedc745 Merge branch 'master' of github.com:bspkrs/FML into bspkrsgui + MinecraftForge/FML@7eb36a1481aea9f68fa46bc199195769b27d904b Merge branch 'bspkrsgui' + cpw: Fix mcp release number + +Build 1.7.2-10.12.2.1145: + bspkrs: + Added support for new FML config GUI classes + refactored lots of stuff based on comments + + added Configuration.load() exception handling and logging + cpw: + MinecraftForge/FML@701d98eafa4d55144b166d26030818baa9b2f680 Added config GUI system + MinecraftForge/FML@50164db5c13c85636c7fda0e13bae1fc0aedc745 Merge branch 'master' of github.com:bspkrs/FML into bspkrsgui + MinecraftForge/FML@7eb36a1481aea9f68fa46bc199195769b27d904b Merge branch 'bspkrsgui' + +Build 1.7.10_pre4-10.12.2.1144-prerelease: + cpw: Clean patch cruft. + +Build 1.7.10_pre4-10.12.2.1143-prerelease: + cpw: Fix new method with Side.CLIENT when it shouldn't have it. Closes a bunch of reports of problems. + +Build 1.7.10_pre4-10.12.2.1142-prerelease: + cpw: + MinecraftForge/FML@701d98eafa4d55144b166d26030818baa9b2f680 Added config GUI system + MinecraftForge/FML@50164db5c13c85636c7fda0e13bae1fc0aedc745 Merge branch 'master' of github.com:bspkrs/FML into bspkrsgui + MinecraftForge/FML@7eb36a1481aea9f68fa46bc199195769b27d904b Merge branch 'bspkrsgui' + MinecraftForge/FML@96a7e14a45404449fb72af6d2d5e1efd30003318 Merge branch 'master' into mc179 + MinecraftForge/FML@f45f18b1d71e1c1d12582faa337a19e73ed5fb18 Fix accessing guava from transformers + MinecraftForge/FML@8f7adced471951c798cfa6844b0abc176c93d19b Fix library issue. mojang auth requests newer libs, so we get them at dev time. But the mojang json doesn't refer them at runtime. So there's a lib mismatch. Fortunately all are available at mojang, so we can update the json. + +Build 1.7.10_pre4-10.12.2.1141-prerelease: + cpw: + MinecraftForge/FML@5d6dc5dce37e488188d6fc468c16e8a6183a3610 Fix up other exit points. Should stop process hangs for clean exits. + MinecraftForge/FML@8a240ec3c7e4cf4c57beabdfe9bd408e57de1bdc Merge branch 'master' into mc179 + MinecraftForge/FML@0cd5ef6bb71cda1ef6add892d1247148bf1ecc15 Fix NPE when no FMLAT is defined + +Build 1.7.10_pre4-10.12.2.1139-prerelease: + cpw: MinecraftForge/FML@e1529845384f4935b7c11d4d36d25db51c0b9a31 Add support for mod access transformers without a coremod requirement. Use the "FMLAT" manifest attribute, with a space separate list of files that live in the 'META-INF' directory. They should conform to standard AT formatting. + +Build 1.7.10_pre4-10.12.2.1138-prerelease: + cpw: MinecraftForge/FML@06ab104c9ab798af6d2726e02a238211ff8124e1 Force the descriptors to the right type for the field they're referencing. Fixes the sand issue + +Build 1.7.10-pre4-10.12.2.1135-prerelease: + LexManos: Fix flower pots not droping the items that are inside them. + +Build 1.7.2-10.12.2.1133: + Christian: Null check the Item in the supplied stack as well as the stack itself. + +Build 1.7.2-10.12.2.1132: + Christian: And fix firing for single player loading. + +Build 1.7.2-10.12.2.1131: + Christian: Fix derpity derp. + +Build 1.7.2-10.12.2.1130: + Christian: + Fire an event when a player loads or saves from disk. Mods that want to load an additional + player related file from the players dir can now do so in that event. + +Build 1.7.2-10.12.2.1129: + Christian: + Some patch offsets + MinecraftForge/FML@7219061b05db73d245405ef777b412d0787398b6 Also patch in warnings for Vec3Pool - similarly removed. + MinecraftForge/FML@dff22045587b37282adeb2167486a572f51f1f16 FML now sets a security manager (FINALLY!). It's primary purpose at this point is to catch rogue calls to System.exit so that they can cause a proper crash report, rather than silently abandoning the game. + +Build 1.7.2-10.12.2.1128: + lumien231: Fixes a server crash caused by a player joining that is in a non existent dimension + +Build 1.7.2-10.12.2.1127: + thog92: Add missing 1.7 biomes to BiomeDictionary + +Build 1.7.2-10.12.2.1126: + nemesis: + Fixed ArrayIndexOutOfBoundsException in getOreName + + Added sanity check to prevent ArrayIndexOutOfBoundsException in getOreName for negative ids. + +Build 1.7.2-10.12.2.1125: + LexManos: Fixed vines generation for hanging off of trees. + +Build 1.7.2-10.12.2.1124: + bloodshot: + Don't call ChunkDataEvent.Load async + + ChunkDataEvent.Load must be called after TE's are loaded since this is + what mods expect. The event is handled by ChunkIOProvider during + callStage2. + +Build 1.7.2-10.12.2.1123: + bloodshot: + Load chunks asynchronously for players. + + When a player triggers a chunk load via walking around or teleporting + there is no need to stop everything and get this chunk on the main thread. + The client is used to having to wait some time for this chunk and the + server doesn't immediately do anything with it except send it to the + player. At the same time chunk loading is the last major source of file IO + that still runs on the main thread. + + These two facts make it possible to offload chunks loaded for this reason + to another thread. However, not all parts of chunk loading can happen off + the main thread. For this we use the new AsynchronousExecutor system to + split chunk loading in to three pieces. The first is loading data from + disk, decompressing it, and parsing it in to an NBT structure. The second + piece is creating entities and tile entities in the chunk and adding them + to the world, this is still done on the main thread. The third piece is + informing everyone who requested a chunk load that the load is finished. + For this we register callbacks and then run them on the main thread once + the previous two stages are finished. + + There are still cases where a chunk is needed immediately and these will + still trigger chunk loading entirely on the main thread. The most obvious + case is plugins using the API to request a chunk load. We also must load + the chunk immediately when something in the world tries to access it. In + these cases we ignore any possibly pending or in progress chunk loading + that is happening asynchronously as we will have the chunk loaded by the + time they are finished. + + The hope is that overall this system will result in less CPU time and + pauses due to blocking file IO on the main thread thus giving more + consistent performance. Testing so far has shown that this also speeds up + chunk loading client side although some of this is likely to be because + we are sending less chunks at once for the client to process. + + Thanks for ammaraskar for help with the implementation of this feature. + + This commit is based off the following : + + Bukkit/CraftBukkit@b8fc6ab2c12e9b4c8d7b5370e44f23cc838014b2 + Bukkit/CraftBukkit@85f5776df2a9c827565e799f150ae8a197086a98 + Bukkit/CraftBukkit@0714971ca2a31bc729bdd78ded8c69ffb2284813 + Bukkit/CraftBukkit@7f49722f457dcc31f8cac8e011871ff1b7fd3306 + Bukkit/CraftBukkit@53ad0cf1abe9c060ef411a86e9a16352f3e5197e + +Build 1.7.2-10.12.2.1122: + antoine.lucas.33: Add missing onLivingJump calls + +Build 1.7.2-10.12.2.1121: + LexManos: Pop version for new Recomended build. + +Build 1.7.2-10.12.1.1120: + Christian: Warn when chunks are being self-recursively loaded. This can cause serious issues. Modders should watch out. + Christian: MinecraftForge/FML@1a99ec7db612f258983c6ac685da906bf7cde0a6 Deprecate getAABBPool so people can stop using it in mods. Failure to do so will result in 1.7.10 upgrade incompatibility. Use getBoundingBox instead. + +Build 1.7.2-10.12.1.1119: + LexManos: Changed dustLapis to gemLapis to make OM SHUT THE HELL UP. + +Build 1.7.2-10.12.1.1118: + LexManos: Fixed missed metadata offset, and now cache return values of getOres for speed. + +Build 1.7.2-10.12.1.1117: + cojomax99: World fog color and density can now be controlled through an event + +Build 1.7.2-10.12.1.1116: + diesieben07: Fix not being able to change target & attackDamage for EnderTeleportEvent. + +Build 1.7.2-10.12.1.1115: + LexManos: Fixed inverted player parameters in PlayerEvent.Clone, Closes #1142 Closes #1140 + +Build 1.7.2-10.12.1.1114: + LexManos: Changed EntityWolf to EntityTameable in EntityLivingBase.attackEntityFrom, to allow for more custom pets. Closes #1141 + +Build 1.7.2-10.12.1.1113: + LexManos: Rework OreDictionary's internals to be a bit more speedy to help combat modders using it inapropriatly. Closes #1022 Closes #1131 + +Build 1.7.2-10.12.1.1112: + Christian: + MinecraftForge/FML@e3ce211cc798f4d86ca6f974d9ba8b4e389b4dc9 Nullcheck the dispatchers on players. Should stop some crashes when spamming connectivity. + MinecraftForge/FML@480bf2c1d078038bb59c4254a01a5af685c7cb22 Fix REPLY handling in SimpleNetworkWrapper. Closes #440 + +Build 1.7.2-10.12.1.1111: + LexManos: + Fix inverted parameters in OreDictionary.getOreID Closes #1123 + -.- Closes #1120 + +Build 1.7.2-10.12.1.1110: + Adubbz: Greatly simplified the addition of new biomes to the default world + +Build 1.7.2-10.12.1.1109: + LexManos: Added Noteblock change and play events. Closes #1027 #1025 + +Build 1.7.2-10.12.1.1108: + LexManos: Add target world to PlayerInteractEvent for potential 'cross dimension' interaction such as LittleBlocks. Closes #1071 + +Build 1.7.2-10.12.1.1107: + LexManos: Add a couple of localizations to Forge added strings. Closes #1068 + +Build 1.7.2-10.12.1.1106: + rwtema: Fixed setBlock not using the location-specific version of getLightOpacity() + +Build 1.7.2-10.12.1.1105: + LexManos: Filter all vanilla blocks that we missed through Forge's getDrops and BlockDrops events. As well as implemented IShearable for DoublePlants and DeadBushes. Mojang really should generic out some of this stuff instead of repeating logic all over the place! + +Build 1.7.2-10.12.1.1104: + LexManos: Fix patch fuzz + LexManos: Fixed GuiContainer calling button.mouseReleased. Closes #1116 + LexManos: Add comment to RotationHelper telling modders where to actually look, closes #1115 + +Build 1.7.2-10.12.1.1101: + diesieben07: + Add PlayerEvent.StartTracking and .StopTracking & make trackedEntityIDs visible + & Update, as discussed on IRC (squash) + +Build 1.7.2-10.12.1.1100: + vilim.lendvaj: Make finite fluid blocks drainable + +Build 1.7.2-10.12.1.1099: + LexManos: Fix enum helpers for EnumRarity {moved to Commn and changed paramter} and EnumCreatureType {new parameter} and added junit test for them. Closes #1009 + +Build 1.7.2-10.12.1.1098: + Christian: MinecraftForge/FML@1d41aa978d41267e4040ec449e10f49a20edd4fa Fix the side for the compatibility check. Should result in green ticks finally! + +Build 1.7.2-10.12.1.1097: + LexManos: Change IShearable JavaDoc by one line so Anti would shut up. Closes #1054 + +Build 1.7.2-10.12.1.1096: + Christian: MinecraftForge/FML@4512f8e5e316ddaf6a4fe35470f1f88dcdddae1a Warn when the objectholder finds nothing in the registry. Helps debug mismatched names. Also, actually make the scoping thing work with objectholder + +Build 1.7.2-10.12.1.1095: + fry: Added world display list render events + +Build 1.7.2-10.12.1.1094: + foka_12: + Fix getOreIDs not using the wildcard value correctly + + You can see it's not working by requesting the ore IDs from lapis, and you'll see the name "dye" is missing (and that's the one registered using the wildcard). + + Fixed it by inverting the order of the item stack parameters. + +Build 1.7.2-10.12.1.1093: + LexManos: Prevent duplciates in registered Ores in the OreDictionary and clean up some of the code, add new function to return all ores the specified ItemStack satisfies. Closes #1102 + +Build 1.7.2-10.12.1.1092: + vilim.lendvaj: + Fix fluid blocks + For https://github.com/BuildCraft/BuildCraft/issues/1843 . + +Build 1.7.2-10.12.1.1091: + LexManos: + Updated FML: + MinecraftForge/FML@3aba56440aa7a95f6431efcdcb5c127ebafc8891 lastIndexOf, Note Don't code while sick. + +Build 1.7.2-10.12.1.1090: + LexManos: + Updated FML: + MinecraftForge/FML@c828bb63c57cb10c23d9b1c3a6934e9f9ddba37b Make AccessTransformer change INVOKESPECIAL to INVOKEVIRTUAL when making methods visible + MinecraftForge/FML@a9aa468457a1eeed3366505b93e36da654610f05 Merge pull request #431 from diesieben07/at-invokevirtual + MinecraftForge/FML@31d726abad0dec6d1b853e9adf6a01580aee2af4 Fix the null networkHandler in the MessageContext + MinecraftForge/FML@725d988e36a7b104b9f5d8ae2daf993ac12af5bd Add in the objectholder, autopopulated by FML based on simple rules. Allows for reference driven substitution of mod blocks and items based on their server running state. + MinecraftForge/FML@f07bf5cb30a20ca9f62337512e936cfefcfbf0c4 Fixed deobfusication of nested inner classes. And removed legacy ModLoader remaps. + LexManos: + Updated FML: + MinecraftForge/FML@3a687f48b9606b4f9179d63ef0b831a25821ff8f -.- Save File First. My Bad. + +Build 1.7.2-10.12.1.1088: + LexManos: Add Glass, Colored glass, ore storage blocks, alines, and a few others to ore dicitonary. Closes #1011 + +Build 1.7.2-10.12.1.1087: + clashsoft: Update GuiScreen.java.patch + LexManos: Add new PlayerEvent.Clone called when an EntityPlayer is cloned via dimension travil or respawn. + LexManos: Made WorldGenShrub respect Block.canSustainPlant, Closes #1096 + +Build 1.7.2-10.12.1.1085: + delma: + Fluid events now know how much fluid is moved + + Added amount that is being filled/drained to the FluidEvent + + Added constructors without amount to ensure backwards compability + + Added deprecation to amountless constructors + +Build 1.7.2-10.12.1.1084: + LexManos: Fixed Stems not droping a random number of seeds based on metadata, Closes #1087 + +Build 1.7.2-10.12.1.1083: + xcompwiz: + Bug Fixes to Biome Decoration and Chunk + Fixes issue with biome decoration crashing on worlds with exposed void + Fixes same issue in JungleBiome decoration + Fixes forge bug in getting lighting from a block in chunk + +Build 1.7.2-10.12.1.1082: + LexManos: In Flower Forest biome a Poppy should spawn instead of Blue Orchid Closes #1078 + LexManos: Added Farmland to PLAINS type plants as that has changed in 1.7. Also made BlockTallGrass call it's super.canBlockStay to better support custom soils. Closes #1077 + LexManos: Added accessible instance to RenderBlocks and RenderItem for modders to use who don't wish to create there own instance. Warning: Other modders may influance the transient state of the instance, BE WEARY MODDERS. + +Build 1.7.2-10.12.1.1081: + Christian: MinecraftForge/FML@43e3ee1af1cab54db238dab4994076fdbe68bc6a Swap Listenerlist constructor around. Should fix parent resizing issue? + +Build 1.7.2-10.12.1.1080: + Christian: MinecraftForge/FML@70570a863ffa6a3ba7e2dd30b471bb47615b8bf8 Fix up possible CME + +Build 1.7.2-10.12.1.1079: + Christian: MinecraftForge/FML@503da3a2577a069b7847c158a27e8316c85ed852 Don't consider null NetworkDispatchers. This should fix a bunch of fakeplayer issues. + +Build 1.7.2-10.12.1.1078: + LexManos: Fully clear DimensionManager's DimensionID bitset when world is loaded. Closes #1074 + LexManos: Fixed No Blue Orchids spawn in swamp when using bone meal Closes #1072 + +Build 1.7.2-10.12.1.1077: + Christian: Fix forge validating strict versions on remote connections. + +Build 1.7.2-10.12.1.1076: + Christian: + MinecraftForge/FML@a8cbef2321a8e1bdfac56476bdfb5b306f71d38b Finally hopefully fully kills the race condition causing a classcast on slow machines. + MinecraftForge/FML@8dbd1ae0a177a556d03630a059242a2ee7f45e55 Fix ObjectIntIdentityMap sporadically matching non-identical objects. + MinecraftForge/FML@42713c66e565a26e963099baa838800f250089c3 Merge pull request #426 from sfPlayer1/master + +Build 1.7.2-10.12.1.1075: + Christian: + MinecraftForge/FML@d8b6adb2598ce144568a0aaf26fa8b988c028b7c Add a helper for casting some common collection types into generic form + MinecraftForge/FML@5275cea844a6afacc0deb41d153f01c1c25bb924 Try and see if there is anything to the identityHashCode collision hypothesis. If you see this in your error messages, kindly let us know! + +Build 1.7.2-10.12.1.1074: + LexManos: + Updated FML: + MinecraftForge/FML@a70308ef41f1e24074ea718f64caf75b8d6acba7 Update mcmod.info + MinecraftForge/FML@8555344eb33e4f0cc676defdb7391a24ebd5677d updated wrapper to gradle 1.12 + MinecraftForge/FML@1d5fc60f82e911c1abfbebbe781316126c02c987 Merge pull request #411 from matthewprenger/master + MinecraftForge/FML@3612ad0c25d103ba9bc81b32e8ecfef2dfc1cadc Attempt to fix another race condition related to reading NetClientHandler. + MinecraftForge/FML@c73a2076e3dd5d1f60c2fe2f589109cefa2dc6ce Fix potential rance condition in connecting to vanilla servers as well. And move latch into client side only. + MinecraftForge/FML@1436ac2f14fbdb48777c90b1b93378108c9cbf36 Fine use FMLCommonHandler. + MinecraftForge/FML@542e9acec1016c950c6f80af0c9da3190691359b documented dependencies + MinecraftForge/FML@ddc2cfbe864bd377232dbd1aa65df6e710d4639d Merge pull request #402 from AbrarSyed/patch-1 + MinecraftForge/FML@362ec8dee7ed2c291a8ed287c52eacdd80582eff Merge pull request #419 from Thog92/master + MinecraftForge/FML@b9de9ebc960bbf26e7aee570701aa4c226252fee Revert "Fix refreshResources not happening if an error occurs." + MinecraftForge/FML@738ce1d7cd5575269375066586d0a37881c536e2 Re-add removed genericiterable to clean a warning + MinecraftForge/FML@b0eb1ef7c6f4a63689898bf28f28e84d2dbae6e7 Split loadmods into loadmods and preinitmods, to allow resource loading to occur *always* between the two phases. This should fix mods not being able to access resources during preinit. + MinecraftForge/FML@de546bdf6cbeadb612cd6385bac8d54480073496 Clean up some missing generic info + MinecraftForge/FML@cd43eacbb25bc9cc0e81138844fa3aa7fd133037 Ensure that the loadcontroller is ready to preinit. + MinecraftForge/FML@f2fe80dc36972fe9db57e700380b6869abbc1832 Fixed default network mod checking to allow client side mods without the server side. Mods wishing to REQUIRE server side components must specify a custom check handler using @NetworkCheckHandler + MinecraftForge/FML@0c36868f92a3516c83ae363e13e5cb1db81236d1 Fix network disconnect with message on the client side in NetworkDispatcher. + +Build 1.7.2-10.12.1.1073: + bspkrs: Fixed unforeseen NPE + +Build 1.7.2-10.12.1.1072: + LexManos: + Revert "Implemented hashCode and equals in ItemStack, Closes #986" + + This reverts commit 0b01545a03942abca7b7ea28030be81e2ebeaa59. + +Build 1.7.2-10.12.1.1071: + LexManos: Implemented hashCode and equals in ItemStack, Closes #986 + +Build 1.7.2-10.12.1.1070: + LexManos: Fix extended entity properties being lost when leaving the end, This introduces the concept of calling IExtendedEntityProperties.init when entites/worlds change. Lets see if mods explode. + +Build 1.7.2-10.12.1.1069: + bspkrs: New GuiScreen events and a new ElementType DEBUG for RenderGameOverlayEvent + +Build 1.7.2-10.12.1.1068: + LexManos: Added new hook to WeightedRandom.getItem that allows for use of custom rnadom generators, prevents redundant code in mods. + +Build 1.7.2-10.12.1.1067: + LexManos: + Updated FML: + MinecraftForge/FML@2c56c32c5aa8842cfadaf8c237396cdb75673909 Fix saving backups with the raw name. Fix air block not being assigned as the default. + MinecraftForge/FML@d0f8073fa51db7426d5ded373f3404fa60d722f0 Merge pull request #413 from sfPlayer1/master + MinecraftForge/FML@810b1f3075e6061ab189e1f6975bd77b20040d71 Clean some generic warnings up. Make a generic list handler. Helpful for others I think too. + MinecraftForge/FML@fff86ee9d35874bdf77a1eaabe77615441644064 Fix refreshResources not happening if an error occurs. + MinecraftForge/FML@76d8d0e870a4e389167634283984dc10abb08e84 Fix mod version checking + MinecraftForge/FML@b84d0760ae47832e5b1e4d50237b582b2d50d520 Fix display of mod status at the server + MinecraftForge/FML@251af1d09dfbf636e2fb3f323a5345c81cc07aea Fixed memory leak on the client caused by Netty holding references to the World. + LexManos: Fixed hard references in WorldGenBigTree and ForgeCommand that caused worlds to leak in the client. + +Build 1.7.2-10.12.1.1066: + lhb: + Fix for Block.getExplosionResistance getting passed the wrong parameters + + It is being sent the x, x, y coordinates instead of x, y, z + +Build 1.7.2-10.12.1.1065: + CovertJaguar: + Fix issue with flexible rail return value + + Between 1.6 and 1.7 the return value to BlockRailBase.isFlexibleRail() + was inverted. While this is not a huge deal and could be worked around + by simply inverting your return value, it does mean its no longer + consistent with the function name and javadocs. + bioxx2007: Adds a new ReplaceBiomeBlocks Event constructor that supplies the metadata array if applicable and updates the ChunkProviderGenerate class to pass in the metadata array. + +Build 1.7.2-10.12.1.1061: + bspkrs: get a spelling checker :P + +Build 1.7.2-10.12.1.1060: + LexManos: Bump Forge version in prep for release. + +Build 1.7.2-10.12.0.1059: + LexManos: Try and fix invalid framebuffer depth/stencil setup, Thanks Ivoforce. Closes #1032 + +Build 1.7.2-10.12.0.1058: + apricefrench2d: + Fix infinite loop in RecipeSorter + + If recipe is multiple levels of inheritance from Object and not categorized, cls=cls.getSuperclass(); needs to be repeated more than once. It must therefore be moved to inside the while loop. + +Build 1.7.2-10.12.0.1057: + ohai.iChun: Fixes stencil buffers on platforms not supporting OpenGL 3.0 or higher. + +Build 1.7.2-10.12.0.1056: + LexManos: + Small wording change in license to allow for specifc differnet licnense contributions. + + Updated FML: + MinecraftForge/FML@e58562d3edfd1cd37fdc0a9e54181aed7433fdff Fix remaining issue with autoassigned Block and Item IDs overlapping. + MinecraftForge/FML@a82195772e539437911c25508168cb607659bc71 Registry: Block IDs after failing to find a mapping for them + MinecraftForge/FML@fd9389015fd5c6150155531bf1fffb38cfe9d551 Fix FMLMissingMappingsEvent.get + MinecraftForge/FML@5eebd4df718d65ac8426deba61e1ebb6ae2fde18 Registry: Implement support for remapping blocks/items to a new name. + MinecraftForge/FML@7325aa5033e7a5b5db79340777dd7a1c763315a0 Registry: cleanup, fix missing id error GUI formatting + MinecraftForge/FML@eb29d651ebda7086fe6d1f716295b087e2c17e6f Fix old 1.7 worlds with broken ID mappings + MinecraftForge/FML@6fd3c12a4a15a5cf38c421a94576a5cacd3fb7c1 Registry: allow handling missing blocks/items regardless of the mod id + MinecraftForge/FML@038fa17ad33aeba276db84ab170504fce884c1e7 Merge branch 'master' of https://github.com/MinecraftForge/FML + MinecraftForge/FML@49c623f59c440ba177adf2d76332ecee25e12236 initial attempt at a better way to ask the user in case of startup issues + MinecraftForge/FML@9be92dcfcb1c737025397c92b18ed027a6c7f4fa Registry: Complain about bogus registrations + MinecraftForge/FML@fd6d55afcc4f4c650c143ad43e09fbdc2cb9d850 Registry: Allow ignoring missing mods from the GUI, with confirm+backup + Registry: Add confirm+backup for automated corrupted id table fixup Require the user to confirm loading from a backup level.dat + MinecraftForge/FML@c47fc3b382434d435050b4ee02a02550b81f5717 Enable custom gui rendering only as required + MinecraftForge/FML@f77632df35dbf53fb31420fa86e6792f13257020 Remove unneeded entity spawn debug logging. + MinecraftForge/FML@c7adb42199a0684d8748451d39deb8326c0a2194 Registry: Repair mismatched ItemBlocks as well Fix a few misc issues + MinecraftForge/FML@c8a245a985779fd2545ee4b58a93270973aeb435 Registry: Fix debug info + MinecraftForge/FML@c8a0b72eba9265be608670424e1bd835a9d2f1e2 Registry: Complain about missing mods when repairing broken worlds Registry: Reduce console spam + MinecraftForge/FML@8e44006f432f1b36b826ff0469d99986a6051e4b Registry: Protect against putObject misuse, handle duplicate registrations better + MinecraftForge/FML@294c93212cd9f30c50b9d1a3b048a6141c45cdea Registry: Add support for registering ItemBlocks before their Blocks + MinecraftForge/FML@3b42b33b6ec4020b5032cae06760053ed135fae8 Merge pull request #400 from sfPlayer1/master + +Build 1.7.2-10.12.0.1055: + traincrazyb: + Small Fix: Held Items & Multiple Render Passes + + Passes beyond 1 now have the correct icon. + +Build 1.7.2-10.12.0.1054: + LexManos: Fix line offset in Minecraft patch, and mix RenderPlayer looping once to many on multi-pass items. + +Build 1.7.2-10.12.0.1053: + t.tomkins: Update PlaySoundEvent17.java + +Build 1.7.2-10.12.0.1052: + LexManos: Update access transformer, Closes #951 and #1021 + LexManos: Add NPE protection to GuiingameMenu.actionPerformed, Closes #961 + LexManos: Finally do SoundSystem workup for 1.7, Closes #982 + +Build 1.7.2-10.12.0.1051: + LexManos: Use BiomeGenBase's array size instead of hardcoding it in BiomeDictionary. Closes #871 + LexManos: Fix potential threading issue if FluidRegistry.loopupFluidForBlock is called from two threads at the same time before being setup. Closes #936 + +Build 1.7.2-10.12.0.1050: + LexManos: New hook to truely seperate the display of the 'durability' bar from the current / max durability. Allowing modders to control that display easier. + LexManos: ItemStack sensitive version of Item.getAttributeModifiers, Closes #816 + LexManos: Add ANIMALS tpe to PopulateChunkEvent.Populate Custom providers should call this function if they spawn animals curing population. Closes #790 + LexManos: Add AnvilUpdateEvent which is fired when a user places a item in both input slots of a Anvil and allows modders to control the output. Closes #838 + +Build 1.7.2-10.12.0.1049: + LexManos: Add position to BreakSpeed event. Closes #621 + LexManos: Advanced Model Loader available server-side for data driven models. To be cleanuped and re-evaluated in 1.8. Closes #773 + +Build 1.7.2-10.12.0.1048: + Abrar Syed: COnverted patches to SRG names + Abrar Syed: updated for ForgeGradle 1.2 + Abrar Syed: added .exe file.. fixed a bunch of patches + Abrar Syed: updated FML to latest master + Abrar Syed: fixed remaining noop patches and exc derp + LexManos: Update patches for new Fixed FernFlower used in FG 1.2. + +Build 1.7.2-10.12.0.1047: + reflex_ion: + This correctly uses the world height less one block for placement of a + Door. + + Required for placing doors inside a littleblocks area. + +Build 1.7.2-10.12.0.1046: + LexManos: MinecraftForge/FML@ef07de4f65ea16e1db1467845e316cb4c7d01a1f Fix hard link to DedicatedSerever when opening a LAN connection causing stalls on connecting. + +Build 1.7.2-10.12.0.1045: + LexManos: -.- Both null combinations. + +Build 1.7.2-10.12.0.1044: + LexManos: properly implement equals, sod off Player. + +Build 1.7.2-10.12.0.1043: + LexManos: Implement simple hash based equals in Fluid ContainerKey. + +Build 1.7.2-10.12.0.1042: + LexManos: Make StructureVillagePieces.Village public. + +Build 1.7.2-10.12.0.1041: + ohai.iChun: Fixes stencil bits not existing in Minecraft's framebuffer causing stencil test to not work. + +Build 1.7.2-10.12.0.1040: + LexManos: + Updated FML: + MinecraftForge/FML@e8b60441ccca8cccdc130560b4c8bf400aebc605 Reload game settings after mod loading is finished to capture mod keybindings. Closes #378 + MinecraftForge/FML@399770e572c9177babfb65a27280253023db2d9e Kill the modEventTypes list, register anything that extends FMLEvent, Fixes MissingMappingEvent handler, and any futureevents added. + MinecraftForge/FML@b7ad532ab5eb3e00d77ffde946d25675c9f69cf7 Re-enable post initalize texture pack reloading to allow Icons to be registerd through any init phase. + +Build 1.7.2-10.12.0.1039: + t.tomkins: + Small Fix: Held Items & Multiple Render Passes + + Passes beyond 1 now have the correct icon. + DemoXin: * Added Ore Dictionary entries and recipe replacements for Diamond, Emerald, Crops, Redstone, and Glowstone + DemoXin: * Fixed Items.glowstone to Items.glowstone_dust + +Build 1.7.2-10.12.0.1034: + LexManos: Fixed hashcode in FluidContainerRegistry, still needs a redesign. Closes #967 + +Build 1.7.2-10.12.0.1033: + ohai.iChun: Add cancelable RenderHandEvent. + +Build 1.7.2-10.12.0.1032: + LexManos: Fix a typo in our tile entity fix causing it to be ineffective. + +Build 1.7.2-10.12.0.1031: + LexManos: Fix items with color rendering incorrectly. + +Build 1.7.2-10.12.0.1030: + Christian: + Update Forge for patch changes + + MinecraftForge/FML@064b66af3d6c92b19821b88ec26cbb59577d68b4 Prevent players from logging in until server has finished starting. + MinecraftForge/FML@2aa73afa15908dadb0a033c49deb0ffefad2f265 Fix ExampleMod.java for build #1024+ + MinecraftForge/FML@c890206268da3c594d97198f5426b52ff6b8460c Try and handle removal of mods a bit better. Currently no way to allow a world which has missing blocks to load - but i have the code in place to allow it i think. + MinecraftForge/FML@995c204338cd601e118396d4b4ef8feb6e759037 Fix failing to load a world with missing mod blocks and items. There will be a way to force worlds to load when stuff is missing, but for right now, it will fail as this is "world safe". + MinecraftForge/FML@fa5f4c884272f415933329a9e914e0b7d052e31a Some argumentation + MinecraftForge/FML@45409bfa0c136078823a1aef1358396d92a269ee Prevent player dat files getting reset during disconnects. + MinecraftForge/FML@33100d6bab654a4bd59701b1ec2bf91caa3399da Merge pull request #371 from bl4ckscor3/patch-1 + MinecraftForge/FML@572d32358ab11e5916d91c4c7b9c04a70cfed2f6 Merge pull request #373 from bloodmc/master + MinecraftForge/FML@d0dd05a15c2eca9eabd308319c2ed85cb632922b FML expands S3F to support payloads up to 2 megs in size. Should be transparent + +Build 1.7.2-10.12.0.1029: + LexManos: Fixeed a missed -1 in SpawnerAnimals patch. Thanks Blood. + +Build 1.7.2-10.12.0.1028: + LexManos: Cull FakePlayers when worlds are unloaded. + +Build 1.7.2-10.12.0.1027: + LexManos: Use correct tag types when reading Forced Chunk data. Fixes ticket loading. Closes #964 + +Build 1.7.2-10.12.0.1026: + LexManos: Fixed FluidContainerRegisry.contansFluid closes #845 + +Build 1.7.2-10.12.0.1025: + LexManos: Fix AIOOB error with Endermen and blocks >256. Also better support for ID remapping. More to come later. + +Build 1.7.2-10.12.0.1024: + LexManos: + Updated FML: + MinecraftForge/FML@03fb1879d72fbd347badc140fed6c2c3191d2990 Fix obf error when right clicking a Empty Map. + MinecraftForge/FML@6bb9b8b9532b276450d03a3419e0da016aecead8 Clean up FMLEventChannel. Closes #367. + MinecraftForge/FML@b7b3450dcd123ab5df6b3693c9c2123bc3846b88 Update MCP mapping snapshot to latest crowdsourced names. + MinecraftForge/FML@8c9e8b52708bd0630303f8b5dc184ab60e2553a1 Fix isRemote, this is integral to so many parts of the code, everyone knows it by this name, People should not change it. + LexManos: Add the beginnings of a Constants class, to document/clean some of the magic numbers that are in the MC code base. + +Build 1.7.2-10.12.0.1023: + Christian: + MinecraftForge/FML@d87822ad8519da1c808e48bcc0a1bf8eb15c0095 Bump gradle wrapper to 1.10 + MinecraftForge/FML@359ac3ca2a941d70709168fbbbc0725c861668dd Ensure we check both item and block registries when finding valid IDs. Should fix #365 + MinecraftForge/FML@cee0f0b81179d307059843f08401f8700fb3ddb2 Tweak so that writing to the context will automatically send a message back to the originator in handshakeestablished. + Christian: Add a discriminator for fluididspacket. remove extraneous channel handler. + Christian: Fix up the event handler so it knows it's owned by forge + +Build 1.7.2-10.12.0.1022: + LexManos: Uncomment aa few FluidRegistry entries. + LexManos: Fixed issue where enchantment effects caused slight rendeirng issue. + LexManos: Fixed missed parens causing trapdoors to fall off incorrectly. + +Build 1.7.2-10.12.0.1021: + LexManos: Inital Fluid system update, untested. Still in progress. + +Build 1.7.2-10.12.0.1020: + LexManos: Fix NPE when breaking ice. + LexManos: Attempt a AIOOB error fix in tesselator when there are alot of transparent blocks in the rendering range. + +Build 1.7.2-10.12.0.1019: + Christian: + MinecraftForge/FML@544320b8d239df4a5ee2b3a7ec331ce2ec0a2c09 Beginning of a saveinspectionhandler. + MinecraftForge/FML@ab199c5811fe2d831592601d4f77691fbf82d1b8 Try harder to find a mod container. + MinecraftForge/FML@8633d780c925ebb719c37ac52e2f3db5f9957895 And make a loud message if there isn't a modcontainer found, substitute Minecraft. In general, this can only happen for coremods not properly registering their code. Closes #363 + +Build 1.7.2-10.12.0.1018: + LexManos: Fix imporerly efficient tools breaking blocks to fast. + +Build 1.7.2-10.12.0.1017: + LexManos: Fixed potential NPE in SlotCrafting, and added ItemStack sensitive version fo hasContainerItem. Closes #854 + LexManos: Adds a WeatherRender in the style of SkyRender, Closes #844 + +Build 1.7.2-10.12.0.1016: + LexManos: Move change of metadata to immediatly after change of Block, should prevent any 'invalid' tile entities from breaking created. Reference: #897 + +Build 1.7.2-10.12.0.1015: + LexManos: New PlayerUseItemEvents, Start, Stop, Tick and Finish. See PlayerUseItemEvent.java for more details. Closes #924 + +Build 1.7.2-10.12.0.1014: + LexManos: Make ItemBlock.field_150939_a public, closes #945 + LexManos: Missing EntityAITasks.tasks and MapgGenStructreIO register ATs, Closes #949 + LexManos: Implement PlayerPickupXpEvent, fired when a player aquires XP from a EntityXPOrb. Closes #942 + LexManos: Exclude cobblestone slab recipe from ore dictification, closes #940 + LexManos: Add the ability for custom records to have finer control over there sound resource location. Closes #933 + LexManos: Don't short circuit item icons for multiple render passes while being used. Closes #929 + +Build 1.7.2-10.12.0.1013: + LexManos: Fix Furnace stopping on 63rd Item, Closes #947 + +Build 1.7.2-10.12.0.1012: + Christian: + MinecraftForge/FML@b6d95d704b65dd8232ec8ddd333de378db8fe161 Name the log files properly. fml-junk is an early startup annoyance I can't kill because log4j2. + MinecraftForge/FML@8692ca17d13eda036b5ef996ec8e8706e7707d80 Log4j2 logging context for things. This should help add context when things go wrong in mods. + MinecraftForge/FML@a7ca131a337b5f0d4fc6f438626ac2d5b7771b3c And don't spam NONE everywhere + MinecraftForge/FML@741e172ffe163f0dd3018e1474af46ef0696396a Log4j2 doesn't need debug level logging for itself anymore + +Build 1.7.2-10.12.0.1011: + Christian: MinecraftForge/FML@458b0620b43116c943549a0f060c7e8830c2d77a Log the bad packet in a prettier way. Also, don't show the authlib debug data in the log file. + +Build 1.7.2-10.12.0.1010: + LexManos: Add BookCloning to the recipe sorter. + +Build 1.7.2-10.12.0.1009: + Christian: + MinecraftForge/FML@9a8d16b66e67691a4c83a9e1e236304e9f6d5139 Fix log4j2 config. Fix server gui to *show* logging. Fix log spamminess in the console. Fix bug in servergui that can cause deadlock. + MinecraftForge/FML@a355eecb2c14123964c6ae2402a0933d57ae9736 Add in error logging for outbound messages. Fix bug with indexedcodec NPE + MinecraftForge/FML@1c793abe0eef6846f681c9673019b0ebc49caaaf Fix derp with networkcheck + MinecraftForge/FML@675b5a07788ada17bc26a9c4f26598e77d2098cf And turn down some more logging, now we have useful logging back again.. + +Build 1.7.2-10.12.0.1008: + Christian: + MinecraftForge/FML@4aa2416ce5dcd8e77761703c018d1e7d08464025 Propagate Optional method removal to trait implementation classes + MinecraftForge/FML@fc025a7b73d9b3f46ecf2257227657592f5506b5 Logging Changes + MinecraftForge/FML@f0132a6f3b47e746a1a7df3ef84f4be989f140dd changed fml log level to all + MinecraftForge/FML@f23eba4352c38fd21e04e81f3db72c6cafe65a36 put max number of FML log files to 3 + MinecraftForge/FML@449ac98b77025eba38a75d0242113fffe26a8cf9 SSP Worlds updating from 1.6 will now pop a warning message before loading, and will capture a timestamped zip file in the minecraft dir before starting to load. Allows for people to test updates. + MinecraftForge/FML@3557fe31c92ea8d76c90052f9b8b6da963300c4f Throw an exception when discriminator is not found + MinecraftForge/FML@25240457283ba40c32022c97fc982c2ff4408e46 Make NetworkEventFiringHandler sharable + MinecraftForge/FML@dfc0899ec66f87502b5727939ac2f0ad0fabf89f Merge pull request #357 from jk-5/sharable + MinecraftForge/FML@79d42fca8d6b9d73204890ef0edb9d73cf075d87 Merge pull request #355 from jk-5/errorhandling + MinecraftForge/FML@7907e16e96de21e8ba536906ae71adcf02bfa535 Add a type adapter for artifact version. Should fix #354 + MinecraftForge/FML@7ac5bddbc3c227e0ed9385904a2bd9621078e2de Allow indexed messages to validate themselves. Also, catch exceptions from an embedded channel, and cause them to close the connection. It's ugly, but it means that the client doesn't crash if it connects to a screwy bungycord that's trying a 1.6 handshake for some reason. + MinecraftForge/FML@5adacc3b336bacbe30aa06175ef80c3aac08a62a Check the mod, not it's container, in the check handler. Closes #358 + MinecraftForge/FML@3d26f28bcf3e79e1f5fe20fcf056c604487dc35b Allow connection when server is apparently offline. Might allow :NOFML circumvention though. Hmmm. Closes #359 + MinecraftForge/FML@a62374d4aceac1c4ab39b3c0bae624ccbca65b6b findBlock should now return null, not the default block, if the thing being looked for is not found. Closes #352 + MinecraftForge/FML@6a695c4348d062af50b8cf5208530fc5036eba17 Try and stop the epic channel closed spam at close time. Closes #353 + MinecraftForge/FML@35a38d7840a5d0cd842005822c4ec6a9d3b65b6a Make sidedproxy support non-public fields. Closes #344 + MinecraftForge/FML@9d2e089df692655df04315a3822f43140015f3af Merge branch 'logging' of github.com:AbrarSyed/FML into abrar-borked + MinecraftForge/FML@79b04898d43d354714e09ce7e66efb5357ebcf61 And restore suppressions. ABRAR, DON'T TIDY CODE!!!! + MinecraftForge/FML@3dfb54e066ab91e44405706233f2dfffee9add72 Merge branch 'trait-optional' of github.com:RainWarrior/FML + MinecraftForge/FML@32bb7315cc6beff84f186a33e73219cc5280821a Add in example assets dir. Closes #308 + MinecraftForge/FML@16d33d298953b41dbbe3e3b504e800f4f46a3e1b Clean up and document outbound handler a bit better. Add in dispatcher target. Closes #361 + MinecraftForge/FML@5719b9ec533b3e43213dbafcb448221884efd9e8 Fix reply handling. Make the proxy message available for subclasses of indexedcodec. Fire user events into the network event firing. + +Build 1.7.2-10.12.0.1007: + LexManos: Add support in Techne models for the TextureSize tag. Closes #856 + +Build 1.7.2-10.12.0.1006: + LexManos: Updated FML: MinecraftForge/FML@444a7d7fa1cf7fad7dda67f581fa0e3be36069b7 Move placement of single player world load hook to fix NPEs. + LexManos: Fixed RenderWorldLastEvent never being called, was missed in 1.7 update. Closes #932 + +Build 1.7.2-10.12.0.1005: + LexManos: Fix flexible rails, Closes #944 + +Build 1.7.2-10.12.0.1004: + LexManos: Fix warnings in Forge codebase. + LexManos: + Updated FML: + MinecraftForge/FML@7c5d62704ac1d3e586f3bfe26265a534e5362c73 Make UniqueIdentifier final and add a hashCode. Closes #348 + MinecraftForge/FML@ff7b5845e7f6b300d413b917f57adc472a4ebcff Clean up some warnings about @Override + MinecraftForge/FML@275ccac6f14bc66b88c76b1040aa7167f995967c Fix NPE at startup + MinecraftForge/FML@2a5a8d0cd062d3feac9c4de234e3dab1ff4462e5 Fix memory leak?! + +Build 1.7.2-10.12.0.1003: + Christian: + Add exception logging to forge channel handlers as well + + MinecraftForge/FML@53557dcd0582e09f7f35eb3bc2fd130fba3be4a0 Put logging exception handlers on all channel inbounds. Fix problem with failure to login. Closes #350 + +Build 1.7.2-10.12.0.1002: + Christian: MinecraftForge/FML@9c96ca4402e4c231285f170281dd543bfffa191a Fire a custom packet channel registration/deregistration event, for any mods that care about that kind of thing + +Build 1.7.2-10.12.0.1001: + Christian: + MinecraftForge/FML@e14efe786f6255a18e148c4137f560f5e2d2a38f Some fixes and tweaks + MinecraftForge/FML@c013870b1df5e63bd84d92545ebdd434db74b5d1 Merge branch 'simplenet' + MinecraftForge/FML@30882b0c1d2743afebbebc288d73f25696e0815c Clean up some warnings. Add in simple network impl + MinecraftForge/FML@9cab2ab36e7981c847e3e9ae8c3fbbb36531ba6d Add in some tests and examples for the "simple" network stuff + MinecraftForge/FML@a429e106dd00b34302ec5893e0a8fc97c8fc8019 Fix bug with SSP, and hook so we can do confirmation of world loading, as well as other things + +Build 1.7.2-10.12.0.1000: + Christian: + MinecraftForge/FML@b362e8a2733eb3082975edfdf83c996f048b65d3 At the request of AbrarSyed. + MinecraftForge/FML@e344303ec7a5ed27c4378ff072a036df7a350902 Merge pull request #346 from Jezzadabomb338/master + MinecraftForge/FML@a4686b1261a9bad523b4efa8a36a4433a58897cc Added basic Mojang account authentication support for development time login. + MinecraftForge/FML@dd17979a2f6f02ac4a9dda09b52c96365cc5fec9 Fix bukkit connectivity issue. + +Build 1.7.2-10.12.0.999: + Christian: + Updated FML: + MinecraftForge/FML@1db3daa0e82e67fc27ca3d535a09c806c1a54d67 added override toString method for getting full name. + MinecraftForge/FML@acf74a34032224a73c4c03280cafa0042c35cf5a changed the readme to reflect new setup task. + MinecraftForge/FML@96c19b35807fa078cb18b4ae50567d0360bcdb03 undid readme change + MinecraftForge/FML@a89939e57e9ff061df3d53cf1cb075b31de5de1b Merge pull request #336 from jadar/master + MinecraftForge/FML@717a8d694532bd9438eed8d9cf4b57318b2b4cfd Fix csv string vs list of strings. Thanks immibis. Closes #334 + MinecraftForge/FML@584c0f368bca1d5b0223b5b3611b366b9a00f7d7 Fix potential ordering issue, clean up some imports + MinecraftForge/FML@28293b29ea65c30fe80c49e85e2ae15a4db68933 Add in a simple(ish) event driven network handling system. Register using newEventDrivenChannel and you'll get a simple network handler that will fire events at the subscriber(s) of your choice, whenever a packet is received. You'll also get some convenience methods for sending to things. + MinecraftForge/FML@80b00dc7966d96111e2ce8643db8e0f544c2bc89 Fix openGui. Closes #342 + MinecraftForge/FML@fc69bcf2807dc2b85eb52681ba9531cb3e2f1945 Fix up privacy derp in TickEvent. Closes #343 + MinecraftForge/FML@10d056a494aac22137b644cff341a5958e8168fc Fix possible NPE derp + MinecraftForge/FML@5da6dcc7e3607e5f107f6a7d39a4b4e1eb7fb306 Divert connection through FML, so we can deny connections to servers that don't want us + +Build 1.7.2-10.12.0.998: + ohai.iChun: Squash commits so Lex would stop whining. Fix erroneous position when getting player position with changed eye height. + +Build 1.7.2-10.12.0.997: + Christian: + Updated FML: + MinecraftForge/FML@d5bfd69e35b21f701390a8c4c4c58d7ec1fff1fc Fix problem with connecting to vanilla. SHOW what's modded and what's vanilla in the list. Hooks that make the blocking work to come + MinecraftForge/FML@dd098854b0b65b8509b8788422e02d989a991b87 Fix the keybinding array to the right one + MinecraftForge/FML@43068eb9862f280611f26f4107ff5ac2b42b08e4 Fix TargetPoint to be static + +Build 1.7.2-10.12.0.996: + LexManos: Attempt to prevent a NPE when MC renders a lot of things at once. + +Build 1.7.2-10.12.0.995: + minalien: Fixed MinecraftForgeClient for custom Item Renderer implementations. Removed check for forward-slashes (/) in texture asset locations (but left check for backslash in place). + +Build 1.7.2-10.12.0.994: + LexManos: MinecraftForge/FML@0d810c01fab99ac491c2277097a4198518fe6c75 Mark jopt needed on the server, herp derp, blame Abrar! + +Build 1.7.2-10.12.0.993: + LexManos: Deprecate BlockFire.func_149842_a, and throw exception if someone tries to set the burn properties for air. Should prevent 'The Air is on fire!' reports. + LexManos: Fix DoublePlant placement, closes #921 + +Build 1.7.2-10.12.0.991: + verybigbro: Create ru_RU.lang + +Build 1.7.2-10.12.0.990: + Christian: + Updated FML: + MinecraftForge/FML@5317672631f30e1c9655f0bb28dd8b158deea2fb Add a utility method for finding the channel handler name based on type. Should fix naming weirdnesses. + MinecraftForge/FML@9de9a1553086ebeeb5d5fc0f6d96da8680e52df0 Fix stupid hardcoding derp + +Build 1.7.2-10.12.0.989: + Vexatos: Create de_DE.lang + Vexatos: Update de_DE.lang + LexManos: Fixed pipeline naming issue in the ForgeNetworkHandler. + +Build 1.7.2-10.12.0.987: + LexManos: Fixing an infinite recursion case, Closes #916 + LexManos: + Models now load from resource packs + Models must now be loaded from resource packs using the standard resource pack reference. For example, to load a model named "assets/mymod/models/mymodel.obj", you would call AdvancedModelLoader.loadModel("mymod:models/mymodel.obj"); + Closes #670 + LexManos: Fix panes/iron bars not connecting correctly. Closes #904 + LexManos: Fixed the run config for dev time server, Cloases #913 + +Build 1.7.2-10.12.0.986: + Adubbz: Made canBeReplacedByLeaves default to whether a block isn't opaque rather than if it is, also uninverted the checks for canBeReplacedByLeaves in WorldGenBigMushroom, WorldGenSwamp, WorldGenTaiga1 and WorldGenTaiga2 + +Build 1.7.2-10.12.0.985: + Christian: Fix inversion + +Build 1.7.2-10.12.0.984: + Christian: + Updated FML: + MinecraftForge/FML@21b13d63512ce399c82cbb6b9042eefa6dcdaacd Lots of network cleanup. Gui packets now work too! + MinecraftForge/FML@b3f98d1ee0416aa452f8611d458968afdf50775a Fix derpiness with Mods button when Realms is available + MinecraftForge/FML@cdd9d92a4f8cd199e2d8a34bb398ef32e5f1e275 Starting work on the actual GUI. Still work to do. Needs an API. + MinecraftForge/FML@ab5eb3ccfff7f9ccfd8720b23fcef3131e54d57d Fix button size for GuiModList + MinecraftForge/FML@3113138bd1377d71afe3b8290e18511bfb6e5e97 Tweak button positions. + MinecraftForge/FML@c5e29b574a315d48668ebc9189bcc497a0eae13e Avoiding redundant calls to LogManager + MinecraftForge/FML@fbc1f8f6f9effa4a538880f9fec0ce5010226d09 Config GUIs in the modlist now work. + MinecraftForge/FML@fa4f3015a0d7147cbde3edec7664e78e5bcacbb9 Added transparent background for GuiIngameModOptions as per cpw's request. May not compile due to manual de-mcp-fication. + MinecraftForge/FML@7bf119e1e54cadff690ec31a4bab93c0d1d0aad1 Fix up readmes and credits. We no longer support modloader. + MinecraftForge/FML@779cd05aa1ced720a63cc508b82e68cc6fc8daa9 Tweaks + MinecraftForge/FML@b51fb913551a5116cc3b9bb7583b1666f280c650 Merge branch 'patch-1' of github.com:airbreather/FML + Christian: + Updated FML: + MinecraftForge/FML@6f1da6550e10164bd6c678829f111bb5de9383b6 Fix up mcpname derp in GuiScrollingList. + +Build 1.7.2-10.12.0.982: + Adubbz: Fixed sky colour transitions on a render distance of 16, fixed the WorldGen of various things + +Build 1.7.2-10.12.0.981: + jk-5: Update ForgeMessage.java + jk-5: Added a constructor and made the fields package-private + jk-5: Added default constructor for reflection + +Build 1.7.2-10.12.0.980: + LexManos: Update patches for AT changes. + LexManos: Fix inverted login in BlockPistonBase causing blocks to break incorrectly. Closes #910 #909 + +Build 1.7.2-10.12.0.979: + Christian: + Updated FML: + MinecraftForge/FML@22ba6fda5ee2dbf29dc03ba93ff9c7707edeaeee Expose the nethandler in a few places, and pull out FMLEmbeddedChannel, exposing a utility method on it. More to come. + LexManos: Update for the FMLEmbeddedChannel change. + +Build 1.7.2-10.12.0.977: + Christian: + Fix build.gradle for tweakClass property + + Updated FML: + MinecraftForge/FML@f36152398d1d287e7a55a31c77a2614cfb63e1b6 Add in the tweakclass, fix the json for lzma @ the server. + +Build 1.7.2-10.12.0.976: + Christian: + Updated FML: + MinecraftForge/FML@5d069629cf47cd04f2002b3b9a2c32b0ea73c26e Allow itemstacks for furnace recipe inputs. Allow passing extra arguments through registerblock into the itemblock constructor. + +Build 1.7.2-10.12.0.975: + Christian: + Updated FML: + MinecraftForge/FML@061288909de0f0452adf51a5a9935fd09992c801 Fire simple network connect/disconnect gameevents. + +Build 1.7.2-10.12.0.974: + Adubbz: Made BlockCrops.getDrops call its super method + +Build 1.7.2-10.12.0.973: + Christian: Fix the network handler for forge + +Build 1.7.2-10.12.0.972: + Christian: + Updated FML: + MinecraftForge/FML@34819c9303870f560232464a2d16eb46d152515c Make gradlew executable on linux + MinecraftForge/FML@53a1f9841421b41d543d7d1d51319b44c86a527e Attempt to load old pre-1.7 worlds. ENSURE YOU HAVE A BACKUP! + MinecraftForge/FML@6a5f9e135f88b662e4e01e8882f861448910ca90 Fix example mod code for 1.7 + +Build 1.7.2-10.12.0.971: + Christian: Allow tools to override their material harvest levels. + +Build 1.7.2-10.12.0.970: + Christian: Tidier implementation of previous commit. Should fix for subclasses of individual tools too + +Build 1.7.2-10.12.0.969: + Christian: Add in harvesting abilities of the items, should fix effectiveness + +Build 1.7.2-10.12.0.968: + Christian: + Updated FML: + MinecraftForge/FML@f8d6213829d570501166d64d7c8bb4977567131f Update render registry + MinecraftForge/FML@ec316f113fefef12f6defed9eb68de368d7f4420 AT for renderblocks + +Build 1.7.2-10.12.0.967: + LexManos: + MinecraftForge/FML@3714426e19f8f0edaaeda8c787993f8f3615a44d fix derp in example builscript + MinecraftForge/FML@01fb451b6918599de5e732d7ff30c761438ab930 Merge pull request #311 from AbrarSyed/patch-3 + MinecraftForge/FML@30d532f4fc6fc65ea7e79707a75ff4d6ea0ea031 Pass 1: Most patches are restored. + MinecraftForge/FML@53127eec308d3929d68d3d9fafabcfef37e95c37 Merge branch 'master' of github.com:MinecraftForge/FML + MinecraftForge/FML@7ab3c3a37ceb8ab945208206aec86739a2138329 Update gitignore + MinecraftForge/FML@38cec7a11fae7cf12bda3a8d16a50bb6136d8886 The basic network handshaking for FML is done. All scenarios seem to work. + MinecraftForge/FML@9f928963f20bc9bbfbe1391fb16c6f5ca5fd4344 A network design I like. It uses the netty embedded channel to allow mods to build channel pipelines on top of custom payload packets. + MinecraftForge/FML@58f7487cfaf4a25a8349021b9cca5ef4ba0b541c Check in patches. Add in some network timeout tweaking values so you can debug the network. + MinecraftForge/FML@e544adba5c7e9286f917342af2669e5888fa0a17 More cleanup. Bidirectional server <-> client network works for mods as well as FML|HS now. + MinecraftForge/FML@f5c38e2359c2e6eca13cd6606465ee36086a7113 OK, network channels appear to be working well for both dedi and integrated servers. The beginnings of the new mod structure too. + MinecraftForge/FML@9c96a0a10a5cbe34786be8fd41f9818b5ac929bc More network stuff, partially done id syncing. + MinecraftForge/FML@2aaaeba15eabdec189daa8662e9ffdf0b5a09dbe ID loading from the server save now works. + LexManos: Kill liquids finally. + LexManos: Bump data for 1.7 start. + LexManos: Some work on 1.7, waiting for Abrar to fix a few things. + LexManos: + Updated FML: + MinecraftForge/FML@a30f17362764f3e4e594386e193f9e4368e6836e Add sonatype snapshots repo for SpecialSource snapshots. + MinecraftForge/FML@b2550b8a693315ccc205f5315eac67c5283d7af9 Add mappings for Items/Blocks fields. + MinecraftForge/FML@57f7f1d7abd304d3e9f42567f1d66c10122e4ec6 Update for fixed Enum cleaning and names. + MinecraftForge/FML@99c681ad8736e4976053718c3d453b2fb30eefe0 Did it manually, forgot it needed the end comma + LexManos: + Updated FML: + MinecraftForge/FML@1d71c017f45aa7ed9d7d7c5ed5250a8d22477980 ID syncing. + MinecraftForge/FML@fd36f50d8210342f65cb0272bac56a3bcc42dd18 Cleanups + MinecraftForge/FML@89e4e483c204c11b6fdfed34893fc223a7d6a899 Add in a remapping event for mods to consume. + MinecraftForge/FML@cd417c6786256fa23f181ff0b76696bc6dfb0291 Fixed remote and local connections work with mods now. + MinecraftForge/FML@ef492407ef812bb6bbc7f0bd8efbd16d07efcafb Entity spawning works. + MinecraftForge/FML@d0d31d9575403eb2ec058898b86ffd99a9220f75 SpawnAdjustment packet. Clean up stuffs. No more compile errors. + MinecraftForge/FML@3e278acb71e4e3d0406e80f0fad5071c9215ed33 Fix stupid possible compiler error. + MinecraftForge/FML@009d4dee2328cc8d97b74177a2c5a3c359e6564a Fix the exc file. Fix the deobfremapper for handling inner classes. + MinecraftForge/FML@49cb893d12bd4f82b5d1b50d1e6517a256525d32 Fix exc this time *sigh* + MinecraftForge/FML@31efcfc3b2085f5d4e070ddab34a0be1481b4c6f Clean up patches for latest exc. + MinecraftForge/FML@7a4ceebf5efe5b3650080cf912e371d92fc70a55 Kill old patches and add rejects to ignore file. + MinecraftForge/FML@7ea571f593464ad4226ba845da27ff66161621b1 Fix AT, Fix exc. Almost works now! + MinecraftForge/FML@b852e302851cfaf77e1db6f86408e8d049703656 First functional release under reobfuscation. + MinecraftForge/FML@df870c1a3341d8e2e88d7fc3e2f3d9ed2507989f Update shiped ForgeGradle for 1.7 + MinecraftForge/FML@55aa337f952bc72c5a001a6ed661978b11822c63 Rename synthetic bridge methods, these methods are not decompiled, but need to reobf correctly cross the recompile boundary. + MinecraftForge/FML@0098c57f94808751062ee45f2ee267324bb42089 Merge pull request #316 from AbrarSyed/patch-4 + LexManos: Comment out fluids until King gets his hands on it + LexManos: Killed a few hundred compile errors. + Christian: + Moved the core event handler parts to FML. Implemented the Forge network handler based on the new + netty strategy. + + Updated FML: + MinecraftForge/FML@3b2994a3def35a2d3058960b71dc59dc48b802f9 Some patching touchups + MinecraftForge/FML@557357fe179529e0b44aab2f3fcef0c5adf981d5 Update for log4j2 + MinecraftForge/FML@a2b324beb2ef6ec73000678c9305fd70d4ec1643 Copy eventhandler from Forge into FML. It is going to replace a lot of the runtime event systems. + MinecraftForge/FML@4071ff38afe15fddf5db0be882f5627f503a37c6 Patch some GUIs. We're gonna add some basic mod gui config support. + MinecraftForge/FML@0b419ac79c307579f162d47e0388a9d75bcd0a6e Fire a user event down the channels when a handshake has occured. + Christian: + Updated FML: + MinecraftForge/FML@32561265fc935cd6639d5b2e086e879f375676fa Ticks, Player events, keybindings, all migrated to the new event driven system. + LexManos: Inital patch update for 1.7.2, Doesn't compile, not done yet. + LexManos: + Updated FML: + MinecraftForge/FML@a17489172cd54ca955548b15fa0669c9f95d7f45 Code to disable mods at runtime, or other times. + MinecraftForge/FML@85516d9588ebfadbba25f21b2f973e4e81abbaa6 ICraftingHandler, IPickupHandler are now both events. + MinecraftForge/FML@e4b63a1801b453797f5e820eb3f5bd42e6d43948 IWorldGenerator now has an ordering at registration time. This means the order of worldgen should be much more stable. + MinecraftForge/FML@ef3856f9a34e82a05cb2b7715e3611f8fb1a9a6b Update patches for Gradle's rename rewrite: MinecraftForge/ForgeGradle@19e7acf2a27a6c6ae60f6e8ab38337defddc16d3 + MinecraftForge/FML@31ea100b29dfdb4fc907e212c3d49a5240ca72a9 Working on id missing handling + MinecraftForge/FML@3e76dfba34aaba4397fc3fb2bd28e0d1f0abe3e4 More tweaking on id stuffs at worldload + MinecraftForge/FML@f860c8ad3bc7537f885b27c7f045b5b1140c05f4 bump to legacy launcher 1.9 with logging unification stuffs. + bloodshot: + Refactored BiomeManager stronghold add/remove methods to support new + + MapGenStronghold dynamic biome changes. + Changed InitNoiseGensEvent to pass a NoiseGenerator array instead of + NoiseGeneratorOctaves due to new NoiseGeneratorPerlin in + ChunkProviderGenerate. + Fixed worldgen crash caused by wrong metadata in Chunk patch. + LexManos: Get object based on identity not name. + LexManos: Forge uses the FORGE channel for packets. + LexManos: Fix MethodNotFound crash when shutting down internal server. + LexManos: + Fix: + Block placement/interaction + Tesselator crash due to wrong mapping + Missing isreplaceable check in world.canPlaceAt + Small foratting/logging cleanup + Temporarly commented out efficancy changes till I implement it. + LexManos: + Updated FML: + MinecraftForge/FML@58132ccda3a575f10fc209c421fd5d80e01164cc Add new required --accessToken to launch specs. + LexManos: Bump version to 10.12.0 to mark 1.7. + LexManos: Fix debug HUD rendering semi-transparently. + LexManos: Temporary fix for items rendering with effects on one layer. Restores default vanilla rendering, which is considered a bug in modded community. + LexManos: Move Grass {Flower} registry to BiomeGenBase as 1.7 made flowers Biome specifc, this means modders who wish to add global base flowers need to add them to all the biomes indavidually. + LexManos: Fixed accedential inverted logic that caused Potions to render incorrectly. Thanks iChun. + LexManos: Fix items rendering on the GUI with invalid state due to glint rendering changing it. Thanks iChun. + Christian: + Updated FML: + MinecraftForge/FML@156a9ae03a3c80bd1499a8e692c44a322ad9df62 Fix build script + MinecraftForge/FML@7d3b1250e8368886bed0e0da350a94abaa4b6247 Fix handshaking properly. Also, fix ID syncup. It now will completely freeze the idmap after preinit. This frozen map is used to inject "new" stuff into existing serverside worlds. Interesting sideeffect: remote servers lacking things will change the client, to also LACK ids for those things. watch for -1 ids in your remap events. Note: idmaps should be considered temporary per server instance. SERVERSTOPPED will restore "startup" state, as will client logout. + LexManos: + MinecraftForge/FML@c180d9b15735ce89a38c497acd65fa3fab595f77 Add 1.7.2 base json, Gradle will automatically download updated versions of this. Keeping it in the repo allows us to se + e what base json we have built our jsons off of. And if it changes update accordingly. + LexManos: Added constructor to WorldType, and delegated the BiomeLayer management to it. Also updated the access transformer for Item/Block classes. + LexManos: Forgot to regen patches... + LexManos: Resize pending tile updates when it goes over the curent length. Fixed AIOOB error. + LexManos: Add a version check mechanic to startup, it is done in a seperate thread and has a config option to compleetly disable it. This allows us to notify users of new recomended builds. Hopefully stemming the flow of outdated help request. Also adds a warning to the main screen if you are running a 'Beta' Forge. Which means a Forge for a new version of Minecraft that we have not promoted a recomended build for yet. + LexManos: Fix dig speed on redstone ore and obsidian. + ohai.iChun: Add render offset to event. + Christian: + Updated FML: + MinecraftForge/FML@268bbabee6ae3fa1d596bd18e172298e26dc9ce4 Fix handling world reloads when new stuffs are added + +Build 1.6.4-9.11.1.964: + LexManos: + Bump build for gradle fixes: + Now Builds for java 1.6 + Include version,json in universal + Fixed classpath issues in eclipse task. + +Build 1.6.4-9.11.1.963: + luacs1998: + Update readme for ForgeGradle + + Let me know if there's anything else to add or change. + luacs1998: Updated + luacs1998: Another update for eclipse users + luacs1998: Update README.txt + +Build 1.6.4-9.11.1.961: + LexManos: Updated FML: MinecraftForge/FML@c2b919d339e5f63271cfb67a77235c21c5c3b80e Don't validate signatures in dev env. + +Build 960: + Abrar Syed: Step 1: The Purge + Abrar Syed: update FML for gradle changes + Abrar Syed: Step 2: The Reformation + Abrar Syed: Step 3: The Rebirth + Abrar Syed: fixed versioning and stuff + Abrar Syed: added buildSrc to the gitIgnore + LexManos: Fix for new FML, and publish to maven local + LexManos: Update run configs. + LexManos: + Updated FML: + MinecraftForge/FML@e9a7660cb8961660186c7c23e61ab35f9c2dfb81 updated samples + MinecraftForge/FML@30894f7afadf5d3f3c3d5a54c3f904413d5f2309 Merge pull request #307 from AbrarSyed/master + MinecraftForge/FML@c4b8a393f90b00ad7ee4992ea4341ffb6d676abb Make the working directory the root of the eclipse workspace. + LexManos: Regenerate all patches, No functional change as added this is a formatting change only. + Abrar Syed: update build.gradle + porcariadagata: Make the gradle wrapper executable. + LexManos: Proper configuratuion name for jenkins. + LexManos: Fix build file pom closures. + +Build 1.6.4-9.11.1.953: + LexManos: Fix NPE on specific tile entities when the block break event is canceled. Closes #863 + LexManos: Fix NPE in FakePlayers when they are created in a purely client side environment. To remove in 1.7 as FakePlayers should be used for server side interaction with the world on a player's behalf, not for client rendering. + +Build 1.6.4-9.11.1.952: + Christian: + Updated FML: + MinecraftForge/FML@23baf3a8ce58cb8306189401a60647957ccbb4c2 Actually fix the nethandler code + + Update patches + +Build 1.6.4-9.11.1.951: + Christian: + Updated FML: + MinecraftForge/FML@b7f34629c3c47b92ee89d72b0dc935b4997cb009 Don't try and open GUIs on the server. + Christian: + Updated FML: + MinecraftForge/FML@da72640c7ef1f44c49f7f592fbdd193622a30b40 Way to go, missing import. *sigh* + +Build 1.6.4-9.11.1.949: + Christian: + Updated FML: + MinecraftForge/FML@6af42bc656dfb98972d034363352affc9e777805 Add in null protection for client/server sides of handleChat + Christian: Don't send openGui commands from the fakeplayer. Fixes thaumcraft and probably others. + +Build 1.6.4-9.11.1.948: + CovertJaguar: Fix Water/Lava Fluid Localization + +Build 1.6.4-9.11.1.947: + LexManos: Noop out FakePlayer.addStat. + +Build 1.6.4-9.11.1.946: + Christian: + Updated FML: + MinecraftForge/FML@3d25b4e793c59a9131a441d6c7a2d80cac9cd701 Add in the ability to strip interface references for specific interfaces - this is probably mostly useful for scala scenarios where sythetic methods are generated and is not a substitute for using Optional.Method where appropriate. Closes #300 + +Build 1.6.4-9.11.1.945: + onibait: Add block break events based on @bloodmc's initial 1.5.2 Pull Request + onibait: Add block break events based on @bloodmc's initial 1.5.2 Pull Request + onibait: Fixed formatting + onibait: + Cleaned up patches to BlockOre and BlockRedstoneOre + Fixed trailing whitespace (it bugs me too) + +Build 1.6.4-9.11.1.944: + Christian: + Updated FML: + MinecraftForge/FML@f4532410ec1dbf43ce15dfa78d07e5f7be408b08 Change a couple of warnings, as a prelude to 1.7- preinit is now required for all GameRegistry activity, and every item and block REQUIRES registration. + +Build 1.6.4-9.11.1.943: + Christian: + Updated FML: + MinecraftForge/FML@8f87021b0f1ae5b277ad4d1891761b7a7ae1ab71 Fix derp with custom properties. They work now! + +Build 1.6.4-9.11.1.942: + Christian: + Updated FML: + MinecraftForge/FML@bc57ff9e83803d804e9d5374d76273fcd68611f4 Fix recursive API dependency resolution. Allows nested APIs, such as BuildCraft's + +Build 1.6.4-9.11.1.941: + Christian: + Updated FML: + MinecraftForge/FML@de8ab934d8ae960ebc0dede16218ca1e9e488ebc Fix up duplicate entries + +Build 1.6.4-9.11.1.940: + Christian: + Updated FML: + MinecraftForge/FML@81fe1c9682234297443402a54e4b852ef49d0ba8 Add in an API marker for API type packages. This does several things: 1. Packages marked as API will generate a new "modid" (the provides) that can be depended on. 2. Packages marked as API will be searched systemwide, and anything declaring that package (even without the API marker) will get an implicit dependency on the API package. 3. The API package itself will get a soft dependency on the "owner" package. + +Build 1.6.4-9.11.1.939: + LexManos: Add new recipe sorter that is called after all mods are initalized. This is disabled by default in 1.6 to not break current worlds as it may change machine's recipy outputs. Will enable by default in 1.7. Players may enable it in the forge config. + +Build 1.6.4-9.11.1.938: + xcompwiz: + Adds a Check to prevent Biome Replacement + + Splits the BiomeGenBase constructor to create one which takes a flag + that indicates whether to insert the biome object into the biomeList + array. The standard constructor calls the new one with the default of + true. This allows biome wrapper-objects to exist. + +Build 1.6.4-9.11.1.937: + Christian: + Updated FML: + MinecraftForge/FML@dac7f590eabb326c4467dbc829b4aae1e4be2779 Modify ordering of networkmod registration and mod instantiation. This fixes VersionCheckHandler logging an incorrect failure message due to NPE. + MinecraftForge/FML@f0dc530b2833a1c89673208fe296dba5520671c1 Fix up documentation of VersionCheckHandler - it only ever accepted a String and only works on the NetworkMod annotated class + MinecraftForge/FML@243a21a353e6b7717f64008776928c7132110ddf Wrapping coremods as tweakers. Part 1. + MinecraftForge/FML@58a299aabcfadb4139f126a2d46b5247bede4185 Attempt to inject coremods as tweakers, so both can share a dependency ordering + LexManos: Format strings properly in MC's internal logger. Fixes resource pack case warnings. + +Build 1.6.4-9.11.1.935: + LexManos: Updated FML: MinecraftForge/FML@bf54d4d66799f2e58944095826d0722ed0120b1f Make each mod's EventBus log a child of it's main logger. + LexManos: Fix null pointer exception in BiomeDictionary causing the ChunkManager's config to not load/save. + +Build 1.6.4-9.11.1.934: + LexManos: Add wildcard versions of OreDict replacements, Closes #827 + +Build 1.6.4-9.11.1.933: + Christian: + Updated FML: + MinecraftForge/FML@da4337efbfa07b35f5883107768f9ba2f1b24b9b Fix up handling the new method signature data for NetworkCheckHandlers + +Build 1.6.4-9.11.1.931: + Christian: + Updated FML: + MinecraftForge/FML@f92962bbbbb90c19788a5dc2eafdc2eeefdd77ce Use null to empty, so missing values work. *sigh* + +Build 1.6.4-9.11.1.930: + Christian: Add in an event for zombie summoning. Allows for mods to control summoning behaviour, as well as custom summoned mob. + Christian: And remember to make the event class static *sigh* + +Build 1.6.4-9.11.1.928: + Christian: And allow for tweaking baby chance as well. + Christian: And set the RIGHT variable *sigh* + +Build 1.6.4-9.11.1.926: + Christian: Allow configuration of the zombie additional summoning mechanic. The vanilla mechanic is a little borked at times. + +Build 1.6.4-9.11.1.925: + Christian: + Updated FML: + MinecraftForge/FML@58577775d277a4408bda510534eb36841b08ced4 Very minor style fixes + MinecraftForge/FML@96be82343c25b83dd842ada8d6e8b66eb4e4ee00 Merge pull request #280 from mc10/patch-1 + MinecraftForge/FML@2714da10228020a6f2321f6c9a703f0d24fe1370 Primitive capability for tweakers to order. Add a "TweakOrder" integer property to your manifest, or accept the default of zero. + +Build 1.6.4-9.11.1.924: + LexManos: Prevent session from being printed to the console, also make sure the username is not empty. Causes a lot of bugs further down the line. + +Build 1.6.4-9.11.1.923: + Christian: + Updated FML: + MinecraftForge/FML@fc3e7647d2aff01146b1f5bd2ab6b57ef8e833e5 Support, and fix up, interface lists for Optional + +Build 1.6.4-9.11.1.922: + LexManos: Added some missing air checks to world gen features. + +Build 1.6.4-9.11.1.921: + LexManos: Fix repeated argument in CleintCommands. + +Build 1.6.4-9.11.1.920: + LexManos: MinecraftForge/FML@a381874bb9c3bdeeb508bb81719b4d210eb29696 Delay sound system backend initalization to speed up startup and prevent race condition on some computers. + +Build 1.6.4-9.11.1.919: + reflex_ion: + Added PlayerOpenContainerEvent and added ForgeHooks.canInteractWith + + - Used to override the canInteractWith during player tick + - setResult to ALLOW/DENY as required + - Defaults to Vanilla behaviour in any other instance. + + Required for LittleBlocks Mod and to Assist Gullivers Mod + +Build 1.6.4-9.11.1.918: + Christian: + Updated FML: + MinecraftForge/FML@bc64ceabef76b1f4667b22ca8241b72351b44338 Optional shouldn't be constructable itself. It's purely a wrapper thing. + MinecraftForge/FML@55525f6d2eb24f42c26a291b8ce98feb4d4498c9 ModLoader is officially deprecated. It will all cease to be with 1.7. + +Build 1.6.4-9.11.1.917: + Christian: + Updated FML: + MinecraftForge/FML@63ba3aa0099f43183315fb4e16f9e8e8007362f8 Add in support for Optional interfaces and methods. Be gone coremods! + +Build 1.6.4-9.11.1.916: + LexManos: Fix missing patch which caused per-world storage to not be saved. + +Build 1.6.4-9.11.1.915: + rhilenova: Added pre/post to player list rendering in GuiIngameForge. + rhilenova: Moved PLAYER_LIST event inside display check. + +Build 1.6.4-9.11.1.914: + LexManos: + Make isItemStackDamageable() pass the stack to getMaxDamage() to use the Forge version of getMaxDamage(). + Fixes display issues with mods using getMaxDamage(ItemStack) instead of the vanilla one. Closes #805 + LexManos: Bump version number for todays changes. + +Build 1.6.4-9.11.0.913: + ben.blank: allow blocks to choose how they handle indirect power + ben.blank: move `shouldCheckWeakPower` to Forge section + +Build 1.6.4-9.11.0.912: + jrtc27: Pass arguments to install.sh and install.cmd to install.py + +Build 1.6.4-9.11.0.911: + LexManos: Add cancelable EntityStructByLightningEvent, Closes #789 + +Build 1.6.4-9.11.0.910: + LexManos: Stack sensitive version of Item.getItemStackLimit. Closes #771 + +Build 1.6.4-9.11.0.909: + Anthony Lomeli: Villager Trading GUI will not open if Player is sneaking. + +Build 1.6.4-9.11.0.908: + LexManos: Added all the vanilla records to the ore dictionary. Closes #731 + +Build 1.6.4-9.11.0.907: + LexManos: Direct canApplyAtEnchantingTable through canApply Closes #740 + +Build 1.6.4-9.11.0.906: + LexManos: Add pre and post event to rendering Chat, allowing for placement of the chat box. Closes #733 + +Build 1.6.4-9.11.0.905: + LexManos: Set densityDir in BlockFluidBase's constructor, closes #737 + +Build 1.6.4-9.11.0.904: + LexManos: Fix placement of snow cover over metadata 6. Closes #724 + +Build 1.6.4-9.11.0.903: + LexManos: + Add the ability to register chat commands that only execute on the client. Works with autocomplete. + Client commands are gray when shown in the autocomplete list (when you press tab) + Closes #640 + +Build 1.6.4-9.11.0.902: + LexManos: Update workspace to point at launchwrapper 1.8 + LexManos: Vanilla hopper should obey the IInventory contract, TileEntityHopper now takes into account IInventory.getInventoryStackLimit() when inserting items Closes #597. + +Build 1.6.4-9.11.0.901: + hobos_taco: + Added ItemTooltipEvent + + This event is fired at the end of ItemStack.getTooltip(EntityPlayer, boolean), which in turn is called from it's respective GUIContainer. It allows an itemstack's tooltip to be changed depending on the player, itemstack or whether the advanced information on item tooltips is being shown, toggled by F3+H. + +Build 1.6.4-9.11.0.900: + Christian: + Updated FML: + MinecraftForge/FML@5265e34a350adbb762264379f0134bfa40d33eaa Fix null killing the server + +Build 1.6.4-9.11.0.899: + LexManos: MinecraftForge/FML@35ab9f52b02d84592e4c7607feb6009710b2f7d9 Fix md5s for new checksums.sha1 in scala libraries. + +Build 1.6.4-9.11.0.898: + Christian: + Updated FML: + MinecraftForge/FML@e356f4d713b1269825839954fe86f5312ede0fc6 Cross-modsystem compatibility fix with thanks to Mumfrey @ liteloader + MinecraftForge/FML@9b55f1f48f89a5348ac1d58622b71946f310316a Attempt at a shared modlist implementation - should allow visibility between liteloader and fml for "mod list display" + +Build 1.6.4-9.11.0.897: + Christian: + Updated FML: + MinecraftForge/FML@bfc25bc5da1ff0f6fd0faf817b32a8f6d35dedc2 Add to both the classloader and the parent + +Build 1.6.4-9.11.0.896: + Christian: + Updated FML: + MinecraftForge/FML@9f0f9e7288afc6cce9a425ad770a208af9e28648 Fix deobf tweaker + +Build 1.6.4-9.11.0.895: + Christian: + Updated FML: + MinecraftForge/FML@ce6404fd5bb5e8e425af3bcafeaa285575bf39a3 TYPOS!!! + +Build 1.6.4-9.11.0.894: + Christian: + Updated FML: + MinecraftForge/FML@8f18a3de9a02b003762dace891829ef64dfedf49 Separate deobf tweaker so it runs last. Should fix problems with cascaded tweakers expecting an obf environment. + +Build 1.6.4-9.11.0.893: + Christian: + Updated FML: + MinecraftForge/FML@8e26c99de3b44d272d2fdc398e0687db17bce3b7 Add debugging for deobfuscation + MinecraftForge/FML@1d902df5814b815959165e4aa69272003f002d25 Use the negative cache in latest legacylauncher. + MinecraftForge/FML@9815d8c3793182a08fcdbd29376a3f70bff464d0 Update for launchwrapper 1.8 + +Build 1.6.4-9.11.0.892: + LexManos: Add wrapper exception to the new Structure ID system to point to the correct Structure. + +Build 1.6.4-9.11.0.891: + LexManos: Update dev workspace for 1.6.4 .. + LexManos: Remove some side onlys on BiomeEvents that don't need them. + LexManos: Fixed typo in bounding box based ladder checks that caused potential infinite loops with entities in certian positions. Thanks Overmind for reporting it. + LexManos: + Updated FML: + MinecraftForge/FML@fc8c3bef0380d59c0842a252e4f0bd29127ee78b Update to new installer that uses xz compression and better support for non-standard jvms + +Build 1.6.4-9.11.0.886: + Christian: + Updated FML: + MinecraftForge/FML@a4de22c1addf0a6b95d38e467a96f2af417c86d5 And use the parent that's actually going to be valid. *sigh* + +Build 1.6.4-9.11.0.885: + CovertJaguar: + Fluid Rarity should have a default + + Oops. + Christian: + Updated FML: + MinecraftForge/FML@70cffe6982b27df0ea7d8d4d8851a0c0043bb2cb Herpaderp. Make addURL accessible. *sigh* + +Build 1.6.4-9.11.0.884: + Christian: + Updated FML: + MinecraftForge/FML@4a94c2c71bb4cc9644caeb06011a189989b22f87 Fix NPE when loading second single-player world + MinecraftForge/FML@0e80fcb8f716cfef5b016a73ca32ff0e2f3c3c05 Merge pull request #284 from smcv/uninit + MinecraftForge/FML@39620f1e41464f53482277dc3bcb0b9eed8ca25c Fix injection of tweaker into system + +Build 1.6.4-9.11.0.883: + Christian: + Updated FML: + MinecraftForge/FML@79c39f8b7c711377f7919abd1ee6a56a339d1062 Fix classpath for launchwrapper 1.7 + +Build 1.6.4-9.11.0.882: + traincrazyb: Correcting SoundManager Transformer + +Build 1.6.4-9.11.0.881: + Christian: Clean patch fuzz + +Build 1.6.4-9.11.0.880: + Christian: + Updated FML: + MinecraftForge/FML@f6190e8752013c0d6857090ffd42559cf83809ae Update workspaces for 1.6.4 + +Build 1.6.4-9.11.0.879: + Christian: + Updated FML: + MinecraftForge/FML@25981706ef12654b6c2baccc80fa2298bb5afb4a Update for MC 1.6.4 + MinecraftForge/FML@0950b9fc8441a2d3b022ed876f17ee5ac0c47b9c Fix up a deep crash in the early server init hanging the client + +Build 1.6.3-9.11.0.878: + LexManos: Remove duplicate access transformer + LexManos: Move have handler creation up, to prevent NPE. + +Build 1.6.3-9.11.0.877: + LexManos: + Updated FML: + MinecraftForge/FML@e7dd728f955aa4713fef45fea770b1f91246d712 Format the log messages through MessageFormat. Thanks CovertJaguar for the pointer. + MinecraftForge/FML@82d896a35e08be5712bdc15bdb93e5d4fc0ddd46 Make final transformers actually work on methods as well. + +Build 1.6.3-9.11.0.876: + LexManos: Move the Structure data save files to per-world data folders. Vanilla saves them to the global folder which will potentially cause conflicts if two worlds generate 'Villages'. Which in the modded world is highly likely. Refer back to the long standing vanilla issue where nether 'villages' would override the overworlds villages, it's the same situation. + +Build 1.6.3-9.11.0.875: + LexManos: Make MapGenStructureIO name registration functions public, Any mod that has anything extending StructureStart or StructureComponent must register there classes and create a default (no parameter) constructor. + +Build 1.6.3-9.11.0.874: + LexManos: Unfinalized Item.getIconIndex(ItemStack) + +Build 1.6.3-9.11.0.873: + LexManos: + Updated FML: + MinecraftForge/FML@da70cdd35a378d02db47d2aa31fb9aac87beaedc Update tweaker for new Launcher API + MinecraftForge/FML@352117fd78eec745da6c80b8d354947c4dbbbb48 Update for new installer and thank you. + MinecraftForge/FML@40a34af43105ebcb5a63ce2351ca119da5a8158e Merge branch 'master' into newtweak + MinecraftForge/FML@e77d2547ad447025729ae7f3cccaaf343c4c86f9 Update for pre-ninja 1.6.3 update + MinecraftForge/FML@34493b0d99e2cf2bdca080ff226f2dfeedb1cf51 Update for real 1.6.3 update + MinecraftForge/FML@95afc95b248ecc69bc6ffcc5a95912820d8f4066 Update mcp mod info + MinecraftForge/FML@ff75416a325717770a5cf457c859bfb0abcbe281 Update mc_versions data and commands patch and eclipse workspace + MinecraftForge/FML@8f2e67558127f16d92399ea97cbcb0df46d52e19 Update the src distro's eclipse workspace. + LexManos: Bump version for new MC version. + LexManos: Actually push the submodule update -.- + +Build 1.6.2-9.10.1.871: + Christian: + Updated FML: + MinecraftForge/FML@81328b6684c5127427153807b5e498c2efefb96b Add in support for using a mirror list and provide checksums for packed download of libs + +Build 1.6.2-9.10.1.870: + Christian: + Revert "Added a RenderType that allows Map-style rendering w/o inheriting from" + + This reverts commit eb4688bf5ea132cd8ddc802a7dad6d423ad50543. + + Conflicts: + patches/minecraft/net/minecraft/client/renderer/ItemRenderer.java.patch + +Build 1.6.2-9.10.1.869: + vilim.lendvaj: Prevent NPE in fluid lookup for block + Christian: Fix broken PR from vilml. TEST! + +Build 1.6.2-9.10.1.867: + CovertJaguar: + Allow Fluids to have Rarities + + Used for tool tips. + +Build 1.6.2-9.10.1.866: + Christian: Fix the divider + +Build 1.6.2-9.10.1.865: + Adubbz: + Sky colours now smoothly transition + + Made transitions even smoother + + Sky colours now smoothly transition + Christian: Move stuff around a bit- also tie range and enabled to options. + +Build 1.6.2-9.10.1.864: + ml: + Added a RenderType that allows Map-style rendering w/o inheriting from + ItemMap. + Christian: Tweak patch comment + +Build 1.6.2-9.10.1.863: + mitchpetrie29: Check if block is air instead of just ID zero when growing from stem block. + +Build 1.6.2-9.10.1.862: + Christian: Allows proper raytracing from actual player eye position rather than hardcoded eye heights. + +Build 1.6.2-9.10.1.861: + claire.alexandria: Added fov hook + claire.alexandria: fixed merge + claire.alexandria: Small formatting changes (opening braces on new line) + +Build 1.6.2-9.10.1.860: + Christian: + Updated FML: + MinecraftForge/FML@b5af446d7111730c7973c9f0d6b76e62b78b9131 Fix sidedness derp in LanguageRegistry. + +Build 1.6.2-9.10.1.859: + Christian: The partial tick should be available for all render player events. Weird it wasn't. + +Build 1.6.2-9.10.1.858: + Christian: Reverting HarvestEvent, for new implementation + Christian: Redo harvest event. This time with simpler logic, that should be less liable to weird "missing" stuff. + +Build 1.6.2-9.10.1.857: + LexManos: Fix bug where guis were not closed properly, resulting in signs not having there text set. + +Build 1.6.2-9.10.1.856: + Christian: Change trigger calculation so entities get some time to age before refiring the event. + +Build 1.6.2-9.10.1.855: + LexManos: Create helper apply_patches script and add paramter to change patch output folder. + +Build 1.6.2-9.10.1.854: + Christian: + Change from Cancelable to using a Result. This means you can force despawn mobs you + don't want around anymore. Also, deferred check to once every 20 ticks. May tune it + down further or make it a config if this event is a lag issue. + +Build 1.6.2-9.10.1.853: + Christian: + Add a cancellable despawn event- allows mods to decide to prevent the despawning + of certain otherwise normally despawnable mobs. + Christian: + Added fov hook + + Small formatting changes (opening braces on new line) + Christian: Create es_ES.lang + +Build 1.6.2-9.10.1.852: + Christian: Add some javadoc to the HarvestBlock event. + +Build 1.6.2-9.10.1.851: + Christian: Use the dropchance from the event. + Christian: Clean up some formatting. + +Build 1.6.2-9.10.1.850: + claire.alexandria: Added tessellation methods to obj model, for ISBRH-friendliness + claire.alexandria: Fixed both RenderAllExcept behaviours + claire.alexandria: Added more render methods to IModelCustom interface. + jk-5: + Added GuiOpenEvent + + You can use this for a clean way to override guis, without needing an + TickHandler to check if the gui you want to override is open and show + your own gui + + Proper close check + mhahn: + capacity was not respected + + Updated to properly calculate the amount of free space in the tank + before checking that against the amount of the resource. + robin: create french localization + claire.alexandria: Added display name hook + claire.alexandria: Memoization of display name result + claire.alexandria: Added mouse event + claire.alexandria: inserted hook into Minecraft.java + claire.alexandria: fixed logic error + ohai.iChun: + Fix player push out of blocks clientside being hardcoded and not based on entity size. + Added player eyeHeight field to allow changeable eye heights of players rather than being hardcoded per player class as well as add a getDefaultEyeHeight function. + Christian: Reduce patch size significantly + Christian: Fix patch for new MCP naming. + Christian: Add a bit of javadoc + Christian: MachineMuse, remember, there's TWO model formats supported! + Christian: Defer firing CreateDecorator until it's likely mods have had a chance to register their listener. Should close #759 + Christian: + Add a harvestblock event, to allow mods to intercept and change the drops for blocks. Don't abuse this, or we'll have to take safety measures. + Fires for both silktouch and non-silktouch harvesting, and provides the player. Note, you may need to + change your break overrides to pass on the player for best results. + Christian: Add in a block reverse lookup for fluids. Closes #749 + +Build 1.6.2-9.10.1.849: + Christian: + Update forge for MCP naming updates + + Updated FML: + MinecraftForge/FML@d0c6e92900590f578b80d9a6c00fa28fd333d3bf Update MCP data + Christian: Update version to 9.10.1 for mcp naming changes. + +Build 1.6.2-9.10.0.848: + Christian: Fix possible NPE in searching code. + +Build 1.6.2-9.10.0.847: + Christian: + Updated FML: + MinecraftForge/FML@2a9c485edc4cf3382154d5b3b9b600386f2ab8ae Remove @SideOnly from 70318 (getDistance) it makes no sense that it's not on the server. + +Build 1.6.2-9.10.0.846: + Christian: + Updated FML: + MinecraftForge/FML@a13598b17ea9637c054d867a76298d6c080c5e32 Use java 1.6 compatible method of closing the zip file. Stops stupid compile error. + +Build 1.6.2-9.10.0.845: + Christian: Small fix to container registry. emptyContainer is not null, it's "NULL_EMPTYCONTAINER" now and won't match any valid container. + +Build 1.6.2-9.10.0.844: + Christian: Tweak the release to add in assets to the distributable. *sigh* + +Build 1.6.2-9.10.0.843: + Christian: + Updated FML: + MinecraftForge/FML@1c9a853868f7df0daa5f67b99401dfab44ae18e6 Allow coremods to properly inject asset readers. + MinecraftForge/FML@40b54013b4c9b01686411cd47a7866eeb650ea2b Allow server side lang file injection, hopefully + Christian: Add some starting work for a forge tps command. Also update coremod for new FML behaviour + +Build 1.6.2-9.10.0.842: + Christian: + Updated FML: + MinecraftForge/FML@b993cf4a9825865b3a8a0c7b083c23d56dbd1d6f More exception handling for less derpiness. + +Build 1.6.2-9.10.0.841: + Christian: + In the time honoured tradition of trying to fix vanilla, we today attempt to patch the pathfinding AI so that it doesn't lag when + there's a lot of entities. Basically, if the zombie can't reach the villager, backoff subsequent pathfinding attempts. Hopefully + should really help with lag caused by zombie swarms. + +Build 1.6.2-9.10.0.840: + Christian: Allow multipass RenderItem rendering for terrain icons too. Should fix sengir's saplings. + +Build 1.6.2-9.10.0.839: + Christian: + Updated FML: + MinecraftForge/FML@913f6f6d36bd179db7c147db0485e99dee693933 Try and use the relaunch log, which should be classloaded.. + MinecraftForge/FML@ac065ff5f76b6c512b346366107efde66e9e1c88 Reset the IWorldGenerator seed for each mod, before calling. That should mean worldgen is consistent and not dependent on mod ordering, or mod sideeffects. + +Build 1.6.2-9.10.0.838: + LexManos: Cache world on all render passes in case some mod disables the first pass. + LexManos: Skipp toss event for null entity items. Closes #732 + +Build 1.6.2-9.10.0.837: + LexManos: Fix bug with custom Fluids. You can now drown in them! + +Build 1.6.2-9.10.0.836: + Christian: + Updated FML: + MinecraftForge/FML@9468e41bbf3ea425c50daa710cf3ada11c82b238 Fix up scala refs, for better results + +Build 1.6.2-9.10.0.835: + Nick: + Adds Temperature to Lava + + Missing lava temperature. Feel free to change it to any value. + 1300K is the typical max for Magma so wasn't sure what was desired. Regardless, better than the same temp as water at 295K :smile: + +Build 1.6.2-9.10.0.834: + Christian: + Updated FML: + MinecraftForge/FML@4a9d0f9bd522e543b76daaf9c49b6214443c595f Add in some log information + Christian: + Updated FML: + MinecraftForge/FML@f157e7a6ecdeac2758fc0eaf547d3e8a763fb15b And more coremod logging + Christian: + Updated FML: + MinecraftForge/FML@ffdd056a18eddb8f28b74435d40e69c956b9dd48 Check keys, not values *sigh* + +Build 1.6.2-9.10.0.833: + Christian: + Updated FML: + MinecraftForge/FML@03989166665956df03aa85472eb13dca2d74a38d And actually instantiate the collection *sigh* + +Build 1.6.2-9.10.0.832: + Christian: + Updated FML: + MinecraftForge/FML@dec9a3924d361bc016cb7f6b3e95764158cf5ae1 Add in "FMLCorePluginContainsMod" in the manifest. If this value is present, FML will attempt to parse your mod jar file as a normal mod file as well, instantiating mod containers there. + +Build 1.6.2-9.10.0.831: + Christian: + Updated FML: + MinecraftForge/FML@24701206808a43b9c7b10d7130c47b5d1e841bb6 Clean up a couple of resources. Also, don't parse jars just because they're in the mods dir + +Build 1.6.2-9.10.0.830: + Christian: + Updated FML: + MinecraftForge/FML@9a5e24e338c6172531efb086a4b584c26d4f1435 Fix stupid derp is stupid. Closes #275 and means sp614x can do his thing + MinecraftForge/FML@ba90b616070ce15793eb05e5afaed62a6f07c6e7 Make sure we only add args to the argument list if a tweaker hasn't already. Should fix LiteLoader compatibility issue. + +Build 1.6.2-9.10.0.829: + LexManos: Fix NPE in enchangint books. + +Build 1.6.2-9.10.0.828: + LexManos: Fix inverted case, search works now. + +Build 1.6.2-9.10.0.826: + ross.swartz: Add stone and cobblestone to Ore Dictionary + ross.swartz: Update OreDictionary.java + LexManos: Addition: Added isAllowedOnBooks hook to Enchantments Closes #589 + +Build 1.6.2-9.10.0.825: + LexManos: Deprecate Block.addCreativeItems, Kill in 1.6.3+ Closes #655 + +Build 1.6.2-9.10.0.824: + mehvids: Add onNeighborTileChange callback to block by generalizing func_96440_m to all blocks rather than just comparators. + +Build 1.6.2-9.10.0.822: + malc.geddes: Added a new function to allow control over whether an entity is dismounted when the entity it is riding goes under water + LexManos: Allow creative tabs to have a search box if they want to Closes #592 + +Build 1.6.2-9.10.0.821: + tommy.stanley96: Fixed Fluid Non-Solid Block Duplication + tommy.stanley96: Fixed Double Item Drop + tommy.stanley96: Fixed Classic Checking + +Build 1.6.2-9.10.0.820: + LexManos: Add optional feature to check entire bounding box for ladders. Closes #709 + +Build 1.6.2-9.10.0.819: + LexManos: Only refresh vanilla tile entities when IDs change. + +Build 1.6.2-9.10.0.818: + LexManos: + Updated FML: + MinecraftForge/FML@f275a24b43559cfdced243ff77e9848c9d458362 Add in some reverse lookup methods for game registry data + MinecraftForge/FML@cb05c8c4aa60a131de92f0a21c06697c8f8896a8 Add missing SideOnly in BaseMod + MinecraftForge/FML@1857064afa9ace796440c19f3275637a6e659375 Merge pull request #266 from grompe/patch-1 + MinecraftForge/FML@182aa9c0cbe61ac69b0d428ead1dc817dd2a2e71 Fixed install.sh not passing arguments to install.py + MinecraftForge/FML@f46a538b41157081c840f647f123513ac4c5a071 Merge pull request #268 from Bo98/sh-args-fix + MinecraftForge/FML@29ef3d5ab412dcabbd67695558880c45011ace82 Update installer. + +Build 1.6.2-9.10.0.817: + tommy.stanley96: + Fluid Render Fix + + Formatting + ohai.iChun: Add Pre and Post events for RenderLivingEvent + ohai.iChun: Add Pre and Post events firing for RendererLivingEntity + ohai.iChun: if statement added + ohai.iChun: Update RendererLivingEntity.java.patch + tommy.stanley96: + Fixed fluids eating each other + + Fluids check for other fluids density before flowing, if their density + is higher they can flow into the other fluid, if not they can't. + CovertJaguar: Add SneakClick bypass to client + cpw: Fix names for water/lava fluids. Closes #689 + cpw: + Add support for loading legacy liquid stacks as new fluid stacks. + Requires having been written with the "liquidname" code from forge 1.5.x + cpw: + Add a translation map for looking up legacy liquid names to convert + to new fluid names. + tommy.stanley96: Fluid Rendering Fixes + cpw: Fix formatting error in PR + cpw: + Tweak setBlock in update tick - it should only send serverside updates for + source blocks. Experimental attempt to fix worldgen issues for fluid blocks + cpw: + Updated FML: + MinecraftForge/FML@57befa89bbbf2bc2fcc4a97b78e07b3f9e23ef9d Fix keybindings being derped + MinecraftForge/FML@1d84e8063e9d0dc73928dba006e6001201285cad Temporarily add a version of 'reobfuscate.py' that will resolve complex reobfuscation graph issues with specialsource. Copy it over 'reobfuscate.py' in the mcp runtime dir. Hopefully will have an MCP/specialsource fix in the coming days. + ohai.iChun: Fix RenderLivingEvent.Pre/Post not being fired by most Renders. + tonkamatt98: + added temperature to fluids + + it could be useful for blocks that are affected by temperature + mitchel.pyl: Fix render colour on bottom of fluids + mitchel.pyl: Fix small derp + +Build 1.6.2-9.10.0.816: + purpleposeidon: + Add an InputStream constructor to WavefrontObject + + It is said that Resource Packs will return InputStreams. And I like putting my models into texture packs which, obviously, give InputStreams rather than URLs. + 7of9: Add cloud height to WorldType + +Build 1.6.2-9.10.0.815-miscchanges: + mitchel.pyl: Fix render colour on bottom of fluids + mitchel.pyl: Fix small derp + +Build 1.6.2-9.10.0.812-miscchanges: + tonkamatt98: + added temperature to fluids + + it could be useful for blocks that are affected by temperature + +Build 1.6.2-9.10.0.811-miscchanges: + ohai.iChun: Fix RenderLivingEvent.Pre/Post not being fired by most Renders. + +Build 1.6.2-9.10.0.810-miscchanges: + cpw: + Updated FML: + MinecraftForge/FML@57befa89bbbf2bc2fcc4a97b78e07b3f9e23ef9d Fix keybindings being derped + MinecraftForge/FML@1d84e8063e9d0dc73928dba006e6001201285cad Temporarily add a version of 'reobfuscate.py' that will resolve complex reobfuscation graph issues with specialsource. Copy it over 'reobfuscate.py' in the mcp runtime dir. Hopefully will have an MCP/specialsource fix in the coming days. + +Build 1.6.2-9.10.0.809-miscchanges: + cpw: Fix formatting error in PR + cpw: + Tweak setBlock in update tick - it should only send serverside updates for + source blocks. Experimental attempt to fix worldgen issues for fluid blocks + +Build 1.6.2-9.10.0.808-miscchanges: + tommy.stanley96: Fluid Rendering Fixes + +Build 1.6.2-9.10.0.807-miscchanges: + cpw: + Add a translation map for looking up legacy liquid names to convert + to new fluid names. + +Build 1.6.2-9.10.0.806-miscchanges: + cpw: + Add support for loading legacy liquid stacks as new fluid stacks. + Requires having been written with the "liquidname" code from forge 1.5.x + +Build 1.6.2-9.10.0.804: + copyboy: Fix getArmorTexture by passing it the subtype + +Build 1.6.2-9.10.0.802: + LexManos: + Re-added deprecated liquids system. To be removed next major MC versions after issues with Fluids are fixed. (reverse-merged from commit 9b5208fa308f22c24e295ce3be38dcafea2857ea) + This WILL be removed and should not be developed against aside for a temporary 1.6 release. + +Build 1.6.2-9.10.0.801: + LexManos: Remove SideOnly(Client) in IBlockAccess.isAirBlock + +Build 1.6.2-9.10.0.800: + LexManos: MinecraftForge/FML@10b16d32da4b7c32b15e69cf1c636505ebbe2540 Use json 2.9.1 nightly for OSX in release json like vanilla does. + +Build 1.6.2-9.10.0.799: + LexManos: General code cleanup of Fluid system. Made Fluid icons and associated functions non-sided. + +Build 1.6.2-9.10.0.798: + LexManos: MinecraftForge/FML@3f21a2c1b413e591f61f2906c3adbadd9c5b09e3 Stupid spaces and windows escaping -.- + +Build 1.6.2-9.10.0.797: + LexManos: MinecraftForge/FML@b2958c9066db8c95bb4260893fbfe00103fc4ba1 Add quotes for paths with spaces -.- + LexManos: Package 'version.json' with universal jar for maunchers to use. It's the json used by the vanilla Minecraft launcher for Forge. + +Build 1.6.2-9.10.0.796: + LexManos: MinecraftForge/FML@9520978b81d4cba5d8b0af0d5f155bd115023795 Use a temporary file for recompile's command line to combat command length to long issues. + +Build 1.6.2-9.10.0.795: + LexManos: Updated FML: MinecraftForge/FML@4981aa3421262c3c1c4705468fe202df8198b9f0 Fix potential NPE in villager skin registry. Closes #678 + +Build 1.6.2-9.10.0.794: + Nick: + Fixes Vanilla Fluid Still Icon Setters + + Fixes null icons from being set for both the still water/lava icons, and sets the correct Icon. + +Build 1.6.2-9.10.0.793: + LexManos: Updated FML: MinecraftForge/FML@c48b48ee15f38d3e794b6eb3499c536226ca5a79 Fix server launching. + +Build 1.6.2-9.10.0.792: + Christian: Fix for new location of mcp logo. + +Build 1.6.2-9.10.0.791: + Christian: + Updated FML: + MinecraftForge/FML@0378355c3720d587652b7792665a8b70bf104eb3 The server.classpath generates the runtime manifest, so it needs the non-debug asm jars. + MinecraftForge/FML@a3f48734ffbbb2eccffdafcd3cbe73824bd1afd6 Fix up jar sanity check code. FML validation of the jar works now and doesn't derp classloading. + MinecraftForge/FML@9947ba85036542a3231e25328d3300f2a5337370 Fix logo handling. no more NPE if the logo can't be found. Also, fix location of mcp logo now. + +Build 1.6.2-9.10.0.790: + Adubbz: + Made eating particles compatible with metadata + + Removed extra spaces + + Made eating particles compatible with metadata + Christian: + Updated FML: + MinecraftForge/FML@e44e8b3112bd56c716a00c19d0be2f15d9128b70 Force a global asset scan prior to mod construction : you should be able to reference assets anywhere in your mod now. + MinecraftForge/FML@20e93a412ee13498babef02d404f57bf5e0fd919 Fix up logos in the mod screen. Clean up some unnecessary casts and suppressions, use the -debug asm library at dev time, since it contains full symbols and code in compiled form. + LexManos: MinecraftForge/FML@b9f4b02cb0b041594656f05de70225df702a8ddd Kill mcp's truncate method, for more useful logs. + LexManos: + Updated FML: + MinecraftForge/FML@7348929819b0ae8ad35419ef5dbf66e66b442858 Kill release time scala libraries, to be re-evaluated after all movement is done and shit is fixed. May require manual instalation for mods that use scala. + MinecraftForge/FML@6de36d78f57f6f08ec586b67b684d0e5406cd436 Coremods now have a primitive dependency capability. Also, we search mods dir for special "TweakClass" manifests. These are using the vanilla tweak mechanism to inject into Minecraft. Helpful for other "platform" systems, when you don't want to have to deal with json changes! + MinecraftForge/FML@d4b30422b64a62a2f8a8c2cccd94cb0fd06154e0 Update build and eclipse workspaces for debug asm. + LexManos: MinecraftForge/FML@c625ef30093abb0755985c74d1f31e2c4cf6cfdd Update Forge signature for new private key + LexManos: Update changelog generator to point to new jenkins. + LexManos: Monkey patch to try and make print flush properly. + +Build 1.6.2-9.10.0.789: + LexManos: Re-add reverted patch AGAIN cpw check your commits -.- + +Build 1.6.2-9.10.0.787: + Christian: + Updated FML: + MinecraftForge/FML@bab4d87ce76baa40200939cc46780b1d3b2ff466 Update FML for new stealth update for 1.6.2 + +Build 1.6.2-9.10.0.786: + Christian: Remove forge ISidedInventory, deprecated since 1.5. + +Build 1.6.2-9.10.0.785: + Christian: + Allow optional rider interaction for entities, thanks for the suggestion Vswe. + + Updated FML: + MinecraftForge/FML@7af5c21d74679d1a53550f9719bba22b2f28dd13 @InstanceFactory was set to look for Fields instead of methods + MinecraftForge/FML@bc9d1fe657c7a0953adc7d4c5ed81c575bdfb0f1 Merge pull request #254 from CaptainShadows/patch-1 + +Build 1.6.2-9.10.0.784: + LexManos: MinecraftForge/FML@c913258ca38e662264bdf4aafbfbef86881c9290 Disable signature check of client for now, it's broken. + Christian: + Updated FML: + MinecraftForge/FML@97269a5e3dc0a0e2e1a79183f9f5f2ee120e90bd Decode the file URL. Hopefully will make things work more.. + MinecraftForge/FML@d4d522c5978ecd7a9195977b3327b441901bb5b4 And don't forget to remove the test code + +Build 1.6.2-9.10.0.781: + LexManos: + Updated FML: + MinecraftForge/FML@dfa3a2665d6782b87713cea26dda558ac990a72a Add MC Version to installed version name. + MinecraftForge/FML@e91431fb707ce3e7e4296ccb8f3b2e5208b4dfac Don't validate signatures on servers, they are not signed. + MinecraftForge/FML@c7ab872c85dd057a4e44e12e34089dfd1a1184b6 Temporarily disable GuiModList's Mod logos. + +Build 1.6.2-9.10.0.780: + LexManos: + Updated FML: + MinecraftForge/FML@c997f2adbc4c11cd8c2abe5f82ccd00b0e954b68 FML now verifies that the minecraft jar is correct and intact. This is intended to discourage those who think that modifying the minecraft jar is still acceptable. + MinecraftForge/FML@0db4624b27a5ecf59ed506ccfc26459ca26ee408 Don't initialize the server. + MinecraftForge/FML@4fa375683fdb7edff67c951fb371ab4a23435308 Fix NPE in new debug line when patch targets don't exist. + +Build 1.6.2-9.10.0.779: + LexManos: Fix accedential reverted patch. + LexManos: Proper return for getRegisteredFluidContainerData thanks Soaryn. Ref issue #634 + +Build 1.6.2-9.10.0.778: + Christian: Make resourcelocation the class available on the server. + +Build 1.6.2-9.10.0.777: + Christian: + Drop two domain related fixes that have been applied in vanilla. + + Updated FML: + MinecraftForge/FML@c47d08c89dfcacb96e36c427593174e08dcb4224 Tweak debug data on patched classes + MinecraftForge/FML@dbf5fe38cee04288e92d57f8782114b452245bce We now generate an adler32 checksum for each patched file and verify at load time that they match. Mismatch won't crash, but will emit a big warning.. + MinecraftForge/FML@e88a0cd13f63904f7317e1a73880611f58820389 Update for stealth update. Thanks mojang! + MinecraftForge/FML@2336002f20e9412a7663781b23c51de0eff6a692 The game is going to exit in face of patch mismatch, unless you force it to run with fml.ignorePatchDiscrepancies in the system properties. + +Build 1.6.2-9.10.0.776: + LexManos: + Updated FML: + MinecraftForge/FML@1d0384f8f664d7002019b865675a5fddf2963b3d Update for 1.6.2 and MCP 8.04 + MinecraftForge/FML@111b0216fdc55f56a8361a584141bca7c9c3f070 Add the jsons for 1.6.2 + MinecraftForge/FML@6f96d89e2bf9313b26eeb4c334a208bf3e1c9ad4 Update eclipse workspaces for 1.6.2 + LexManos: Remove deprecated Liquids API, Use new Fluids system as replacement. + LexManos: Bump version to 9.10 for new MC version and removal of Fluids. + +Build 1.6.1-8.9.0.775: + Christian: + Updated FML: + MinecraftForge/FML@c97ac284a5e7dbdbccbad2f7ccc95252c4aef239 Update ModLoaderFuelHelper.java + MinecraftForge/FML@3a200e901e34ade679e4485307f57bee725bbe94 Fix coremod injection into main system. Should stop double-dipping coremods. + MinecraftForge/FML@2676c8999cbede05b5475ba68bfc25467a67d4fc Update mcp data. fixes #248 + MinecraftForge/FML@5990e29af7b70e343dfd9cf38bb3e033e71a4489 Merge pull request #247 from jk-5/patch-1 + MinecraftForge/FML@adc89722770b7319884619cadc6f10cc9050df24 Add cascadedTweaks. This will allow simple coexistence for any other mod framework using the tweaker system as well. Hi Voxel and LiteLoader! + +Build 1.6.1-8.9.0.774: + xcompwiz: + Makes player-specific spawnpoints dimension aware + + Makes ServerConfigurationManager correctly get player-specific spawn + point for the target dimension + Changes EntityPlayer to store and save a (bed) spawn point for every + dimension, as well as transfer them to respawn "clones" + +Build 1.6.1-8.9.0.773: + LexManos: Re-gather list of Icons when atlas textures are stitched, allows for addition/removal of blocks/items after the atlas's inital constrction. + +Build 1.6.1-8.9.0.772: + LexManos: Fix enchantment effect on single pass items. Closes #644 + +Build 1.6.1-8.9.0.771: + kinglemming: + Forge Fluid System! + + Signed-off-by: King Lemming + LexManos: Mark old liquid system as deperated to be removed next Minecraft release. + +Build 1.6.1-8.9.0.770-newliquid: + LexManos: Mark old liquid system as deperated to be removed next Minecraft release. + +Build 1.6.1-8.9.0.769-newliquid: + richard: Techne model loader (incomplete for debugging) + richard: Complete it, got the bug figured out + Christian: + Updated FML: + MinecraftForge/FML@24c405665105a789a0708a7e30c8bcb96899da6b Add in an optional modid identifier for @SidedProxy. It's main use is when both scala and java @Mods reside in the same package, and you want the @SidedProxy behaviour for a specific @Mod language type. In general it should not be needed otherwise. + MinecraftForge/FML@cd0466395a8f1af3ec44f124bf4088df2d318603 Fix sysout with trailing messages after a newline + LexManos: Disable ImageIO's File based cache, should speed up texturepack loading/stitching. + jadran.kotnik: Added rotation support for all vanilla blocks that can be rotated. + LexManos: + Add NPE protection to ItemStack delegates. Closes #601 + Also cleaned up the names of said delegates, we do not have to follow MCP's crowdsourced names as they are very bad. + Redirected damage through setItemDamage to allow items to have finder control of breaking. + LexManos: Fix Air block check in BlockPortal. + LexManos: Fix hoes being able to till dirt under other blocks, and made it look for air type blocks. + LexManos: Add NPE protection to refernce to MinecraftServer.worldServer + LexManos: Fix AIOOB exception in crash reporting if exception does not have a stack. Possible, but odd. + LexManos: Fixed changelog generation. + LexManos: Forgot most important side, release script. + Christian: Make glass panes and iron fences connect to block sides based on solidity. This does change IBlockAccess, so anything with a custom IBlockAccess may need to implement the new method. + Christian: + Fix server patch FML update + + Updated FML: + MinecraftForge/FML@22738de028a9ba51d43d73857dfb8969985566f0 Attempt to properly fix deadlock if the internal server derps. It should never hang now. Damn you fast computer.. + MinecraftForge/FML@05a854cd2af53ca822ee8b249b0b3bbe44f94675 Small tweaks to the mcp data. Nothing major.. + mitchel.pyl: Fix tripwire patches for solid sides + LexManos: Added EntityLiving to Block.isLadder arguments, deperacating older version. New parameter has the possibility of being null, so modders must take care. Closes #608 + LexManos: Add air checks to BlockSand falling and Piston pushing. Please report any other issues with custom 'Air' blocks in issue #602 + LexManos: Bump Forge revision and mark recomended. + LexManos: Fic Chest content gneeration delegate call. Cloases #609 + LexManos: Add air check to Flint and Steel Ref: #602 + LexManos: Update workspace for new library structure. + LexManos: Update FML to 16launch branch + LexManos: Initial patch update to 1.6, Does not compile, need to update references to the old TexturePack system. + LexManos: Small fixup, need to Update GuiIngameForge for new HUD changes. + LexManos: + Updated FML: + MinecraftForge/FML@6a318ddb784ca8b2bef0f6718089f7beb4d404e0 Fix typo in new packages. + MinecraftForge/FML@3711da9c456d20865a965734cc5aeaf7f5cb5e5d Another typo + MinecraftForge/FML@e35e4b16ff3d6dea547c41f02f2ca31ebe1f74aa More fixups + MinecraftForge/FML@18371bd8c9bd107f774289da35519f593ccc8ee7 Some fixes for updated mcp code + MinecraftForge/FML@ef646d3146e1f285d2cb8e79a74373beffa84774 Merge branch '16launch' + MinecraftForge/FML@7406b38d8ad1bc5c2c641c74f1614b946f246588 1.6.1 + MinecraftForge/FML@12c928c538c1c04d3a21255c747d15468328ace9 Tweak commands patch + MinecraftForge/FML@3f15cd54c2d776ea161aaedbecad9e188d66578f Functional client @ 1.6.1 + MinecraftForge/FML@71a92de5d95fccc4fe17cc39d0836891c6622f4d Client launch for eclipse + LexManos: + Updated FML: + MinecraftForge/FML@8960f6869fbe30d358a40997c47999025c3eae68 Add windows lzma executable http://tukaani.org/xz/ He states that most things are under public domai + n, But I couldn't find an exact reference to this executable. I'm going to assume it under public domain and distribuiting it here is fine. If not someone pleas + e direct me to the apropriate license and I will act accordingly. + MinecraftForge/FML@70cfe24e67adf6872ef1501599e2115e420c2539 Fix wrong project name in distro eclipse launch. + MinecraftForge/FML@7a004087f79b94bc92f29d50eb71288b6c1c968c Add deobf data to src dist. Dont create deobf jar as we ship the lzma Added *.lzma to .gitignore + LexManos: + Updated FML: + MinecraftForge/FML@110cf372eb5aa85df20b248976f1acdefa85e102 Add deobf data to merge-common, workspace is now actually runnable! + LexManos: Support dirty submodules in changelog script. + LexManos: 1.6.1 Update + LexManos: Add new launch configs to dev workspace. + LexManos: Update GuiIngameForge to reflect Mojang changes in 1.6.1 + LexManos: + Updated FML: + MinecraftForge/FML@c418da353f6a8420b095fa737e8b0eae270d31ae Cleanup coremod code, server side working now. + LexManos: Update release script to generate binary patches and include deobf data. + LexManos: Deprecation sweep and update version to 8.9 to reflect 1.6.1 update. + LexManos: MinecraftForge/FML@7fecf2ad6bdd918149a3c43453f6a78bd11e5404 Update mcp URL. + LexManos: Try absolute path, to not confuse jenkins. + LexManos: + Updated FML: + MinecraftForge/FML@1229c4c4ea888f4f69272eed94ef5a53ce79ccda Fix src distrabution, and got rid of pesky common folder in eclipse workspace. src is now installable. + MinecraftForge/FML@902772ed0cb6c22c4cd7ad9b0ec7a02961b5e016 Revert common folder fix, Common folder does nothing, feel free to delete it after first load. + LexManos: Update src distro installer script. Source distro works now! + LexManos: Update ToolMaterial enum helper. + LexManos: Release will now build a installer jar and use the standard 'target' output folder. + LexManos: + Updated FML: + MinecraftForge/FML@29d6c875d0675ffa14428c511bd6ebe9232a486c Add FML Installer logo crated by @ZaverSLO https://twitter.com/ZaverSLO/status/349947190300508162 + MinecraftForge/FML@3d17434510e890574b68c8a181b80c830b5d043a Build installer package for the new client launcher. + MinecraftForge/FML@bf38d947569911dab03319a8b0f1964f36b195b2 Update json samples + MinecraftForge/FML@7037184a4e724300001dfc1f8df2e76a0ec30368 Fix up release JSON + MinecraftForge/FML@dc7d02ebf6c9fc5965344a9aeca79f230a40afb4 Fix json syntax error. + LexManos: + Fix installer unintended replace. + + Updated FML: + MinecraftForge/FML@9b6525e80504ff72a1798cf5797bf148295db776 Point scala downloads to our servers, Launcher doesn't like standard maven repos. + LexManos: + Updated FML: + MinecraftForge/FML@91ecf711092e1610dd10e77cdd517c3324e62d8d Fix -rel json + MinecraftForge/FML@efc369ee83a7b62f605c13e16efad66b63b4bd8c Fix EventHandler annotation. + MinecraftForge/FML@fbd57b32641b540d609314d91fd64350d50b9013 Mods are now loaded as resource packs. Vanilla will scan for valid prefixes based on subdirs of 'ass + ets' which can then be referenced as ResourceLocations with the ":path" notation. + LexManos: + Updated FML: + MinecraftForge/FML@5a97d183dfb13b0f831172a1afef7407347ea7bc Remember to update your patches!!!! + MinecraftForge/FML@f1b533ad87ea08d6e62259c59779bcec1636e2fe Keep these on our servers until the launcher is actually fixed -.- + LexManos: Fix bound texture in Controls screen, Closes #631 and #629 + LexManos: Make Block.setIconName public + LexManos: Update filler block to prevent useless console warning. + LexManos: Fix resource domain when loading icon. Textures should be located in /assets/{domain}/textures/{block|item}/{name}.png Same strcutre as before except 'assets' instead of 'mods'. + LexManos: Update ChestGenHooks for new Dungeon chest strcture. + Christian: + Start: f1b533ad87ea08d6e62259c59779bcec1636e2fe + End: f21cd286ca8e974b75536224a38cc0dacaca8454 + Updated FML: + MinecraftForge/FML@f21cd286ca8e974b75536224a38cc0dacaca8454 Resource packs, part two. FML mods are now resource packs. Vanilla will scan anything under 'assets' and turn it into a resource prefix. Use resourcelocations to look stuff up. + LexManos: Move resource location resolution down to TextureAtlasSprite and allow for sprites that are not stitched. + LexManos: Attempt to gather lastBuild information to fix ChangeLog's off-by-one issue. + LexManos: + Updated FML: + MinecraftForge/FML@6f0eedc9a64e4e246c40335e91b4868ad7f5a9e2 Fixed ClassCastException when loading ModLoader mods + MinecraftForge/FML@8844554da6d5d15756d7b0a9da2f5924006b3190 Merge pull request #243 from jrtc27/modclassloader + MinecraftForge/FML@7aa7221756d62ea1fbc750d7cf7acfdb28d75f2e Fix transformer search + MinecraftForge/FML@5f7df5e742cbc21565cee0d25709b5cb5462127c Revert "Keep these on our servers until the launcher is actually fixed -.-" + MinecraftForge/FML@ad79b9ed86eaf8c2702d79505d78a931c1774560 Fix up some deprecation warnings, and clean up coremod code that's going away. + MinecraftForge/FML@ba3707af22376f8f18103f63db56e4614a9c37db More javadoc cleanup + LexManos: Update dev worksapce: Proper natives location and new server launch profile. + LexManos: TEMPORARY fix for MCP mapping issue. + LexManos: Include MANIFEST file from FML's universal.jar, makes the jar runnable now! + LexManos: + Updated FML: + MinecraftForge/FML@155e8468180c93f1886a64028628764b1b22dd58 Add in support for mods/ as a mod location. Also drop coremods as a location. They go in mods too now. + MinecraftForge/FML@3f4bf61ae6757605b27078c7321de9f640876836 Update key + MinecraftForge/FML@4545beb49d5348d8632e42965627b9837115525b Add deobf-data to setup env. + MinecraftForge/FML@e24f94951741709329208f738000b72933302a24 Fix eclipse workspaces and launch configurations. + MinecraftForge/FML@532bee7ce1c4392ee11f0389d98f0c2be6240aa0 Update to new MCP bugfix version, Fixes: Missing Armor/Item rendering, and Boss health mapping issues. + LexManos: + Updated FML: + MinecraftForge/FML@7ce84491d1d4eada442944e02fc0e50c51f8045c Fix missing argument and startclient/startserver support. + LexManos: Fix domain issue with SoundPool entries. + LexManos: Add hook for EntityWither trying to destroy a block. + LexManos: Fix lether item rendering colors. + LexManos: Render pass sensitive version of Item.hasEffect, Closes #517 + LexManos: Fix compile errors temporarily, dont use till updated to new system. + LexManos: Add missing air checks to WorldGenTrees and ChunkCache Closes #593 + LexManos: Updated FML: MinecraftForge/FML@54e06e841d1c8df24fc30e1ec3a51def67f58858 Move Resource refreshing until affter postInit. + +Build 1.6.1-8.9.0.768: + LexManos: Add missing air checks to WorldGenTrees and ChunkCache Closes #593 + LexManos: Updated FML: MinecraftForge/FML@54e06e841d1c8df24fc30e1ec3a51def67f58858 Move Resource refreshing until affter postInit. + +Build 1.6.1-8.9.0.767: + richard: Techne model loader (incomplete for debugging) + richard: Complete it, got the bug figured out + LexManos: Fix compile errors temporarily, dont use till updated to new system. + +Build 1.6.1-8.9.0.766: + LexManos: Add hook for EntityWither trying to destroy a block. + LexManos: Fix lether item rendering colors. + LexManos: Render pass sensitive version of Item.hasEffect, Closes #517 + +Build 1.6.1-8.9.0.765: + jadran.kotnik: Added rotation support for all vanilla blocks that can be rotated. + +Build 1.6.1-8.9.0.764: + LexManos: + Updated FML: + MinecraftForge/FML@7ce84491d1d4eada442944e02fc0e50c51f8045c Fix missing argument and startclient/startserver support. + LexManos: Fix domain issue with SoundPool entries. + +Build 1.6.1-8.9.0.763: + LexManos: + Updated FML: + MinecraftForge/FML@155e8468180c93f1886a64028628764b1b22dd58 Add in support for mods/ as a mod location. Also drop coremods as a location. They go in mods too now. + MinecraftForge/FML@3f4bf61ae6757605b27078c7321de9f640876836 Update key + MinecraftForge/FML@4545beb49d5348d8632e42965627b9837115525b Add deobf-data to setup env. + MinecraftForge/FML@e24f94951741709329208f738000b72933302a24 Fix eclipse workspaces and launch configurations. + MinecraftForge/FML@532bee7ce1c4392ee11f0389d98f0c2be6240aa0 Update to new MCP bugfix version, Fixes: Missing Armor/Item rendering, and Boss health mapping issues. + +Build 1.6.1-8.9.0.762: + LexManos: Update dev worksapce: Proper natives location and new server launch profile. + LexManos: TEMPORARY fix for MCP mapping issue. + LexManos: Include MANIFEST file from FML's universal.jar, makes the jar runnable now! + +Build 1.6.1-8.9.0.761: + LexManos: + Updated FML: + MinecraftForge/FML@6f0eedc9a64e4e246c40335e91b4868ad7f5a9e2 Fixed ClassCastException when loading ModLoader mods + MinecraftForge/FML@8844554da6d5d15756d7b0a9da2f5924006b3190 Merge pull request #243 from jrtc27/modclassloader + MinecraftForge/FML@7aa7221756d62ea1fbc750d7cf7acfdb28d75f2e Fix transformer search + MinecraftForge/FML@5f7df5e742cbc21565cee0d25709b5cb5462127c Revert "Keep these on our servers until the launcher is actually fixed -.-" + MinecraftForge/FML@ad79b9ed86eaf8c2702d79505d78a931c1774560 Fix up some deprecation warnings, and clean up coremod code that's going away. + MinecraftForge/FML@ba3707af22376f8f18103f63db56e4614a9c37db More javadoc cleanup + +Build 1.6.1-8.9.0.760: + LexManos: Attempt to gather lastBuild information to fix ChangeLog's off-by-one issue. + +Build 1.6.1-8.9.0.759: + LexManos: Move resource location resolution down to TextureAtlasSprite and allow for sprites that are not stitched. + +Build 1.6.1-8.9.0.758: + Christian: + Start: f1b533ad87ea08d6e62259c59779bcec1636e2fe + End: f21cd286ca8e974b75536224a38cc0dacaca8454 + Updated FML: + MinecraftForge/FML@f21cd286ca8e974b75536224a38cc0dacaca8454 Resource packs, part two. FML mods are now resource packs. Vanilla will scan anything under 'assets' and turn it into a resource prefix. Use resourcelocations to look stuff up. + +Build 1.6.1-8.9.0.757: + LexManos: Update ChestGenHooks for new Dungeon chest strcture. + +Build 1.6.1-8.9.0.756: + LexManos: Make Block.setIconName public + LexManos: Update filler block to prevent useless console warning. + LexManos: Fix resource domain when loading icon. Textures should be located in /assets/{domain}/textures/{block|item}/{name}.png Same strcutre as before except 'assets' instead of 'mods'. + +Build 1.6.1-8.9.0.755: + LexManos: Update ToolMaterial enum helper. + LexManos: Release will now build a installer jar and use the standard 'target' output folder. + LexManos: + Updated FML: + MinecraftForge/FML@29d6c875d0675ffa14428c511bd6ebe9232a486c Add FML Installer logo crated by @ZaverSLO https://twitter.com/ZaverSLO/status/349947190300508162 + MinecraftForge/FML@3d17434510e890574b68c8a181b80c830b5d043a Build installer package for the new client launcher. + MinecraftForge/FML@bf38d947569911dab03319a8b0f1964f36b195b2 Update json samples + MinecraftForge/FML@7037184a4e724300001dfc1f8df2e76a0ec30368 Fix up release JSON + MinecraftForge/FML@dc7d02ebf6c9fc5965344a9aeca79f230a40afb4 Fix json syntax error. + LexManos: + Fix installer unintended replace. + + Updated FML: + MinecraftForge/FML@9b6525e80504ff72a1798cf5797bf148295db776 Point scala downloads to our servers, Launcher doesn't like standard maven repos. + LexManos: + Updated FML: + MinecraftForge/FML@91ecf711092e1610dd10e77cdd517c3324e62d8d Fix -rel json + MinecraftForge/FML@efc369ee83a7b62f605c13e16efad66b63b4bd8c Fix EventHandler annotation. + MinecraftForge/FML@fbd57b32641b540d609314d91fd64350d50b9013 Mods are now loaded as resource packs. Vanilla will scan for valid prefixes based on subdirs of 'ass + ets' which can then be referenced as ResourceLocations with the ":path" notation. + LexManos: + Updated FML: + MinecraftForge/FML@5a97d183dfb13b0f831172a1afef7407347ea7bc Remember to update your patches!!!! + MinecraftForge/FML@f1b533ad87ea08d6e62259c59779bcec1636e2fe Keep these on our servers until the launcher is actually fixed -.- + LexManos: Fix bound texture in Controls screen, Closes #631 and #629 + +Build 1.6.1-8.9.0.751: + LexManos: + Updated FML: + MinecraftForge/FML@1229c4c4ea888f4f69272eed94ef5a53ce79ccda Fix src distrabution, and got rid of pesky common folder in eclipse workspace. src is now installable. + MinecraftForge/FML@902772ed0cb6c22c4cd7ad9b0ec7a02961b5e016 Revert common folder fix, Common folder does nothing, feel free to delete it after first load. + LexManos: Update src distro installer script. Source distro works now! + +Build 1.6.1-8.9.0.750-1.6: + LexManos: + Updated FML: + MinecraftForge/FML@1229c4c4ea888f4f69272eed94ef5a53ce79ccda Fix src distrabution, and got rid of pesky common folder in eclipse workspace. src is now installable. + MinecraftForge/FML@902772ed0cb6c22c4cd7ad9b0ec7a02961b5e016 Revert common folder fix, Common folder does nothing, feel free to delete it after first load. + LexManos: Update src distro installer script. Source distro works now! + +Build 1.6.1-8.9.0.749: + LexManos: Update workspace for new library structure. + LexManos: Update FML to 16launch branch + LexManos: Initial patch update to 1.6, Does not compile, need to update references to the old TexturePack system. + LexManos: Small fixup, need to Update GuiIngameForge for new HUD changes. + LexManos: + Updated FML: + MinecraftForge/FML@6a318ddb784ca8b2bef0f6718089f7beb4d404e0 Fix typo in new packages. + MinecraftForge/FML@3711da9c456d20865a965734cc5aeaf7f5cb5e5d Another typo + MinecraftForge/FML@e35e4b16ff3d6dea547c41f02f2ca31ebe1f74aa More fixups + MinecraftForge/FML@18371bd8c9bd107f774289da35519f593ccc8ee7 Some fixes for updated mcp code + MinecraftForge/FML@ef646d3146e1f285d2cb8e79a74373beffa84774 Merge branch '16launch' + MinecraftForge/FML@7406b38d8ad1bc5c2c641c74f1614b946f246588 1.6.1 + MinecraftForge/FML@12c928c538c1c04d3a21255c747d15468328ace9 Tweak commands patch + MinecraftForge/FML@3f15cd54c2d776ea161aaedbecad9e188d66578f Functional client @ 1.6.1 + MinecraftForge/FML@71a92de5d95fccc4fe17cc39d0836891c6622f4d Client launch for eclipse + LexManos: + Updated FML: + MinecraftForge/FML@8960f6869fbe30d358a40997c47999025c3eae68 Add windows lzma executable http://tukaani.org/xz/ He states that most things are under public domai + n, But I couldn't find an exact reference to this executable. I'm going to assume it under public domain and distribuiting it here is fine. If not someone pleas + e direct me to the apropriate license and I will act accordingly. + MinecraftForge/FML@70cfe24e67adf6872ef1501599e2115e420c2539 Fix wrong project name in distro eclipse launch. + MinecraftForge/FML@7a004087f79b94bc92f29d50eb71288b6c1c968c Add deobf data to src dist. Dont create deobf jar as we ship the lzma Added *.lzma to .gitignore + LexManos: + Updated FML: + MinecraftForge/FML@110cf372eb5aa85df20b248976f1acdefa85e102 Add deobf data to merge-common, workspace is now actually runnable! + LexManos: Support dirty submodules in changelog script. + LexManos: 1.6.1 Update + LexManos: Add new launch configs to dev workspace. + LexManos: Update GuiIngameForge to reflect Mojang changes in 1.6.1 + LexManos: + Updated FML: + MinecraftForge/FML@c418da353f6a8420b095fa737e8b0eae270d31ae Cleanup coremod code, server side working now. + LexManos: Update release script to generate binary patches and include deobf data. + LexManos: Deprecation sweep and update version to 8.9 to reflect 1.6.1 update. + LexManos: MinecraftForge/FML@7fecf2ad6bdd918149a3c43453f6a78bd11e5404 Update mcp URL. + LexManos: Try absolute path, to not confuse jenkins. + +Build 1.6.1-8.9.0.748-1.6: + LexManos: Try absolute path, to not confuse jenkins. + +Build 1.5.2-7.8.1.738: + LexManos: Fic Chest content gneeration delegate call. Cloases #609 + LexManos: Add air check to Flint and Steel Ref: #602 + +Build 1.5.2-7.8.1.737: + LexManos: Bump Forge revision and mark recomended. + +Build 1.5.2-7.8.0.736: + LexManos: Added EntityLiving to Block.isLadder arguments, deperacating older version. New parameter has the possibility of being null, so modders must take care. Closes #608 + LexManos: Add air checks to BlockSand falling and Piston pushing. Please report any other issues with custom 'Air' blocks in issue #602 + +Build 1.5.2-7.8.0.735: + mitchel.pyl: Fix tripwire patches for solid sides + +Build 1.5.2-7.8.0.734: + Christian: + Fix server patch FML update + + Updated FML: + MinecraftForge/FML@22738de028a9ba51d43d73857dfb8969985566f0 Attempt to properly fix deadlock if the internal server derps. It should never hang now. Damn you fast computer.. + MinecraftForge/FML@05a854cd2af53ca822ee8b249b0b3bbe44f94675 Small tweaks to the mcp data. Nothing major.. + +Build 1.5.2-7.8.0.733: + Christian: Make glass panes and iron fences connect to block sides based on solidity. This does change IBlockAccess, so anything with a custom IBlockAccess may need to implement the new method. + +Build 1.5.2-7.8.0.732: + LexManos: Forgot most important side, release script. + +Build 1.5.2-7.8.0.731: + LexManos: Fixed changelog generation. + +Build 1.5.2-7.8.0.730: + LexManos: Fix AIOOB exception in crash reporting if exception does not have a stack. Possible, but odd. + +Build 1.5.2-7.8.0.729: + LexManos: Fix hoes being able to till dirt under other blocks, and made it look for air type blocks. + LexManos: Add NPE protection to refernce to MinecraftServer.worldServer + +Build 1.5.2-7.8.0.728: + LexManos: Fix Air block check in BlockPortal. + +Build 1.5.2-7.8.0.727: + LexManos: + Add NPE protection to ItemStack delegates. Closes #601 + Also cleaned up the names of said delegates, we do not have to follow MCP's crowdsourced names as they are very bad. + Redirected damage through setItemDamage to allow items to have finder control of breaking. + +Build 1.5.2-7.8.0.726: + LexManos: Disable ImageIO's File based cache, should speed up texturepack loading/stitching. + +Build 1.5.2-7.8.0.725: + Christian: + Updated FML: + MinecraftForge/FML@24c405665105a789a0708a7e30c8bcb96899da6b Add in an optional modid identifier for @SidedProxy. It's main use is when both scala and java @Mods reside in the same package, and you want the @SidedProxy behaviour for a specific @Mod language type. In general it should not be needed otherwise. + MinecraftForge/FML@cd0466395a8f1af3ec44f124bf4088df2d318603 Fix sysout with trailing messages after a newline + +Build 1.5.2-7.8.0.724-newliquid: + jeffreykog: RenderGameOverlayEvent.Post(ALL) is now called in GuiIngameForge + LexManos: Fix arbitrary GUIContainer text coloring by forcing lighting to be disabled. Closes #594 + Christian: Patch village distance checking to use floats instead of ints, to avoid int wrapping + Christian: Fix isAir check to see if a portal can light. Should fix w/Railcraft and others + LexManos: Make changelog generation non-fatal untill we get jenkins issue figured out. + LexManos: Add cache for ASM Event Handler bridge classes, should not need to redefine a class to invoke the same method on different instances. + LexManos: Ignore registration of a object that is already registered. Preventing duplicate callback invocations. Thanks King_Lemming for pointing this out. + Christian: + Updated FML: + MinecraftForge/FML@6f3da9736531153629fb4213e3b2cae776bfb50a Don't throw an exception if the scala adapter find a java proxy. I may add some distinguishers to @SidedProxy so you know which mod it's for. + MinecraftForge/FML@59fe905695421a5be9370b0009ef794abaaf75bb Don't continue trying to send events to mods that depend on errored mods. + +Build 1.5.2-7.8.0.723: + Christian: + Updated FML: + MinecraftForge/FML@6f3da9736531153629fb4213e3b2cae776bfb50a Don't throw an exception if the scala adapter find a java proxy. I may add some distinguishers to @SidedProxy so you know which mod it's for. + MinecraftForge/FML@59fe905695421a5be9370b0009ef794abaaf75bb Don't continue trying to send events to mods that depend on errored mods. + +Build 1.5.2-7.8.0.722: + jeffreykog: RenderGameOverlayEvent.Post(ALL) is now called in GuiIngameForge + +Build 1.5.2-7.8.0.721: + LexManos: Ignore registration of a object that is already registered. Preventing duplicate callback invocations. Thanks King_Lemming for pointing this out. + +Build 1.5.2-7.8.0.720: + LexManos: Add cache for ASM Event Handler bridge classes, should not need to redefine a class to invoke the same method on different instances. + +Build 1.5.2-7.8.0.719: + Christian: Fix isAir check to see if a portal can light. Should fix w/Railcraft and others + LexManos: Make changelog generation non-fatal untill we get jenkins issue figured out. + +Build 1.5.2-7.8.0.716: + Christian: Patch village distance checking to use floats instead of ints, to avoid int wrapping + +Build 1.5.2-7.8.0.715: + LexManos: Fix arbitrary GUIContainer text coloring by forcing lighting to be disabled. Closes #594 + +Build 1.5.2-7.8.0.713: + Christian: + Updated FML: + MinecraftForge/FML@843a13c1ab1e3901160082fa63c557243fb64675 Try and clean up cycle detection output a bit + MinecraftForge/FML@82e9de8641c6a559eec711ea6d1e940d99cbc98f More tweaks to the mod sorting code + MinecraftForge/FML@ac97370f94d10beee5f021795cddda827c4411d4 Add in a pretty sorting error screen + MinecraftForge/FML@f1d68ed4c82cd28e50ec6a0befc55ff0165bfe08 Throw the sorting exception + MinecraftForge/FML@edc1fb24e2cad9badd2dd18ccccd590d77156e18 Send the "suspect list", and print the suspect versions + +Build 1.5.2-7.8.0.711: + bloodshot: + Add support for servers to register dimensions on client. + + In order to support multi-worlds such as MultiVerse, the server needs the + ability to register dimensions on client or many forge mods such as IC2 + will not function correctly. This has been an issue for MCPC which + provides both Forge and Bukkit support to players. By adding the + DimensionRegisterPacket class, MCPC now has the ability to send the + required packet to client to register a dimension with DimensionManager. + LexManos: Cleanup Dimension Registration packet, generate takes no arguments, and added fix to world to prevent providers from overwriting the dimension ID. + LexManos: Fix potential GL issue when atlas animations bind textures without informating RenderEngine. + +Build 1.5.2-7.8.0.710: + LexManos: + Introduced the framework for Forge's packet handler system. Heavily based off FMLPacket. + Packet splitting and reconstruction is handled. + +Build 1.5.2-7.8.0.708: + Christian: + Updated FML: + MinecraftForge/FML@3bf50c4bbe82f0cc317dafcf2a569cb5210bc738 Fix server side derp with Forge network packet handler + +Build 1.5.2-7.8.0.707: + LexManos: Fix type in biome list. + LexManos: Fixed creative tab rendering with invalid color closes #588 + +Build 1.5.2-7.8.0.706: + Christian: + Add forge network handling support + + Updated FML: + MinecraftForge/FML@4922e90d81d8b8b9374c4d04858a06c5bf03965c Separate network mod config from setup. Allows for Forge Packet Handler nicety + +Build 1.5.2-7.8.0.705: + mehvids: Add hitInfo field to MovingObjectPosition for when an int doesn't suffice + +Build 1.5.2-7.8.0.704: + LexManos: Fix another NPE when Items are in Block range with custom renderers, Modders keep your items out of the block range! Closes #581 + LexManos: Fixed render count for stacks of blocks 40+ and distrabution of items based on scale. Closes #579 + +Build 1.5.2-7.8.0.703: + Christian: Remember x & z passed to getTopSolidOrLiquidBlock and use it for foliage tests. Fixes #575 + +Build 1.5.2-7.8.0.702: + Christian: Fix blending on the hotbar. Closes #574 + +Build 1.5.2-7.8.0.701: + Christian: + Updated FML: + MinecraftForge/FML@23b070c7d02a8da44bf04c2f9ba2b485a44ad967 Alternative @SidedProxy setter for Scala. + MinecraftForge/FML@2cca7aa759b4b6c3a128ce43bbd924e4762c43c2 Some more Scala @SidedProxy adjustments. Now properly supporting pure singletons, i.e. object C { @SidedProxy(...) var proxy: P = null } Removed fallback, as all such singletons are properly handled by the new code now, and class implementations fall back to the code also used for plain Java mods. + MinecraftForge/FML@8517a824e5251c409e05999d42fc6d70497609f5 Merge declaration and initialization of a variable. + MinecraftForge/FML@a3a920437f3ede6841ae2c449a38975b02b28088 Merge pull request #230 from fnuecke/master + Christian: Add in a very simple stencil bit registry to try and arbitrate between mods wanting to use stencil bits in rendering + +Build 1.5.2-7.8.0.700: + hbiede: + Added oreQuartz + + Gives a default quartz Ore Dictionary (I know of at least 3 used by different mods that use Nether Quartz as an equivalent). + gholdampf: updated FurnaceRecipes.java.patch + mike.stengel: Created an ItemStack sensitive version of canHarvestBlock. + +Build 1.5.2-7.8.0.699: + CovertJaguar: + Possible NPE if the liquid isn't in the LD + + https://github.com/BuildCraft/BuildCraft/issues/787 + +Build 1.5.2-7.8.0.698: + LexManos: Fix NPE when rendering EntityItems that are not blocks but int he block range. + +Build 1.5.2-7.8.0.697: + LexManos: Prevent water from dropping snowballs. + +Build 1.5.2-7.8.0.696: + LexManos: Fire EntityJoinWorled event for forced entities {Players and there mounts} as well, just ignore the cancelled value. + +Build 1.5.2-7.8.0.695: + LexManos: + MinecraftForge/FML@787c0c4a6af3af60928b3a90f383a305a17a4347 Don't spit error on LWJGL not supporting 4.3 just warning. + Make custom item renderers attempt to use EQUIPPED type when running first person. For backwards compatiblity, will be removed in 1.6. + And a small change to make the 1.6 check not print it's stack trace. + +Build 1.5.2-7.8.0.693: + purpleposeidon: Fix render bounding box of trapped double chests + jholcroft: + Make getStencilBits static + + Made getStencilBits static so it can be called. + +Build 1.5.2-7.8.0.692: + LexManos: Move Partical rendering down in the order, after everything else. Should fix particals rendering behind water, digging process, and selection. + +Build 1.5.2-7.8.0.691: + LexManos: Fixed NPE in rendering dragged items. + +Build 1.5.2-7.8.0.690: + LexManos: + Attempt to allocate a 8-bit stencil buffer when creating Minecraft's display context. If that throws an error it will revert back to it's default values. + Also contains a method for modders to rereive how many bits the context was created with. Closes #552 + +Build 1.5.2-7.8.0.689: + LexManos: EntityPlayer sensitive version of Item.isValidArmor, deprecated older version. Closes #551 + LexManos: Changed to just plane entity for flexability. + LexManos: New RenderPlayer and RenderLiving events. Closes #493 + +Build 1.5.2-7.8.0.688: + pahimar: Update forge_at.cfg + +Build 1.5.2-7.8.0.687: + mitchpetrie29: Separate EQUIPPED and EQUIPPED_FIRST_PERSON Item Render Types + +Build 1.5.2-7.8.0.686: + LexManos: Capture and fire the PlaySoundAtEntity event for The client entity. Minecraft does some odd bypasses for no good reason. Thanks iPixile for reporting this. + +Build 1.5.2-7.8.0.685: + LexManos: + Updated FML: + MinecraftForge/FML@99bb50d8f8d27217ba58a41c802a504213e99461 Improved Entity Spawn Error + MinecraftForge/FML@c0cca7f41d5b080e39dd8d3d6cfc329295c822e6 Merge pull request #227 from CovertJaguar/patch-1 + MinecraftForge/FML@49111e9c5cffab49ec35f965801c3f0496f6def6 Add version detection to astyle and print error if it doesnt detect version 2.0+ + Also fixed astyle's config for max-instatement-indent that sometimes caused crashes with certian versions of astyle. + +Build 1.5.2-7.8.0.684: + LexManos: + Update to 1.5.2 PR. + MinecraftForge/FML@f0bba74a4748935ef3a715ae2f45feb75cc20376 Update for minecraft 1.5.2 + MinecraftForge/FML@62fdbad74c2507d147ecab56f56029135d88c6f5 Update MCP's md5 for the fixed srg files. + LexManos: + Updated FML: + MinecraftForge/FML@00f00b17bf0da262e6fe3e327ca2deedf7146305 Fix scalac detection to actually use the located command instead of defaulting to 'scalac' + LexManos: Fixed hardcoding of MC version in debug text. + LexManos: Bump version number for 1.5.2 + +Build 1.5.2-7.8.0.683-1.5.2: + LexManos: Bump version number for 1.5.2 + +Build 1.5.1-7.7.2.682: + cadyyan: Fixed build error handling using invalid Python syntax. + +Build 1.5.2-7.7.1.681-1.5.2: + LexManos: Fixed hardcoding of MC version in debug text. + +Build 1.5.2-7.7.1.680-1.5.2: + LexManos: + Updated FML: + MinecraftForge/FML@00f00b17bf0da262e6fe3e327ca2deedf7146305 Fix scalac detection to actually use the located command instead of defaulting to 'scalac' + +Build 1.5.1-7.7.2.679: + LexManos: Changelog generator will now bundle failed builds with the next successful build. Should make it look better and prevent the version numbers from being confusing. + +Build 1.5.1-7.7.2.678: + LexManos: Bump version to 7.7.2 so I can make a release. + +Build 1.5.1-7.7.1.676: + tobias: Fixed ListenerListInst not being rebuild after unregistering a listener, causing calls to unregistered event listeners. + tobias: Replaced derpy tabs with spaces + +Build 1.5.1-7.7.1.675: + kinglemming: + -Add vanilla Ores to the Ore Dictionary. No recipe replacement required. + -Add NBT-sensitive getMaxDamage() for ItemStack. + + Signed-off-by: King Lemming + +Build 1.5.1-7.7.1.674: + LexManos: Attempted a fix for the changelog generation, should print all builds back to 1 now. + +Build 1.5.1-7.7.1.673: + Christian: + Updated FML: + MinecraftForge/FML@cf9b5b445ba284d389c7e32a03d9c8ef43469042 Don't leave scala running in interactive mode. + +Build 1.5.1-7.7.1.672: + Christian: + Updated FML: + MinecraftForge/FML@cfda7fc738ce6079f625a3822ebff5e7e0db5669 Fix URL for MCP + MinecraftForge/FML@781c68121626321e0efddaf4c4db9f1b8b5911db Some fixups for scala compilation in MCP. Scala should now be compilable and reobfuscatable with srgnames in MCP. + Christian: Try and be less noisy about world leaks + Christian: ItemStack delegation to Item for damage values. + LexManos: Fix rotation issue with non-block items. + Christian: + Updated FML: + MinecraftForge/FML@ddadf93ca1d648d88fdb61c9625cd675c3650ccd Fix when an old scalac is present on the system to not fail the build + Christian: + Updated FML: + MinecraftForge/FML@aa200923f0fe0c548faa4f103d803ade2e49d19d Fix patch derp. + +Build 1.5.1-7.7.1.667: + Christian: + Updated FML: + MinecraftForge/FML@dcf069ca52738a7bb7bde01f1c7ebd2e06cd0ac6 Attempt to reduce lines on the screen for id mismatch. Hopefully prevents game crashes. + MinecraftForge/FML@58ba24add2a96bf4c079d5919f2d90dcc2f380e4 Fix possible NPEs in GameData + +Build 1.5.1-7.7.1.666: + Christian: + Updated FML: + MinecraftForge/FML@a3b5eaacfdd9218ef68d3dc064bba729b797cb3d Fix a small modloader compatibility derp: closes #222 + MinecraftForge/FML@677a6e578e84109702365da4a784f9a57d8c9957 Fix scala supporting SidedProxy. It should work now. + MinecraftForge/FML@334a76de75f2b417f04c23526c7e66ceb48e0de2 Update FMLDeobfuscatingRemapper.java + MinecraftForge/FML@42f1d8795599e0d1a516a1fdd7488a09b77e4565 Merge pull request #224 from Glought/master + MinecraftForge/FML@2dcabe01232b48009acbca6724565598761f561b Add a to string to fmlmodcontainer: should mean less derpy cyclic dependency data + MinecraftForge/FML@11ac46daebe901a6012a09ba5f6fe44af5b1be06 Fixing the GameRegistry. Now it is possible to register a Block with a BlockItem using following code: MyBlock myBlock = new MyBlock(); GameRegistry.registerBlock(myBlock, MyBlockItem.class, "myBlock"); where MyBlockItem class has one constructor with signature: public MyBlockItem(int id, Block block) + MinecraftForge/FML@c3fda11d100f9db7c32ef212ac37eade3e35d701 Merge pull request #225 from MarcinSc/master + Christian: Add forge/FML data to the f3 screen. + +Build 1.5.1-7.7.1.665: + LexManos: + Forge now takes control of GuiIngame's renderGameOverlay, and spits out a ton of events to give modders control of how the screen is rendered. + Inital draft for community feedback. + +Build 1.5.1-7.7.1.664: + LexManos: Allow spawning of Bonemeal particles even if block is not set. + +Build 1.5.1-7.7.1.663: + LexManos: Fix the BLOCK_3D render helper for items that aren't an instance of ItemBlock Closes #533 + LexManos: Fix replaceable checks to work on blocks with a non-replacable material, Closes #532 + LexManos: Restore world unload event for client worlds Closes #531 + +Build 1.5.1-7.7.1.662: + LexManos: Fix logic issue in CrashReportCategory patch, blame Jadedcat for sloppy quick patch. + +Build 1.5.1-7.7.1.661: + lhb: + Fix for ClassCastException when attempting to fetch Biome types from BiomeDictionary + + Attempting to fetch the BiomeDictionary types linked to a biome throws a ClassCastException. This fixes that + lhb: getBiomesForType will cause the same problem + +Build 1.5.1-7.7.1.660: + Christian: + Updated FML: + MinecraftForge/FML@b3d4ea05ec633fb1898e97febf786f1a3e420986 Fix possible NPE in findItemStack, closes #218 + Christian: + Simple block recolouring API: closes #525 + Fix up documentation on "rotation" API: it is up to the mod to decide interpretation of "rotation" for the mod/block. + +Build 1.5.1-7.7.1.659: + LexManos: Fix return value of EnchantPower hook, closes #518 + LexManos: Adds a field to the player for maximum health. Player.dat additions are present, getMaxHealth() needs a magic number for spawning. Closes #527 + +Build 1.5.1-7.7.1.657: + LexManos: New hook to allow Items to render Helmet overlays like pumpkins do. + +Build 1.5.1-7.7.1.656: + Christian: + Updated FML: + MinecraftForge/FML@394f424185a044afcd6b31f400e731478171dd18 Fix to output versions in crash logs + MinecraftForge/FML@8f35adca7a41c280a4b63d4787f042f615966cac Use more expressive language when a version specifier is a simple unbounded above condition + +Build 1.5.1-7.7.1.655: + Christian: + Updated FML: + MinecraftForge/FML@5673c1dd2966536000c2b3f17f85131204c4a291 Add srgname to registerTileEntityWithAlternatives + MinecraftForge/FML@7aea09f4ca2f087d59ff6cb0de1c8e3e8b9ea4df Add type info to properly deobfuscate overloaded fields. Fixes #210. + MinecraftForge/FML@edffd04ed2e89ece75189f76b92ae47643ec92f8 Add in some caching of the read field descriptions for efficiency + MinecraftForge/FML@0daf1a6df4203d97be65a76a46550f6ad22ccc79 Merge branch 'agaricusb-fix-deobf-field' + MinecraftForge/FML@ada52078c75fdfa506a4287c112d01d9af961d5a Merge pull request #216 from agaricusb/add-srgname + +Build 1.5.1-7.7.1.654: + jmacwilliams: fixed a bug that prevented proper lava generation near bedrock + +Build 1.5.1-7.7.1.653: + LexManos: Fix AIOOB in crash report stack trimming. + +Build 1.5.1-7.7.1.652: + pahimar: Fix a derp in that we provision the various arrays for a face, even if we are not going to parse data into it. Solves NPEs for when obj models that don't have texture coordinates attempt to render. + pahimar: Missed a bit + +Build 1.5.1-7.7.1.651: + LexManos: Cave and Ravine gen will now take into account the Biomes top and foller block, allowing them to break the surface in modded biomes. Beaches, MushroomIslands and Deserts are exempt from this check to preserve vanilla world gen functionality. Closes #491 + +Build 1.5.1-7.7.1.650: + Christian: Fix offset in AdvancedModelLoader. *doh* + +Build 1.5.1-7.7.1.649: + LexManos: Added NBT data to liquid stacks. Closes #501 + LexManos: Added a small method in the Block.java to specify the amount of enchanting power it can supply to an enchanting table. Closes #508 + +Build 1.5.1-7.7.1.648: + LexManos: Item callback for EntityItem update tick. Closes #426 + LexManos: Add Item 'swing' callback for use when playing the arm swing animation. Closes #505 + +Build 1.5.1-7.7.1.647: + Christian: Delete sneaky extra file + +Build 1.5.1-7.7.1.645: + LexManos: Re-add and mark deprecated the old signature for ForgeHooksClient.getArmorTexture. + +Build 1.5.1-7.7.1.644: + Christian: + Deprecate preloadTexture, make it a no-op. Should stop derpiness with new + texturing system performance tweaks. + +Build 1.5.1-7.7.1.643: + LexManos: + Updated FML: MinecraftForge/FML@4836b3272a9b292c62816c1d1f9e845486753839 Re-worked the Texture patches, optifine helper function, and re-added support fo + r dynamically rotating the texture for mod authors who do things horribly wrong. + +Build 1.5.1-7.7.1.642: + Christian: + Fix performance of texture uploads + + Updated FML: + MinecraftForge/FML@00c788308881a07a683e17e2e9382313f3719b45 Very significant improvement in performance by using glSubImage to upload data. Inspired by frequent complaints about performance of hires texture packs. They probably still need a beefy system but should work. Hopefully I can figure out why the subImage GL side copy isn't working properly for an even more significant speed boost. But this gets things started. + MinecraftForge/FML@57ad221cc6d9605b9d521f86620c2a31f922ac24 And add the patches *sigh* + Christian: + Updated FML: + MinecraftForge/FML@a31607ae7d0214101679a1ecf1ae8032a5257eda Fix compilation derp, and clean up rotation helper. + +Build 1.5.1-7.7.1.640: + LexManos: Small optimization for usages of Minecraft.getGLMaximumTextureSize(), only need to calculate it once. + LexManos: Small bugfix in Stitcher that was preventing ti from fully filling the possible texture space. Should lower the amount of empty space in textures. + LexManos: + Optimize Texture loops a bit for non-rotated textures. Should help the FPS loss on higher resolution texture packs. If it becomes a major issue we may have to look into a more optimized animation system. + + https://mojang.atlassian.net/browse/MC-13206 + +Build 1.5.1-7.7.1.639: + LexManos: Fix scoreboard saving bug caused by our fix of vanilla map saves. + +Build 1.5.1-7.7.1.638: + LexManos: Updated FML: MinecraftForge/FML@1de89525cc2265bdce8704d9bd0d31c57bca4d97 Fixed issue with instalation when java/javac commands had quotes. + LexManos: Deprecate long dead interface that moved to FML. remvoe next MC version. + +Build 1.5.1-7.7.1.637: + LexManos: Updated FML: MinecraftForge/FML@704a70902fca3de620375116a33dccd3d6d576d0 Sanitize input to isRemappedClass to use '/' as a package seperator like the srg files. + +Build 1.5.1-7.7.1.636: + froggytheturtle: + This allows the result of the explosion to take into account metadata, + tile entities, or even to cancel it altogether. + + Allowed block exploding to take into account tile entity and metadata + LexManos: New hook to allow Items to provide there own armor models. Closes #487 + +Build 1.5.1-7.7.1.635: + LexManos: Fix item deletion in creative menu for items that are the same id/meta but differnet NBT's. Closes #479 + LexManos: Untag NBTTagList.removeTag as client side only, allowing simple removal ont he server side. Closes #477 + +Build 1.5.1-7.7.1.634: + LexManos: Allow items to provide there own FontRenderer for there tooltips. Added for #463 + +Build 1.5.1-7.7.1.633: + ProjectZulu: Added maxCanSpawnInChunk event to allow overriding of creature chunk spawn cap + ProjectZulu: Clarify Factory call and Event Functionality + LexManos: Add function to remove categories from a configuration, indavidual properties can be removed using ConfigCategory.remove() Closes #462 + +Build 1.5.1-7.7.1.632: + LexManos: + Pulled Biome Tag System by Emasher, Closes #433 + An issue with biome adding mods which is becoming increasingly annoying for players, is that many mod authors that add biome specific world generation or mobs in their mods, for the most part, hard code them to work with vanilla biomes only. This becomes a huge problem when it's difficult to even find a vanilla biome, let alone a specific one, when biome mods are installed. + + A simple solution to this problem is a tag system for biomes that allows mod authors to set up their world generators, or mobs to generate or spawn in biomes that have been registered with a specific tag such as "FOREST", or "FROZEN". I wrote such a system a few months ago, which I've been using with my own mods, and have made available to anyone who wants to use it. Since then, I've had requests from mod authors and players alike to try and get it, or at least similar functionality, into Forge, where other mod authors will be more comfortable using it. + + Aside from the tags, it also includes a rule based system to classify biomes that have not already been registered with it when information is requested on them (You can opt out of this by registering a biome as type "NULL"). And additionally, the ability to register IWorldGenerators for specific biomes, or biome types (tags) to speed up chunk generation a little bit. + +Build 1.5.1-7.7.1.631: + LexManos: Deprecate IArmorTextureProvider, moved to Item. And exposed more information to the function. Closes #365 + +Build 1.5.1-7.7.1.630: + LexManos: Updated FML: MinecraftForge/FML@570faeb790745c35403c67fabab57651b71da576 Added the ability to save transformed classes to disc for debugging. + LexManos: Add checking for 'ENUM$VALUES' in EnumHelper. Eclipse uses it's own internal compiler which does not follow the java standard of making the values field names $VALUES and private. Instead its public and ENUM$VALUES. Closes #502 + +Build 1.5.1-7.7.1.629: + LexManos: Revert MinecraftForge/MinecraftForge@f594109b30c87f5a0996eee9e8c4513380733cee If concurancy issues arise we will reassess. The provided solution caused entities to be removed incorrectly and cause 'invisible' entities client side. + +Build 1.5.1-7.7.1.628: + LexManos: Fix EntityPlayer passed to Bonemeal event. + +Build 1.5.1-7.7.1.627: + LexManos: Fix off-by-one in rotated textures. + LexManos: Removed index bounds checking in some chunk functions, if you error blame Grum. + +Build 1.5.1-7.7.1.625: + LexManos: Fix vanilla texture bug causing rotated textures to be placed wrong. + +Build 1.5.1-7.7.1.624: + Christian: + Updated FML: + MinecraftForge/FML@8b8837c9ff635d4988e0a1504fca38667825daf0 Fix NPE when branding isn't present + +Build 1.5.1-7.7.1.623: + kraphteu: Remove unneeded SideOnly. ref: Buildcraft/Buildcraft#710 + +Build 1.5.1-7.7.1.622: + Christian: + Removed obsolete patches + Updated FML: + MinecraftForge/FML@26ccb9106e443e664b0fdc1b95c3600b90ab2bc5 Change snooper/crash report brand handling. fmlbranding now loads another string! + MinecraftForge/FML@eff464cf0e656d92dfedf16e79e5cd6c36b9fc76 And the core patches for that + +Build 1.5.1-7.7.1.621: + Christian: Sanity check the item ID for loaded liquid stacks better. + +Build 1.5.1-7.7.1.620: + Christian: Make liquidstacks immutable in their type data. Sorry about this, but it makes things a lot easier. + Christian: Add in persistence code for LiquidTank. Using it should protect against liquids that get removed f.e. Closes #395 + +Build 1.5.1-7.7.1.618: + Christian: Fix up liquidstack so it knows about the texture sheet for it's icon + +Build 1.5.1-7.7.1.617: + Christian: Fix AT file + +Build 1.5.1-7.7.1.616: + Christian: Fix possible NPE in ChunkManager. Closes #478 in reality + +Build 1.5.1-7.7.1.615: + Christian: made BlockFluid.theIcon protected + Christian: fix bug #489 from #429 + Christian: Fix up some liquid logic + +Build 1.5.1-7.7.1.614: + Christian: + Updated FML: + MinecraftForge/FML@2bc6a0666f8a54f6b1fbc3398c6e3a385ecd35b5 Attempt to make any "default package" class public. This might fix problems with certain modloader mods that ship changes to vanilla classes. + Christian: Use the liquid name in liquid stack persistence. Closes #429 + Christian: Fix hashCode + Christian: + Updated FML: + MinecraftForge/FML@0d844874124649099dbcbb9ae2b36719e1dda25f Fix up derp in access transformer + +Build 1.5.1-7.7.1.611: + LexManos: Bump version number for 1.5.1 Note: We really need to do this more... + +Build 1.5.1-7.7.0.610: + LexManos: Fix NPEs when modders stupidly register null texture names. + +Build 1.5.1-7.7.0.609: + LexManos: Fixed issue with Event.hasAnnotation ignoring it's parameter. And cached its values for potential performance gain. Closes #482 + +Build 1.5.1-7.7.0.608: + jesse: + Entity Extended Properties Changes + + Adds IExtendedEntityProperties interface, which specifies three methods + that are needed: Init, Save, and Load. + + Adds the EntityConstructing event, which is called during the + constructor of Entity. It is needed there so that the reference is in + place during the ReadNBT call. + + Adds hooks into Entity that allow registration of + IExtendedEntityProperties classes, as well as saving and loading to NBT. + jesse: + Brewing Stand Changes + + Added an event on potion ingredient applied. Event contains the item + stacks of each of the potions being brewed as well as any remaining + ingredients. + + Changed TileEntityBrewingStand and SlotBrewingStandPotion to look for + instanceof ItemPotion rather than potion.itemID + jesse: + Player Flyable Fall Event + + Adds an event to EntityPlayer that is posted on player fall when the + player has flight capabilities. + Christian: Fix itemframe render bug + Christian: Add in block rotation support. It supports most vanilla blocks (hopefully), logs should be added soon. + jesse: + Access Transformer Changes + + AT changes and corresponding class changes. + Additions (all made public): + EntityLiving.targetTasks + PotionHelper.potionRequirements + PotionHelper.potionAmplifiers + PotionEffect.duration + Potion.setIconIndex + Item.setPotionEffect + Block.blockHardness + Block.blockResistance + jesse: + Enderman Teleport Event + + New event when an enderman teleports that allows the teleport location + to either be modified or completely cancelled. + jesse: + Enderman attackEntityFrom changed + + Changed so that if the teleport fails upon being attacked, Endermen will + take damage as normal. + jesse: + Ender Teleport Changes + + Renamed Ender Teleport Event and added it in to ender pearls. + jesse: + quick bugfix in entityenderman + + reversed boolean check on event result + Christian: + Updated FML: + MinecraftForge/FML@2d368c4c2eb6b4e0bb60757b6e1679c23aaad9db Itemstacks in the GameRegistry (manual registration by mods) + Christian: + Updated FML: + MinecraftForge/FML@5e1949eb0e3a43d3ec6c710289532d93f6819934 Clone the itemstack, and allow for passing in a stacksize + Christian: + Updated FML: + MinecraftForge/FML@ede93d438f2b5fab92cd6a459247ca158354e430 Validate supplied stack size + MinecraftForge/FML@d73ac867df775174dafdd2da193fabd7c3e7407e Add a mechanism to dump the registry- useful for mod developers. + Christian: + Updated FML: + MinecraftForge/FML@82bc9f1b35f5d51a722d294dd252e6bab4d54fa4 Add some information, and a log message letting you know it worked + Christian: Update patches! + Christian: Re-enable changelog? Hopefully... + Christian: Changelog fixup + Christian: Damn you python and your tab obsession! + +Build 1.5.1-7.7.0.605: + Christian: Fix AT config for texturemap + +Build 1.5.1-7.7.0.604: + Christian: + Allow itemstack sensitive damage computation for attacks. Should allow + storing data in the nbt :) + +Build 1.5.1-7.7.0.603: + Christian: + Updated FML: + MinecraftForge/FML@d9db27275ea06d37ae75e201140019ca152314b0 Fix mismatch screen a bit. Should render more correctly now and at least not be blank in a lot of circumstances.. + Christian: Allow items to decide if they can or cannot have book enchantments applied + +Build 1.5.1-7.7.0.602: + Christian: + Updated FML: + MinecraftForge/FML@d1ff1967b50f2ff2edf0b60acdb6508c0a3eeb06 Fixed FMLRelaunchLog's Newline Handling + MinecraftForge/FML@591a25722b36d2d1b200a31278cb8da117363f6b Merge pull request #208 from jrtc27/patch-1 + +Build 1.5.1-7.7.0.601: + Christian: + Updated FML: + MinecraftForge/FML@f709ce757984b13acb7208d6d8fbdeaa83d2928d Fix missing block world rendering + MinecraftForge/FML@748eece456e079a21112a77047d004d4f410b170 Merge pull request #206 from mDiyo/patch-1 + MinecraftForge/FML@012a755bb9ce9737c843b0dfd86473d143b637be Fix up patch properly. Also, fix md5s for the jars. + +Build 1.5.1-7.7.0.600: + LexManos: + Update to 1.5.1 Pre-Release: + MinecraftForge/FML@9565529baf77de27ed8b75be2065da3ba08d16c8 Updated to latest MCP and Minecraft 1.5.1 Pre-release. + MinecraftForge/FML@a573faf92def5dd01af380b3ca86de877c1178a2 Someone derped up this function bad, revert name. + LexManos: MinecraftForge/FML@aaf02ea2ac938d8cbaafdd2f59985c0604d648d7 Updated for new PR client jar. + +Build 1.5-7.7.0.598: + LexManos: + Updated FML: + MinecraftForge/FML@3c346247e1c5de12d4548f6a99349157057e2de6 Fix NPE with CoreMods who do not have the new MCVersion annotation. + LexManos: + Updated FML: + MinecraftForge/FML@625da6492dddcaca8133718aeee97f9981ced623 Fix install.py --mcp-dir option. Fixes #204. + MinecraftForge/FML@687d3c059d054c338c25a489be206a9f3dc63d81 Merge pull request #204 from agaricusb/fix-mcpdir + +Build 1.5.1-7.7.0.597-1.5.1: + LexManos: MinecraftForge/FML@aaf02ea2ac938d8cbaafdd2f59985c0604d648d7 Updated for new PR client jar. + +Build 1.5-7.7.0.595: + LexManos: Change placement of ChunkDataEvent.Save call to apply before sending to worker thread. + +Build 1.5-7.7.0.594: + Christian: + Updated FML: + MinecraftForge/FML@5cc90f060caace93c0bf041d3cc37208f425f623 Fix the logger to treat newlines better, hopefully. Closes #199 + MinecraftForge/FML@5e3af8ac0e18cfa3a92f9ba726ec1a6b55e87d97 Use the relaunch log, for class circularity safety. + MinecraftForge/FML@ce949e6099fe2a63ee6774acd6e55aa55d3b3673 Support simple mc version test in coremods, only effective through jar loading. Also, log some more data about the environment. + +Build 1.5-7.7.0.593: + LexManos: + New TextureStitchEvents called before and after a TextureMap gathers and stitches textures together. + Also added a config option to diable the writing of resulting stitched textures to disc. Default disables the writing. + +Build 1.5-7.7.0.592: + LexManos: + Updated FML: + MinecraftForge/FML@24022ab6ba79e4babb57fc0db893c23d4aec85bc Added comments to note FML-only methods + MinecraftForge/FML@8905237306230a33e2a3bab7a2b6f7a8b42d94e4 Merge pull request #200 from bspkrs/patch-2 + MinecraftForge/FML@577b19c1cf12a354112e829fb5704c32fd6cd0a5 Fix potential NPE in class loading and add extra debug information. + +Build 1.5-7.7.0.591: + LexManos: Fix placing of certian items on Redstone Blocks. + +Build 1.5-7.7.0.590: + LexManos: Fix equipment slots for items when right clicked, and dispensed using a dispensor. + +Build 1.5-7.7.0.589: + LexManos: Prevent pistons from generating snowballs. + LexManos: Fix logic inversion that allowed SnowMen to create snow on hoppers. + +Build 1.5-7.7.0.588: + lepko.san: Fix ShapedOreRecipe checking mirrored recipes + +Build 1.5-7.7.0.587: + Christian: Fix multipass item rendering so that it uses the right spritesheet for the item. + +Build 1.5-7.7.0.586: + froggytheturtle: + Made WorldServer.allPlayersSleeping public + + Made EntityPlayer.sleepTimer public + + Sleep changes + +Build 1.5-7.7.0.585: + LexManos: Fix Activator rails activating TNT carts, closes #458 + +Build 1.5-7.7.0.584: + github: Update ForgeDummyContainer.java + +Build 1.5-7.7.0.583: + Christian: + Updated FML: + MinecraftForge/FML@c5d5f4e5164111c5ae63e8de7ce97cc583d73e6e Fix AllPublic access transformer not affecting methods. Should fix modloader compatibility + +Build 1.5-7.7.0.582: + LexManos: + Updated FML: + MinecraftForge/FML@4762d4d8ef00bd789ffb6bccbd12f7478b07da62 Allocate more ram {typically 256 is defailt} to fermflower, should fix decomplication issues on OSX + MinecraftForge/FML@6370c242f0e1cb8ec80c7dccc1133cb0d0607bae OS X's python 2.6.1 has a bug in zipfile.extractall that makes it unzip directories as regular files. So switch to extract + +Build 1.5-7.7.0.581: + LexManos: Remove the block if TE errors. + +Build 1.5-7.7.0.580: + LexManos: Add config toggle to atempt to remove TileEntities and Entities that error during there update without fully crashing the server, use at your own risk. Closes #424 + +Build 1.5-7.7.0.579: + Christian: + Updated FML: + MinecraftForge/FML@8f2dbf7046f52d836993edb946d7d310b399bf9d Fix up stupid derp in IMC code: actually reset the IMC list after each delivery. Fixes a bunch of mods. Sorry everyone. + +Build 1.5-7.7.0.578: + ohai.iChun: + [Bugfix] One should not assume an item would use the item spritesheet. + + Item class has a func to return an int to use terrain.png or items.png. This makes forge take account of it. + +Build 1.5-7.7.0.577: + LexManos: Fix bug with rendering one too many passes for ItemEntities Closes #450 + LexManos: Fix RedstoneBlock power issues, Closes #452 + LexManos: Fix for nether quartz not generating in the nether, Closes #454 + +Build 1.5-7.7.0.576: + LexManos: Deprecation Sweep in DungeonHooks and fixed wildcard in ChestGenHooks remove function. + +Build 1.5-7.7.0.575: + LexManos: Fix RenderItem to work with items that use the terrain texture map that aren't in the block ID range. Close #443 + LexManos: Move the RenderWorldLastEvent back to before renderHand like it was in 1.4 Closes #444 + LexManos: Add call to EntityLiving when counting entities for Spawning Cap. Closes #447 + LexManos: Fix missed wildcard change in OreDictionary closes #448 + +Build 1.5-7.7.0.574: + LexManos: Fix crash when EnumHelper can't find $VALUES field, log info, and return gracefully. + +Build 1.5-7.7.0.573: + Christian: + Updated FML: + MinecraftForge/FML@23ea835fa7bc0cdb466d058814b5a0e0c67e8c9a Pass obfuscation status to coremods + +Build 1.5-7.7.0.572: + Christian: Some tweaks to the liquid dictionary, to allow for canonical liquid stacks for things like rendering + Christian: + Updated FML: + MinecraftForge/FML@d88db6c0cfd5484428b574889eae02d34535beae Fix up deep tree deobfuscation + +Build 1.5-7.7.0.571: + LexManos: Removed get/setTextureFile from Block, nolonger used. + LexManos: + Updated FML: + MinecraftForge/FML@7b722bfcd6d4c6867d15492c293a455dfd50d272 Update MCP for latest PR silent update. + MinecraftForge/FML@c6dab815f4e036e25b8f56bef7b8ee63f838adb4 Missed joined.exc, must fix scripts. + +Build 1.5-7.7.0.569: + LexManos: + Updated FML: + MinecraftForge/FML@a90504315e928915345c7b04972d912cdaa0bfdb Readjust size of mods button when Minecraft Realms button is enabled. + +Build 1.5-7.7.0.568: + Christian: Fix the oredictionary for the new recipe wildcard value of Short.MAX_VALUE. + +Build 1.5-7.7.0.567: + Christian: + Updated FML: + MinecraftForge/FML@3765ceb02d783ae5156976f3165bafdb6a3ddbb3 Update MCP, fixes the "broken texture packs" problem. + +Build 1.5-7.7.0.566: + Christian: + Updated FML: + MinecraftForge/FML@179c504746910d4196eef3ee2d56f63cf585c983 Simplify logic in tick start/end + MinecraftForge/FML@29edd242cd7a1fadedf4fb874ea8bbd4e643bffa Fix coremods without a manifest crashing the game. Closes #181 + MinecraftForge/FML@ac16845fc4661fa046a252eda7f9a9a847940189 Fix demo mode crash. Closes #187 + MinecraftForge/FML@984291cee91f585a6f4300eedfed882c814843f8 Fix supertype parsing to handle null superclass (Hi Object!). Closes #160 + MinecraftForge/FML@f6479299936f0f94cfc43210dd9dd44b8b5350ef Merge branch 'master' of github.com:Uristqwerty/FML + MinecraftForge/FML@b301e8e4c1877be246fd4f0b45085b70773d8f2b Change type of connection queue to a concurrent linked queue. Much more efficient, hopefully. Closes #189 + Christian: + Updated FML: + MinecraftForge/FML@dab22f5b74f3f2a410e20583f811605dc8e3c05f Fix "0 mods" display when installed in forge. + +Build 1.5-7.7.0.565: + Christian: + Updated FML: + MinecraftForge/FML@485db6be2e6b54a9a523a2b06e0d886792b0826a Use the reobfuscation maps in the reflection helper for field lookups: should help some reflection cases with the deobf. + Christian: + Updated FML: + MinecraftForge/FML@591e65fa1aa52d2a72dc527ad1c2ac53c8eb94c4 Revert "Use the reobfuscation maps in the reflection helper for field lookups: should help some reflection cases with the deobf." + MinecraftForge/FML@2a779ec3289f695b477ec6b0822a27801e2deba1 Try a different way of remapping the fields. Should work because it's userspace, not relauncher space + MinecraftForge/FML@ca2d8bd83475f37946b86cf6fabd8ff810f9c2bf Fix reflection helper: it needs to unmap the classname to find the field maps. + +Build 1.5-7.7.0.563: + Christian: + Updated FML: + MinecraftForge/FML@25f3fcad4654d19637878bdfb2b70a9586fb3fc9 Fix up some relauncher stuff: the vanilla applet works now, as do other applets. Deobf data is resolveable for them too. + +Build 1.5-7.7.0.562: + LexManos: + Updated FML: + MinecraftForge/FML@6bf7c9878cc959d5f5fa8ec0bf9d0d75037df882 Fixed srg name of minecraftDir for runtime deobf. + +Build 1.5-7.7.0.561: + Christian: Refresh patch + Christian: + Updated FML: + MinecraftForge/FML@95d0ff18cdca3b5a91b648c847c00f559f8ce6f2 Fix runtime deobfuscation for remapped inner classes + +Build 1.5-7.7.0.560: + LexManos: + Updated FML: + MinecraftForge/FML@86a9c7d35953296f7c8bd3a2b1b43115ef0f9308 Fixup reobfusication of server code if present. + MinecraftForge/FML@8e7956397dd80902f7ca69c466e833047dfa5010 Just enable server side compile, and warn not to complain tous. + MinecraftForge/FML@889efc1c0a9216b55f6de275e4f4a279d977e60c Fixes GameRegistry.registerBlock + MinecraftForge/FML@fe1623a36a1bb8b0a046d833e896fd46d88898ef Merge pull request #195 from RainWarrior/snapshot15 + MinecraftForge/FML@62f5adf8e21d59408af409a88b2c81757fd3c587 Revert "Fix modlist to use the new texture binding functions, i think" + MinecraftForge/FML@58ee06ea8edf508daa4ab3920790c0153cf6660d Some fixes for the snapshot + MinecraftForge/FML@368a2245ef0071b0b7a35d3bd78ab1ae379f8faf Merge branch 'snapshot15' + MinecraftForge/FML@1eba1dfdc00edf12ca3d8586dc342563218fc717 Fix accidental commands.patch overwrite + MinecraftForge/FML@ebdb166ec87e63503f0071e557cdb44629a0e0c2 Merge branch 'snapshot15' + MinecraftForge/FML@450dd8313c2e9e46d173bbd242f84d48266af7c8 Fix up some small things, merging into mainline + MinecraftForge/FML@1642bad402efe819f4e763bf4b460d8c04194849 Fix Multi-part entity children ID issue, mobs with custom spawning must deal with child ids themselves. + +Build 1.5-7.7.0.559: + LexManos: Update patche for jad-style names. + LexManos: Updated FML and at config for 1.5 snapshot + LexManos: First patches updae to 1.5, Many rendeirng related changes, most notibly removed Item/Block's getTextureFile() functions. + LexManos: Removed some dead code, We don't bind custom tessellators + CovertJaguar: MCL Update + LexManos: Bump major and minor version numbers to mark 1.5, it's gunna break everything. Should be a compileable 1.5 build. + Christian: + Fix a couple of forge patches + + Update FML: d075daf + d075daf Merge branch 'master' into snapshot15 Fix up compilation and patching errors + 1bd6847 Fix up packages.csv ordering for easier diffing + dd832f2 Update for MCP7.30c - fixes redstone rendering issues + aebf6eb Add in a registry method to allow for alternative TileEntity names- they will be used to support loading maps containing the older definiti + 8921cfe Remember to add the new patches! + cd67596 The "ServerStarting" event should now properly crash the server if it fails, so the client will properly exit. Also, added in a "pre-server + e1c6630 Javadoc cleanup + 5ce4e31 Fix breaking change + a99c488 Merge branch 'patch-1' of https://github.com/bspkrs/FML into gh-updates + 94282c5 Merge branch 'FMLLogFormatter' of https://github.com/donington/FML into gh-updates + 7ad8529 Update MCP to MCP7.26a and refresh MCP names + 15534ed Update address of the FML repository to the new location in all the files + aa822e3 Fix logical error in comment text + a14ab91 Update license text to make clear that FML is not a way to sidestep MCP licensing. + 0165742 Fix mcp conf md5 signatures for the snapshot + 26a5b31 FMLLogFormatter: dynamic log level name + LexManos: + Merge commit '695b080197bd577cc34fe6dbc72b74f4a74b2d5c' into snapshot15 + Testing cherry picking. + LexManos: + Sync up with FML, Will not run nativly as you need deobfusication_data.zip in your libs folder. + We have not setup the download for that yet, to make it yourself just zip joined.srg name it deobfusication_data.zip and put it in lib + LexManos: Not supposed to have debug stuff... + LexManos: Updated Forge to s13w09c + Christian: Fix up patches for FML, also, add in FML as a submodule rather than a zip + Christian: + Add in simple texture management for mods using the stitcher. Scope with "{domain}:{texture}" to + get textures that are not at /textures//{texture}.png but /mods/{domain}/textures//{texture}.png + instead + LexManos: Testing selective commit of submodule. + LexManos: + Added submodule changelog ganerator: + + Updated FML: + MinecraftForge/FML@e74087ee430633475c3ca058e54e3ef242a9d6aa Ignore again, testing submodule. + LexManos: Removed GNUWin32 files and uneeded files seince FML is now a submodule. + LexManos: Remove window helper batch files. + LexManos: Update python scripts to reflect that FML is now a submodule. Delete updateasmdata as it's in /fml/ now. Build should work once again. + LexManos: Change FML module to read-only connection. + Christian: Update submodule + LexManos: Copy over some needed files for debugging. + LexManos: Rework configuration, configs should now use Config.hasChanged to deterne if thehould call save(), also re-worked the saving to not use String.format as much. + LexManos: Fixed new python changes. + LexManos: + Updated FML: + MinecraftForge/FML@aed2cc446ad8d5882890c5f218eb894ea7bd2577 Force file name encoding to UTF-8, caused different zips on different systems. + LexManos: Fix animation location for textures with domains + LexManos: Add helper functions for deling with custom TextureStitched + LexManos: Add callback on TextureStitched to control texture loading. + LexManos: New world event for controlling potential entity spawnlists. For #430 + LexManos: Removed erroring imports and update build function to die on errors. + LexManos: Fix ItemSeedFood respecting custom soils. + LexManos: + Updated FML: + MinecraftForge/FML@debbdc00be8ea1a261cdff83785ddc7100419a74 Capture Minecraft logs into FML logging + MinecraftForge/FML@74fffc6fdc2eda8caa9a7feb0826d7babb84751a Update next render to 40 + Christian: + Call stitcher for non-existent textures as well. Probably allows + for generated textures. Hmmm + Christian: let's do it right this time. Hmmm + Christian: + Updated FML: + MinecraftForge/FML@abe4f73a9a3158f6f9d1ea2334798f54a25817bf FIX massive performance issue with FML. Thanks to @sfPlayer1 for finding this epic derp on my part! + Christian: Add an Icon to the LiquidStack, for rendering the liquid in various ways + LexManos: Readd second render pass to TileEntities and Entities, patches were missed when merging in master branch. As note, CB can DIAF. + LexManos: Fix compile error, forget to flush to disc. + LexManos: Make release quit on compile error. + Christian: Clean up Access Transformer mapping data + Christian: + Updated FML: + MinecraftForge/FML@e9ff699c2dcd787a3e0ebaa427c625a48de4c9fb Refresh the renderengine after modloading is complete. Should fix issues with out-of-place texture registration by mods. + MinecraftForge/FML@a723aa68606d57b0ee5bac8b1d1905abef440b54 Refresh copyright notices on everything + MinecraftForge/FML@c42a2101408b21799728c88e2d02c718c3b0dd36 Strip deprecated code + MinecraftForge/FML@6eeae8c49ff4359dc21c44eb73e4e043285cd8bf Fix up state transition derp when the server crashes with an error- it shouldn't double-derp + MinecraftForge/FML@81c6421f84c1bff359dfe927974e8730b348806a Tweak license text- any osi licensed project can use the asm transformer code + LexManos: + Updated to 1.5 Pre-release + Updated FML: + MinecraftForge/FML@2d98835db8c6a7665ef55117d60ab4318876836b Scala support! It's still primitive, I hope that people will like it. I do :) + MinecraftForge/FML@5bfaf7c1700191b6ed8f4752c9a95bf8c25323ef Global object registry, also, support the new itemblockwithmetadata constructor + MinecraftForge/FML@80a40c03e644840d827eb7d67ff97f6558eaa2e4 Update to MCP 1.5 and minecraft 1.5. + MinecraftForge/FML@b3e854a15d7c50b4967be8237df5fdace95a15ee Update for new MCP with srg reobf. + LexManos: Fix typos. + LexManos: Deprecated Forge's ISidedInventroy, there is a vanilla solution. Added temporary config option to legacy furnace slot orientation. + LexManos: + Updated FML: + MinecraftForge/FML@f1c6bdd57d41a938cb3326d509042f6842e42396 Support the MCP format of partial reobfuscation for portability. Ensure modloader-like compatibility + MinecraftForge/FML@0419b9d9751ade4497343aefaf2ca43703eb479a Update MCP info for latest + LexManos: Early define CrashReport classes to combat invalid crash details. + LexManos: Fix reobf call. + +Build 1.5-7.7.0.558-snapshot15: + Christian: Clean up Access Transformer mapping data + Christian: + Updated FML: + MinecraftForge/FML@e9ff699c2dcd787a3e0ebaa427c625a48de4c9fb Refresh the renderengine after modloading is complete. Should fix issues with out-of-place texture registration by mods. + MinecraftForge/FML@a723aa68606d57b0ee5bac8b1d1905abef440b54 Refresh copyright notices on everything + MinecraftForge/FML@c42a2101408b21799728c88e2d02c718c3b0dd36 Strip deprecated code + MinecraftForge/FML@6eeae8c49ff4359dc21c44eb73e4e043285cd8bf Fix up state transition derp when the server crashes with an error- it shouldn't double-derp + MinecraftForge/FML@81c6421f84c1bff359dfe927974e8730b348806a Tweak license text- any osi licensed project can use the asm transformer code + LexManos: + Updated to 1.5 Pre-release + Updated FML: + MinecraftForge/FML@2d98835db8c6a7665ef55117d60ab4318876836b Scala support! It's still primitive, I hope that people will like it. I do :) + MinecraftForge/FML@5bfaf7c1700191b6ed8f4752c9a95bf8c25323ef Global object registry, also, support the new itemblockwithmetadata constructor + MinecraftForge/FML@80a40c03e644840d827eb7d67ff97f6558eaa2e4 Update to MCP 1.5 and minecraft 1.5. + MinecraftForge/FML@b3e854a15d7c50b4967be8237df5fdace95a15ee Update for new MCP with srg reobf. + LexManos: Fix typos. + LexManos: Deprecated Forge's ISidedInventroy, there is a vanilla solution. Added temporary config option to legacy furnace slot orientation. + LexManos: + Updated FML: + MinecraftForge/FML@f1c6bdd57d41a938cb3326d509042f6842e42396 Support the MCP format of partial reobfuscation for portability. Ensure modloader-like compatibility + MinecraftForge/FML@0419b9d9751ade4497343aefaf2ca43703eb479a Update MCP info for latest + LexManos: Early define CrashReport classes to combat invalid crash details. + LexManos: Fix reobf call. + +Build 13w09c-7.7.0.556-snapshot15: + LexManos: Make release quit on compile error. + +Build 13w09c-7.7.0.555-snapshot15: + LexManos: Readd second render pass to TileEntities and Entities, patches were missed when merging in master branch. As note, CB can DIAF. + LexManos: Fix compile error, forget to flush to disc. + +Build 13w09c-7.7.0.553-snapshot15: + Christian: Add an Icon to the LiquidStack, for rendering the liquid in various ways + +Build 13w09c-7.7.0.552-snapshot15: + Christian: + Updated FML: + MinecraftForge/FML@abe4f73a9a3158f6f9d1ea2334798f54a25817bf FIX massive performance issue with FML. Thanks to @sfPlayer1 for finding this epic derp on my part! + +Build 13w09c-7.7.0.551-snapshot15: + Christian: let's do it right this time. Hmmm + +Build 13w09c-7.7.0.550-snapshot15: + Christian: + Call stitcher for non-existent textures as well. Probably allows + for generated textures. Hmmm + +Build 13w09c-7.7.0.549-snapshot15: + LexManos: Fix ItemSeedFood respecting custom soils. + LexManos: + Updated FML: + MinecraftForge/FML@debbdc00be8ea1a261cdff83785ddc7100419a74 Capture Minecraft logs into FML logging + MinecraftForge/FML@74fffc6fdc2eda8caa9a7feb0826d7babb84751a Update next render to 40 + +Build 13w09c-7.7.0.548-snapshot15: + LexManos: Removed erroring imports and update build function to die on errors. + +Build 13w09c-7.7.0.547-snapshot15: + LexManos: New world event for controlling potential entity spawnlists. For #430 + +Build 13w09c-7.7.0.546-snapshot15: + LexManos: Add callback on TextureStitched to control texture loading. + +Build 13w09c-7.7.0.545-snapshot15: + LexManos: Fix animation location for textures with domains + LexManos: Add helper functions for deling with custom TextureStitched + +Build 13w09c-7.7.0.544-snapshot15: + LexManos: Copy over some needed files for debugging. + LexManos: Rework configuration, configs should now use Config.hasChanged to deterne if thehould call save(), also re-worked the saving to not use String.format as much. + LexManos: Fixed new python changes. + LexManos: + Updated FML: + MinecraftForge/FML@aed2cc446ad8d5882890c5f218eb894ea7bd2577 Force file name encoding to UTF-8, caused different zips on different systems. + +Build 13w09c-7.7.0.543-snapshot15: + Christian: Update submodule + +Build 13w09c-7.7.0.542-snapshot15: + Christian: Fix up patches for FML, also, add in FML as a submodule rather than a zip + Christian: + Add in simple texture management for mods using the stitcher. Scope with "{domain}:{texture}" to + get textures that are not at /textures//{texture}.png but /mods/{domain}/textures//{texture}.png + instead + LexManos: Testing selective commit of submodule. + LexManos: + Added submodule changelog ganerator: + + Updated FML: + MinecraftForge/FML@e74087ee430633475c3ca058e54e3ef242a9d6aa Ignore again, testing submodule. + LexManos: Removed GNUWin32 files and uneeded files seince FML is now a submodule. + LexManos: Remove window helper batch files. + LexManos: Update python scripts to reflect that FML is now a submodule. Delete updateasmdata as it's in /fml/ now. Build should work once again. + LexManos: Change FML module to read-only connection. + +Build 13w09c-7.7.0.539-snapshot15: + LexManos: Updated Forge to s13w09c + +Build 13w05b-7.7.0.538-snapshot15: + LexManos: Not supposed to have debug stuff... + +Build 13w05b-7.7.0.537-snapshot15: + LexManos: + Sync up with FML, Will not run nativly as you need deobfusication_data.zip in your libs folder. + We have not setup the download for that yet, to make it yourself just zip joined.srg name it deobfusication_data.zip and put it in lib + +Build 13w02b-7.7.0.536-snapshot15: + mehvids: Gave entities and tile entities access to the second render pass for translucency. + Christian: Attempt to fix a possible NPE in the face of ChickenBones' hackery. ChickenBones. stop it! + Christian: + Fix a potential problem with "Entity already added" when using the dormant + chunk cache capability. The entities in the dormant chunk cache will get new + IDs prior to the cached chunk returning. + Christian: Fix NPE causing issue with the cache. Derpy derp. + Christian: + Add in TESR culling, and a new TileEntity method to allow for differential sizing of the + TESR view culling vs the TE collision bounding box (the former defaults to the latter) + Checked into a branch because it's likely to break expanded TileEntities. + Christian: Bump the revision number for the TESR and renderpass changes + Christian: + Add in a mechanism for explicit subclassing of WeightedRandomChestItem to allow for + generational style chest content generation rather than static. Cleans up some old code nicely + Christian: + We try and log a message if we detect a world leak: it's probably not infallible, but it should + help mod developers- if you see this when testing your mod with, say, mystcraft, you're probably + keeping a hold of an invalid handle to the World (either directly, or indirectly via Entity or TileEntity) + and you should look to refactor to wrap those handles in WeakReferences + LexManos: Moved warning logic down, so that no more tickets are isues if the mod is over it's alotment. Fixes #378 + LexManos: Forge Additions: Exposed ChunkCache.worldObj to public PR #383 + LexManos: Fixup a resource leak warning. + LexManos: Add DimensionManager.unregisterProviderType for PR #388 + LexManos: Added input getters for Ore recipies, and javadoc warning for modders, #390 + LexManos: Rework canSilkHarvest hook to try and honor vanilla overrides, should close #391 + LexManos: Added catch to TileEntityChestRenderer for potential crash when modders do bad things -.- Closes #389 + LexManos: Change access of upper and lower chest fields of InventoryLargeChest to public. Closes #387 + LexManos: Change WorldServer.allPlayersSleeping to public, and remove the SideOnly annotation on EntityPlayer.getSleepTimer() Closes #393 + LexManos: Fix initalization issue with the clamping threshold config value. And remove vanilla console spam related to it. + Christian: Fix small derp in TE + Christian: + Update FML:549b6fd + 549b6fd IMC tweaks: runtimeMessages now work (thanks for all that testing for this much requested feature!) and IMCEvent will no longer rem + 9fafdc1 More logging tweaks. You can probably configure individual mod log files if you wish now + f169f7c A log of logging cleanup. FML will now read logging.properties to configure logging channels a couple of times during startup. You + 3ac891f Try and handle "death on startup" a bit cleaner + 2dc0189 Deprecate the old GUI ticktype. They're dead and have been for some time. + dd98784 Tweak a method signature + 1c9a510 Add parameters to FML install to enable/disable certian aspects. Applying patches, running transformer/merger, and decompiling serv + 1bd6847 Fix up packages.csv ordering for easier diffing + Christian: + Add in "armor ticking"- implement the interface and the armor piece will tick. + + Update FML:22dbe41 + 22dbe41 Fix up mistake that broke all modloading. Nice. + Christian: Fix TESR rendering for double chests + Christian: Fix possible null case for collision bounding box. + Christian: Remove the single use interface ITickingArmor, and apply to Item directly. + Christian: + Fix ServerBrand retriever- forge is now forge,fml! + + Update FML: cd96718 + cd96718 Fix HD mob skins, FINALLY!!! Stupid eyes are stupid. + LexManos: Kill generated timestamp in config files, if you want to retreive this information, usethe file's modified time. Closes #404 + LexManos: Actually use the line parameter in ServerChatEvent, closes #401 + LexManos: Kill .sh wrappers until someone writes more robust versions, closes #392 and closes #402 + LexManos: Made LiquidStack.isLiquidEqual(ItemStack) properly check the contained liquid, in addition to obvious id/meta closes #399 and closes #403 + LexManos: Add item frame transformations to the EntityItem render helper Closes #407 + LexManos: Added a hook into SlotArmor so Items can control if they are classified as a Armor type. Closes #408 + LexManos: Fixes comparison for items in creative inventory, closes #411 + LexManos: Fix fortune modifier always passed as 0 to idDropped closes #412 + LexManos: Fix EventTransformer throwing an NPE when transforming a class that doesn't exist. Closes #413 + LexManos: Fix profiler issue with RenderGlobal patch. Closes #414 + LexManos: Jenkins needs this script, *pokes Overmind* -.- + LexManos: + Update FML to 556: + b6d6f235 Fix sprite map issue. + 1158aa46 Fix Language Registry, closes #FML 163 + 50ce6fb3 Option to disable renaming for srgnames. + LexManos: Disable automatic equiti of pcke dup items for players, and fixed index issues in Player.setCurrentItemOrArmor. + LexManos: Fixed entity colision above max world height, and below 0. Closes #400 + LexManos: Change usage of ketSet/get to entrySet in OreDictionary, closes #422 + LexManos: Fix movement speed check, closes #420 + LexManos: clarify what the size is measured in for the dormant chunk cache. -.- + LexManos: ItemStack sensitive versions of Item.getPotionEffect and Item.isPotionIngredient Closes #321 + LexManos: WorldGen*Trees shoud not respect custom soils. Closes #355 + LexManos: Added unload event for client worlds Closes #405 + LexManos: Store the glMultiTexCoord lightmap for later use with glDrawArrays closes #406 + LexManos: Add water and lava to liquid dictionary by default, closes #419 + LexManos: Bump version to 6.6.2, declaring Forge for MC 1.4.7 feature complete, as 1.5 is on the horizon, only bug fixes from this point on. Unless something major happens on Mojang's end. + LexManos: Fix TESR culling for beacons, and implement a good enough measure for Chests. + +Build 13w02b-7.7.0.535-snapshot15: + LexManos: + Merge commit '695b080197bd577cc34fe6dbc72b74f4a74b2d5c' into snapshot15 + Testing cherry picking. + +Build 1.4.7-6.6.2.534: + LexManos: Fix TESR culling for beacons, and implement a good enough measure for Chests. + +Build 1.4.7-6.6.2.533: + LexManos: Bump version to 6.6.2, declaring Forge for MC 1.4.7 feature complete, as 1.5 is on the horizon, only bug fixes from this point on. Unless something major happens on Mojang's end. + +Build 1.4.7-6.6.1.532: + LexManos: Added unload event for client worlds Closes #405 + LexManos: Store the glMultiTexCoord lightmap for later use with glDrawArrays closes #406 + LexManos: Add water and lava to liquid dictionary by default, closes #419 + +Build 1.4.7-6.6.1.531: + LexManos: WorldGen*Trees shoud not respect custom soils. Closes #355 + +Build 1.4.7-6.6.1.530: + LexManos: Fix movement speed check, closes #420 + LexManos: clarify what the size is measured in for the dormant chunk cache. -.- + LexManos: ItemStack sensitive versions of Item.getPotionEffect and Item.isPotionIngredient Closes #321 + +Build 1.4.7-6.6.1.529: + LexManos: Disable automatic equiti of pcke dup items for players, and fixed index issues in Player.setCurrentItemOrArmor. + LexManos: Fixed entity colision above max world height, and below 0. Closes #400 + LexManos: Change usage of ketSet/get to entrySet in OreDictionary, closes #422 + +Build 1.4.7-6.6.1.528: + LexManos: + Update FML to 556: + b6d6f235 Fix sprite map issue. + 1158aa46 Fix Language Registry, closes #FML 163 + 50ce6fb3 Option to disable renaming for srgnames. + +Build 1.4.7-6.6.1.527: + LexManos: Kill generated timestamp in config files, if you want to retreive this information, usethe file's modified time. Closes #404 + LexManos: Actually use the line parameter in ServerChatEvent, closes #401 + LexManos: Kill .sh wrappers until someone writes more robust versions, closes #392 and closes #402 + LexManos: Made LiquidStack.isLiquidEqual(ItemStack) properly check the contained liquid, in addition to obvious id/meta closes #399 and closes #403 + LexManos: Add item frame transformations to the EntityItem render helper Closes #407 + LexManos: Added a hook into SlotArmor so Items can control if they are classified as a Armor type. Closes #408 + LexManos: Fixes comparison for items in creative inventory, closes #411 + LexManos: Fix fortune modifier always passed as 0 to idDropped closes #412 + LexManos: Fix EventTransformer throwing an NPE when transforming a class that doesn't exist. Closes #413 + LexManos: Fix profiler issue with RenderGlobal patch. Closes #414 + LexManos: Jenkins needs this script, *pokes Overmind* -.- + +Build 1.4.7-6.6.1.524: + Christian: + Fix ServerBrand retriever- forge is now forge,fml! + + Update FML: cd96718 + cd96718 Fix HD mob skins, FINALLY!!! Stupid eyes are stupid. + +Build 1.4.7-6.6.1.523: + Christian: Remove the single use interface ITickingArmor, and apply to Item directly. + +Build 1.4.7-6.6.1.522: + Christian: Fix possible null case for collision bounding box. + +Build 1.4.7-6.6.1.521: + mehvids: Gave entities and tile entities access to the second render pass for translucency. + Christian: + Add in TESR culling, and a new TileEntity method to allow for differential sizing of the + TESR view culling vs the TE collision bounding box (the former defaults to the latter) + Checked into a branch because it's likely to break expanded TileEntities. + Christian: Bump the revision number for the TESR and renderpass changes + Christian: Fix small derp in TE + Christian: + Update FML:549b6fd + 549b6fd IMC tweaks: runtimeMessages now work (thanks for all that testing for this much requested feature!) and IMCEvent will no longer rem + 9fafdc1 More logging tweaks. You can probably configure individual mod log files if you wish now + f169f7c A log of logging cleanup. FML will now read logging.properties to configure logging channels a couple of times during startup. You + 3ac891f Try and handle "death on startup" a bit cleaner + 2dc0189 Deprecate the old GUI ticktype. They're dead and have been for some time. + dd98784 Tweak a method signature + 1c9a510 Add parameters to FML install to enable/disable certian aspects. Applying patches, running transformer/merger, and decompiling serv + 1bd6847 Fix up packages.csv ordering for easier diffing + Christian: + Add in "armor ticking"- implement the interface and the armor piece will tick. + + Update FML:22dbe41 + 22dbe41 Fix up mistake that broke all modloading. Nice. + Christian: Fix TESR rendering for double chests + +Build 1.4.7-6.6.1.520-TESRculling: + Christian: Fix small derp in TE + +Build 1.4.7-6.6.1.519-TESRculling: + Christian: + Add in a mechanism for explicit subclassing of WeightedRandomChestItem to allow for + generational style chest content generation rather than static. Cleans up some old code nicely + Christian: + We try and log a message if we detect a world leak: it's probably not infallible, but it should + help mod developers- if you see this when testing your mod with, say, mystcraft, you're probably + keeping a hold of an invalid handle to the World (either directly, or indirectly via Entity or TileEntity) + and you should look to refactor to wrap those handles in WeakReferences + LexManos: Moved warning logic down, so that no more tickets are isues if the mod is over it's alotment. Fixes #378 + LexManos: Forge Additions: Exposed ChunkCache.worldObj to public PR #383 + LexManos: Fixup a resource leak warning. + LexManos: Add DimensionManager.unregisterProviderType for PR #388 + LexManos: Added input getters for Ore recipies, and javadoc warning for modders, #390 + LexManos: Rework canSilkHarvest hook to try and honor vanilla overrides, should close #391 + LexManos: Added catch to TileEntityChestRenderer for potential crash when modders do bad things -.- Closes #389 + LexManos: Change access of upper and lower chest fields of InventoryLargeChest to public. Closes #387 + LexManos: Change WorldServer.allPlayersSleeping to public, and remove the SideOnly annotation on EntityPlayer.getSleepTimer() Closes #393 + LexManos: Fix initalization issue with the clamping threshold config value. And remove vanilla console spam related to it. + +Build 1.4.7-6.6.0.518: + LexManos: Fix initalization issue with the clamping threshold config value. And remove vanilla console spam related to it. + +Build 1.4.7-6.6.0.517: + LexManos: Moved warning logic down, so that no more tickets are isues if the mod is over it's alotment. Fixes #378 + LexManos: Forge Additions: Exposed ChunkCache.worldObj to public PR #383 + LexManos: Fixup a resource leak warning. + LexManos: Add DimensionManager.unregisterProviderType for PR #388 + LexManos: Added input getters for Ore recipies, and javadoc warning for modders, #390 + LexManos: Rework canSilkHarvest hook to try and honor vanilla overrides, should close #391 + LexManos: Added catch to TileEntityChestRenderer for potential crash when modders do bad things -.- Closes #389 + LexManos: Change access of upper and lower chest fields of InventoryLargeChest to public. Closes #387 + LexManos: Change WorldServer.allPlayersSleeping to public, and remove the SideOnly annotation on EntityPlayer.getSleepTimer() Closes #393 + +Build 1.4.7-6.6.0.516: + Christian: + We try and log a message if we detect a world leak: it's probably not infallible, but it should + help mod developers- if you see this when testing your mod with, say, mystcraft, you're probably + keeping a hold of an invalid handle to the World (either directly, or indirectly via Entity or TileEntity) + and you should look to refactor to wrap those handles in WeakReferences + +Build 1.4.7-6.6.0.515: + Christian: + Add in a mechanism for explicit subclassing of WeightedRandomChestItem to allow for + generational style chest content generation rather than static. Cleans up some old code nicely + +Build 1.4.7-6.6.1.514-TESRculling: + Christian: Bump the revision number for the TESR and renderpass changes + +Build 1.4.7-6.6.0.513-TESRculling: + mehvids: Gave entities and tile entities access to the second render pass for translucency. + +Build 1.4.7-6.6.0.511: + Christian: Fix NPE causing issue with the cache. Derpy derp. + +Build 1.4.7-6.6.0.510: + Christian: + Fix a potential problem with "Entity already added" when using the dormant + chunk cache capability. The entities in the dormant chunk cache will get new + IDs prior to the cached chunk returning. + +Build 1.4.7-6.6.0.509: + Christian: Attempt to fix a possible NPE in the face of ChickenBones' hackery. ChickenBones. stop it! + +Build 13w02b-7.7.0.508-snapshot15: + scott: Add ability to WorldTypes to display the 'Customize' button and react to it + LexManos: + Update FML: + New scripts for signing jars, and repackging source folders. + Fix LanguageRegistry loading files in UTF-8 format. loadLocalization should work for non-xml in all languages now (assumes UTF-8) + Fix incorrect end length calculation. Closes #161 Thanks BStramke! + LexManos: Fix check in getItem() to allow lowest item ID #361 + CovertJaguar: + Fixed render passes for EntityItems + + Should be < instead of <= + Christian: + Update licencing information to make clear that forge is allowed to redistribute and automatically + download parts of MCP, but this permission is not transitive to people distributing MinecraftForge + source independently of the MinecraftForge project. + + Update MCP to 7.26a and FML: 7ad8529 + 7ad8529 Update MCP to MCP7.26a and refresh MCP names + 15534ed Update address of the FML repository to the new location in all the files + a14ab91 Update license text to make clear that FML is not a way to sidestep MCP licensing. + Christian: + Update FML: a99c488 + a99c488 Merge branch 'patch-1' of https://github.com/bspkrs/FML into gh-updates + 94282c5 Merge branch 'FMLLogFormatter' of https://github.com/donington/FML into gh-updates + aa822e3 Fix logical error in comment text + 26a5b31 FMLLogFormatter: dynamic log level name + Christian: Merge part of PR #375 related to ChunkEvent.Load for the client side + Christian: + Update FML: 5ce4e31 + 5ce4e31 Fix breaking change + Christian: + Add in patch to change how playerinstance sends TE chunk updates. It should always send just the TEs + that changed now, and not "ALL" TEs. Also, added configuration value to change the 64 threshold to a + configurable number + Christian: Some javadoc fixes + Christian: + Change DimensionManager.getCurrentSaveRootDirectory() to try and work even for the new server about to start event + + Update FML:8921cfe + 8921cfe Remember to add the new patches! + cd67596 The "ServerStarting" event should now properly crash the server if it fails, so the client will properly exit. A + Christian: + Update FML:aebf6eb + aebf6eb Add in a registry method to allow for alternative TileEntity names- they will be used to support loading maps containing the older definiti + Christian: + Fix a couple of forge patches + + Update FML: d075daf + d075daf Merge branch 'master' into snapshot15 Fix up compilation and patching errors + 1bd6847 Fix up packages.csv ordering for easier diffing + dd832f2 Update for MCP7.30c - fixes redstone rendering issues + aebf6eb Add in a registry method to allow for alternative TileEntity names- they will be used to support loading maps containing the older definiti + 8921cfe Remember to add the new patches! + cd67596 The "ServerStarting" event should now properly crash the server if it fails, so the client will properly exit. Also, added in a "pre-server + e1c6630 Javadoc cleanup + 5ce4e31 Fix breaking change + a99c488 Merge branch 'patch-1' of https://github.com/bspkrs/FML into gh-updates + 94282c5 Merge branch 'FMLLogFormatter' of https://github.com/donington/FML into gh-updates + 7ad8529 Update MCP to MCP7.26a and refresh MCP names + 15534ed Update address of the FML repository to the new location in all the files + aa822e3 Fix logical error in comment text + a14ab91 Update license text to make clear that FML is not a way to sidestep MCP licensing. + 0165742 Fix mcp conf md5 signatures for the snapshot + 26a5b31 FMLLogFormatter: dynamic log level name + +Build 1.4.7-6.6.0.507: + Christian: + Update FML:aebf6eb + aebf6eb Add in a registry method to allow for alternative TileEntity names- they will be used to support loading maps containing the older definiti + +Build 1.4.7-6.6.0.506: + Christian: + Change DimensionManager.getCurrentSaveRootDirectory() to try and work even for the new server about to start event + + Update FML:8921cfe + 8921cfe Remember to add the new patches! + cd67596 The "ServerStarting" event should now properly crash the server if it fails, so the client will properly exit. A + +Build 1.4.7-6.6.0.505: + Christian: Some javadoc fixes + +Build 1.4.7-6.6.0.504: + Christian: + Update FML: 5ce4e31 + 5ce4e31 Fix breaking change + Christian: + Add in patch to change how playerinstance sends TE chunk updates. It should always send just the TEs + that changed now, and not "ALL" TEs. Also, added configuration value to change the 64 threshold to a + configurable number + +Build 1.4.7-6.6.0.503: + scott: Add ability to WorldTypes to display the 'Customize' button and react to it + CovertJaguar: + Fixed render passes for EntityItems + + Should be < instead of <= + Christian: Merge part of PR #375 related to ChunkEvent.Load for the client side + +Build 1.4.7-6.6.0.502: + Christian: + Update FML: a99c488 + a99c488 Merge branch 'patch-1' of https://github.com/bspkrs/FML into gh-updates + 94282c5 Merge branch 'FMLLogFormatter' of https://github.com/donington/FML into gh-updates + aa822e3 Fix logical error in comment text + 26a5b31 FMLLogFormatter: dynamic log level name + +Build 1.4.7-6.6.0.501: + Christian: + Update licencing information to make clear that forge is allowed to redistribute and automatically + download parts of MCP, but this permission is not transitive to people distributing MinecraftForge + source independently of the MinecraftForge project. + + Update MCP to 7.26a and FML: 7ad8529 + 7ad8529 Update MCP to MCP7.26a and refresh MCP names + 15534ed Update address of the FML repository to the new location in all the files + a14ab91 Update license text to make clear that FML is not a way to sidestep MCP licensing. + +Build 13w02b-7.7.0.500-snapshot15: + LexManos: Bump major and minor version numbers to mark 1.5, it's gunna break everything. Should be a compileable 1.5 build. + +Build 1.4.7-6.6.0.499: + LexManos: + Update FML: + New scripts for signing jars, and repackging source folders. + Fix LanguageRegistry loading files in UTF-8 format. loadLocalization should work for non-xml in all languages now (assumes UTF-8) + Fix incorrect end length calculation. Closes #161 Thanks BStramke! + LexManos: Fix check in getItem() to allow lowest item ID #361 + +Build 1.4.7-6.6.0.497: + LexManos: Added getter for Metadata smelting list, because, why not.. PR: #352 + LexManos: Fixed incorrect lighting in some cases. Closes issue #349 + LexManos: + Added event hooks to control to allow mod control of mob spawning. PR: #337 + Deprecated LivingSpecialSpawnEvent in favor of new LivingSpawnEvent.SpecialSpawn + +Build 1.4.7-6.6.0.496: + LexManos: Fix issue where dungeon loot table had wrong values. + LexManos: Fixed issue where ChunkPriderEvent.InitNoiseField used the wrong sizeY value. + LexManos: Some small code cleanups. + +Build 1.4.7-6.6.0.495: + Christian: + Update FML:6f1b762 + 6f1b762 Move server stopped *after* the server has actually stopped. *sigh* + +Build 1.4.7-6.6.0.494: + Christian: + Update FML:d9bfb29 + d9bfb29 Add in a "server stopped" event + +Build 1.4.7-6.6.0.493: + Christian: + Attempt to resolve the entity concurrency issue, by simply deferring unload + to the next tick + +Build 1.4.7-6.6.0.492: + Christian: Fix noisy exception logging + Christian: + Update FML:6fc7bc4 + 6fc7bc4 Add in some classloader debugging information: use fml.debugClassLoading=true as a system property to track down prob + +Build 1.4.7-6.6.0.491: + Christian: + Fix a missed patch and cleaned up other patches + Rollback a method name change that breaks a lot of mods + Update FML: fb701cd + fb701cd Revert MCP name change for canConnectRedstone - it conflicts with a forge method of the same name and breaks 1 + +Build 1.4.7-6.6.0.490: + Christian: + Update for MC 1.4.7 + Update FML: f7cc50b + +Build 1.4.6-6.5.0.489: + LexManos: Attempt a fix for the new chunk compression changes. + +Build 1.4.6-6.5.0.488: + Christian: + Update FML:1a232cf + 1a232cf Fix multiple GUI containers for ML containers. Sorry ultimatechest that this fix took so long, a bug report at + 853f54b Log if there's a problem reading the class bytes + +Build 1.4.6-6.5.0.487: + LexManos: Fix mobs spawning on inverted slabs/stairs. + +Build 1.4.6-6.5.0.486: + LexManos: Use nanoTime instead of currentTimeMillis for potential performance increase. + LexManos: Fixed order <.< you saw nothing. + +Build 1.4.6-6.5.0.484: + LexManos: Fixed issue with Efficancy enchatment when connected to vanilla servers. + LexManos: Fixed EntityMinecard missed patch, Issue #338 + LexManos: Fixed typo in dungeon loot + +Build 1.4.6-6.5.0.483: + Uristqwerty: + Force parent ListenerListInsts to rebuild. + + Without this change, it is possible (and, in fact, nearly guaranteed) for lists to rebuild endlessly if a parent list is marked as needing a rebuild but never actually read. This change forces the parent list(s) to rebuild as well, resulting in a significant performance increase and smoother framerate due to greatly reduced GC activity. + Christian: Protect deflation with a simple semaphore. Should close #336 + +Build 1.4.6-6.5.0.482: + LexManos: Update FML: Fix NPE in fingerprint loading, and pass expectged fingerprint to FMLFingerprintViolationEvent + +Build 1.4.6-6.5.0.481: + Christian: + Update FML: 7e6456d + 7e6456d Fix a message delivery issue in IMC + 664ebda Some tweaks for signing and ID matching + +Build 1.4.6-6.5.0.480: + LexManos: + Fixes a vanilla bug where the player view would dip when stepping between certain blocks + https://mojang.atlassian.net/browse/MC-1594 + Issue #318, let me know if you notice any issue. + +Build 1.4.6-6.5.0.479: + LexManos: Fixed parameter ordering u.u + +Build 1.4.6-6.5.0.478: + LexManos: + Re-write/Deprecated DungeonHooks loot tables, now uses ChestGenHooks like the rest of the world gen. Also fixes issue #330 by adding in enchanted books. + + Should be API compatible. + +Build 1.4.6-6.5.0.477: + LexManos: + Move chunk compression to the network thread in Packet 51 and 56 + + This will reduce the server load considerably by doing the chunk data compression in writePacketData, which will be run from the network thread. + + The chunk compression can easily use 1/4th of the overall server thread CPU time if someone is exploring much, especially when moving quickly (e.g. with quantum leggings). + + Player, this is how it's properly done. + +Build 1.4.6-6.5.0.476: + LexManos: Fix missed patch in EntityMinecart, #334 + LexManos: Explicitly check if useItem is not denied, allows for denying the item without denying the block + +Build 1.4.6-6.5.0.475: + LexManos: Delete unneeded patch. + +Build 1.4.6-6.5.0.474: + Christian: Some access transformations to allow mystcraft to work again. Closes #331 + +Build 1.4.6-6.5.0.473: + Christian: Fix Fireworks to always work in SMP + +Build 1.4.6-6.5.0.472: + Christian: + Fix up enchantment at the enchanting table vs via a book. Adds in a method + that previously exists under a new name: canApplyAtEnchantingTable() + to determine enchantments that can apply at the enchanting table (a smaller + subset of all possible enchantments for an item, now). Also, add your + enchantments to the anvil book application list, if neccessary. + +Build 1.4.6-6.5.0.471: + Christian: Tweak packet56 to see if this resolves the apparent worldgen derpiness + +Build 1.4.6-6.5.0.470: + Christian: + Server side only item callback: allow a held item to decide if it wants to pass sneak-clicks through + to a block, or not. Defaults false- the same as the new vanilla behaviour (sneak clicks with an item + in hand don't activateBlock anymore). + +Build 1.4.6-6.5.0.469: + Christian: Move another patch up a bit - should actually close #329 + +Build 1.4.6-6.5.0.468: + Christian: Add IPlantable to itemseedfood. Potato and carrot support! + +Build 1.4.6-6.5.0.467: + LexManos: + Update FML: + Fixed issue with users who don't have the JDK installed in there path + MCP will now output bfusicated files with windows reserved names to _name.class and FML will prioritize those names. + Fixed placement of onConnectionClosed callback + LexManos: Updated NetClientHandler for onConnectionClosed placement fix. + LexManos: Fixed cpw's derp in the PlayerInteractEvent logic. + +Build 1.4.6-6.5.0.466: + Christian: Fix ItemInWorldManager so that itemUseFirst works, and the playerinteractevent works. Minor patching mis hit. Apologies. + +Build 1.4.6-6.5.0.465: + Christian: OK. AT the right thing, and add in a call to always get the right thing. Clean up patch fuzz too. + +Build 1.4.6-6.5.0.464: + Christian: Access Transform a couple of methods + +Build 1.4.6-6.5.0.463: + LexManos: Fixe BiomeDecorator AT entry. + +Build 1.4.6-6.5.0.462: + Christian: Drop the item in onBlockHarvested, not breakBlock + +Build 1.4.6-6.5.0.461: + Christian: Fix up block drops for skulls and cocoa + +Build 1.4.6-6.5.0.460: + Christian: And fix up the other equals + +Build 1.4.6-6.5.0.459: + Christian: Fix comparing ItemStack tags for equality + +Build 1.4.6-6.5.0.458: + Christian: + Update FML: 40e57a2 + 40e57a2 Update MCP to newer version Fix fingerprint fire + +Build 1.4.6-6.5.0.457: + Christian: + Fix accidentally removed not-deprecated methods. + + Update FML: d604e44 + d604e44 InterModComms now supports a runtime polling based model for inter-mod comms at runtime. Deprecate method that shouldn't be used. COPY it's content to your mod. Don't CALL it. + 8b7778c Don't be as alarming about item overwrites. + +Build 1.4.6-6.5.0.456: + Christian: Fix binding the texture for multiple render passes. Thanks mdiyo! Closes #320 + +Build 1.4.6-6.5.0.455: + Christian: Allow RenderItem to be easily overridden for things that need to render entityitems. IronChest, BuildCraft, RP2, whatever... + +Build 1.4.6-6.5.0.454: + LexManos: Fixed items dieing improperly due to new EntityItem sync changes, also made items render offset when rendered in 3d. + +Build 1.4.6-6.5.0.453: + Christian: Fix RenderItem so that forge textures load for it + +Build 1.4.6-6.5.0.452: + LexManos: Removed all functions marked as deperacted for the new MC version + LexManos: + Updated FML: + Fixes startclient/startserver + + Added configuration file which allows modids to ignore ID validation checking. IT WILL CRASH YOUR GAME in 99.999% of cases. + + Immibis is a whingy ass. And TinyTimRob too. Now STFU and GTFO. closes fml/#510 for ever. + +Build 1.4.6-6.5.0.451: + LexManos: Inital update to 1.4.6, Version bumped to 6.5 + LexManos: Added jar signing to forge, we sign cpw/* and net/minecraftforge/* + LexManos: Try and print error while signing jar + +Build 1.4.5-6.4.2.448: + Christian: + Update FML: e98c311 + e98c311 Fix up handling null names. *sigh* + +Build 1.4.5-6.4.2.447: + Christian: + Update FML: 293edb3 + 293edb3 Some tweaks to item identification. The GameRegistry methods are deprecated to encourage you to use the new named ones instead. These will force a name on the item/block, allowing for stronger matching t + 9266ff3 Updated MCP download mirriors upon Searge's request. + 31695d5 Fix var name messup + bfb3020 Update released eclipse project to link BouncyCastle + 22a88ea Change ID management slightly. IDs are tracked by block type for itemblock items now. This means servers will need to update. Also, ordinal rearrangements within a mod will no longer trigger server disco + +Build 1.4.5-6.4.2.446: + LexManos: Make PlaySoundAtEntityEvent fire for players as well + LexManos: Remove erronious double call to PlayerDestroyItemEvent + +Build 1.4.5-6.4.2.445: + LexManos: Update FML to fix a typo + +Build 1.4.5-6.4.2.444: + LexManos: Automatically resolved imports. + LexManos: Fixup workspace for BC replacement + LexManos: Manual import fixes + LexManos: + Update FML: + Minecraft is now decompiled into sane package names. + Got rid of the src/common folder as the only folder that exists is src/mincraft, because the client and server codebase is merged. + ID Map generation/validation fixes + LexManos: Updated python scripts for removal of common folder + LexManos: Update patches for repackage. + LexManos: Update AT for repackage + LexManos: Update FML: Fixed the eclipse workspace to reference BouncyCastle library. + +Build 1.4.5-6.4.2.443: + LexManos: Bump version to 6.4.2 to mark the merge of TerrainGen branch. + +Build 1.4.5-6.4.1.442: + Christian: + Added terrain gen events + Added biome color events for @XCompWiz + Christian: Removed unchanged file + Christian: Readded unchanged version + Christian: For @XCompWiz, added a hook to allow mods to dynamically change the color that water is rendered. + Christian: Fix RenderBlocks patch, touch branch + +Build 1.4.5-6.4.1.441: + LexManos: + Update FML: + 2f34290e: Fix possible escape leakage.. + 83deece6: Change ID management slightly. IDs are tracked by block type for ItemBlock items now. This means servers will need to update. + + Also, ordinal rearrangements within a mod will no longer trigger server disconnection, though a warning will still be logged. + LexManos: Derp, imported the repackaged names not old names. + +Build 1.4.5-6.4.1.439: + LexManos: Update readme to reflect the fact that we now download MCP. + +Build 1.4.5-6.4.1.438: + LexManos: Fix ForgeDirection.ROTATION_MATRIX for issue #313 + LexManos: Made GuiContainer.drawSlotInventory overrideable for issue #312 + LexManos: Made BlockButton.func_82535_o overrideable for issue #311 + LexManos: Moved check if map cursor should 'spin' and which world a player respawns in to WorldProvider for PR #308 + LexManos: Add .DS_Store to the gitignore for mac users + LexManos: Add CloudRenderer for PR #304 + LexManos: New TileEntity function to determine if the TE should be destroied when Block/Meta changes, For Issue #300 + LexManos: Pistons now respect world height a little better, for PR #286, will review Rotation event later. + LexManos: Creative GUI will now remember what tab page you were on, thanks Matchlighter PR #290 + LexManos: Fix type in ForgeChunkManager.ticketCountAvaILableFor, thanks iChun PR: #285 + LexManos: Fixes crash when mods add TreeMaps to the Configuration map, thanks AtomicStryker, PR: #282 + LexManos: Fix shouldRiderSit() to properly determine if rider is sitting. + LexManos: Expose BiomeDecorator fields for custom Biome information, Issue: #239 + LexManos: Make BlockButton.sensible protected and non-final + +Build 1.4.5-6.4.1.437: + LexManos: Fix for FML Fixes eclipse workspace, now sets execution bits on astyle-osx, and mcp .sh files. Also now kills install if astyle is not found. + +Build 1.4.5-6.4.1.436: + LexManos: Fixed release -skipchangelog + LexManos: Fixed install --mcp-dir + LexManos: + Updated FML to 486: + 02b54ca8: Add a modid on the mods list, should make it easier to do things like forge chunkloading config + 70670f2f: Fix build eclipse extractor task + b9fa3fc9: Add in storage, detection and validation of the ItemID array between client and server + 5e5d8206: Fixing id map generation - should validate correctly now + f9fc06a8: Remade python dist as 32-bit. + 93d47a1c: Reenabled replacement of the eclipse folder. + +Build 1.4.5-6.4.1.435: + LexManos: And finally, fix up the release install script to have a parameter to specity the MCP directory. + +Build 1.4.5-6.4.1.434: + LexManos: Fix Forge install script to use python shipped with FML. + +Build 1.4.5-6.4.1.433: + LexManos: Push didn't get all of eclipse.... + +Build 1.4.5-6.4.1.432: + LexManos: + Cleaned up eclipse workspace and moved it to a zip file. + Setup will extract it if it doesn't already exist. + +Build 430: + Christian: Fix release script for new forge job name. Add in skip changelog option for local builds + +Build 1.4.5-6.4.1.426: + LexManos: Remove MCP from released src distro.. whops. + +Build 1.4.5-6.4.1.425: + Christian: + Fix static method, closes #271 + Don't spam the log if a mod requests a ticket beyond their maximum. A single message is fine. + +Build 1.4.5-6.4.1.424: + GuntherDW: Fix typo in chunkmanager config + Christian: fix List configs + Christian: Add Chunk Watch and UnWatch events. + +Build 1.4.5-6.4.1.414: + Christian: + Tweak release.py script: HEAD==master in general + + Update FML: 26a2ef5 + 26a2ef5 Add a modid on the mods list, should make it easier to do things like fo + b4e3490 Fix build eclipse extractor task + 828341f Fix typo + 7a8dae5 Try and make branch non-derpy + d3c0e1f Try defaulting branch differently + 9c77d3f Remove old eclipse workspace and ship/extract as a zip file (use ant set + 6371e9b Assume Forge is the parent directory when checking for AT configs. + 516954e Name both zips the same format + 1151d5c Last part of branch name only please + 25f1dda Try and get a valid branch name on jenkins + 39a146f Clean up build.xml script- support outputting a branched jar file + 037dcae Small derp in install.py + 01d6da3 Try marking python as binary. + 8b26659 FML will now attempt to download MCP as part of the install process Now + 42b3e6a Windows Python distrabution created using py2exe, thanks Fesh0r for the + e709ab8 Marked more spots in gui/items bitmask as being free. + +Build 1.4.5-6.4.1.413: + LexManos: Add wget and unzip from GnuWin32 for use in the setup scripts. + LexManos: Update FML, now includes python, and will download MCP for you + LexManos: Update python files to add support for specifying MCP directory and FML downloading MCP on the fly. + LexManos: Fix issue with DimensionManager.shouldLoadSpawn + +Build 1.4.5-6.4.1.411: + Christian: Fix #289 + +Build 1.4.5-6.4.1.410: + Christian: + Add in some additional ticket loading callbacks for ChickenBones. Closes #284 + Add in a call to determine if there are possible chunktickets for a world. This should let + Mystcraft and other dynamic world generating mods check if they should immediately load + a world based on existing chunk tickets. + +Build 1.4.5-6.4.1.409: + LexManos: Fix issue where non-BlockContainer TEs would not be removed properly. + +Build 1.4.5-6.4.1.408: + LexManos: Fix logic issue in ForgeChunkManager.ticketCountAvaliableFor(username) PR + LexManos: Fix issue where worlds were potentially unloaded improperly on server shutdown. + +Build 1.4.5-6.4.1.407: + LexManos: Small change to fix loading configs. + +Build 1.4.5-6.4.1.406: + LexManos: Added section of the EntityData NBT that will be persisted for players across respawning. + +Build 1.4.5-6.4.1.405: + LexManos: Exposed some ChunkLoader information for PR #278 + LexManos: Fix potential NPE in EntityJoin handler and print warning. + +Build 1.4.5-6.4.1.404: + LexManos: Small tweak to config to use Treemap + +Build 1.4.5-6.4.1.403: + xcompwiz: + Adds a more intelligent chunk constructor + + Adds a chunk constructor with full block id range, that's metadata + sensitive, has intelligent coord ordering, and which allows for + generation at greater heights than 127. + xcompwiz: Fixes some weird formatting + zach: + Fixes ordering for z & x loops (proper array increment order) + + The ordering before would skip about in the ids and metadata arrays. This runs linearly and should improve performance. + Done live on github + +Build 1.4.5-6.4.1.402: + LexManos: Fixed AIOOB issue with new sanity check in getBlock + +Build 1.4.5-6.4.1.401: + LexManos: Fix potential NPE in saving a property that didn't define a type. + +Build 1.4.5-6.4.1.400: + LexManos: + Added new functions to the Config class to allow for specification of comments when getting properties. + Added new getTerrainBlock whihc will limit the resuling ID to < 256, useful for world gen. + Calls to getBlock with IDs less then 256 will be assigned values above 256 {Thus freeing up terrain gen slots} + Made ConfigCategory implement Map should fix compatibility with most mods that broke two builds ago. + +Build 1.4.5-6.4.0.399: + xhamolk.class11: + OreDictionary addition: getOreID(ItemStack) + + Allow getting the oreID from a ItemStack, as an alternative from getOreID(String). + + Now is easier to exchange items for their equivalencies through the OreDictionary. + +Build 1.4.5-6.4.0.398: + LexManos: New nested configuration category support, for PR #258 + +Build 1.4.5-6.4.0.397: + LexManos: Fixed issue with abandoned chunks. + LexManos: Fixed random chest items not generating to there max stack sizes. + +Build 1.4.5-6.4.0.396: + ohai.iChun: + Add check that Entity saves to disk before saving entity to saved chunkloading data. + + Returning false to addEntityID prevents the entity from being saved (cred to LexManos) + Entities which do not save to disk but are chunkloaders causes errors the next time the world loads. This ought to fix it. + +Build 1.4.5-6.4.0.395: + LexManos: Updated FML, proper free-sprite list for /gui/items.png, and fixed MCP version. + +Build 1.4.5-6.4.0.394: + Christian: + Move server specific patch back to common from minecraft. + + Update FML: 1f5c58b + 1f5c58b Fix up MCP version + 61e4db2 Merge joined.exc add update howto + 5efc1eb Revert "Fix MC-2497 - derpy torch flames. Moved from forge. Everyone sho + 3b3600d Modified merger to just consider all server classes as common. And moved + edcc5ca Forgot mcp.cfg + ca79dfe Updated to 1.4.5b + 5945279 Fix python error + 57bf643 Modified decompile so that we do not have to decompile the server, saves + d9d0a46 Cleaned up some tabs + 2fac644 Change usage of ZipFile, fixes issues with Mac's default instation of py + +Build 1.4.5-6.4.0.393: + LexManos: Fix TE Issue + +Build 1.4.5-6.4.0.390: + LexManos: Removed GnuWin32 programs, should no longer be needed as we've moved to python. + LexManos: Updated to MC 1.4.5b + +Build 1.4.5-6.4.0.388: + Christian: Stupid eclipse resetting preferences. Spaces, not tabs!!! + Christian: + Update FML: 570592b + 570592b Attempt to fix a possible comodification risk + +Build 1.4.5-6.4.0.387: + Christian: Add in events when forcing and unforcing chunks. Hope this works for you ChickenBones! + +Build 1.4.5-6.4.0.386: + Christian: + Update FML: fde9414 + fde9414 Change texturebinding to use the textureId directly rather than iconInde + +Build 1.4.5-6.4.0.385: + LexManos: Fixed issue with default implementation of Beach plant type check + LexManos: Fixed custom soil checks for NetherStalk and Reeds + +Build 1.4.5-6.4.0.384: + LexManos: Release script will now include the Minecraft version in the arcive names. + +Build 6.4.0.383: + Christian: + Update FML: f348496 + f348496 Fix mod display list. Shouldn't be derpy anymore. + a5c31b5 Fix World patch- workaround no longer required and leftovers are bad. + 2dc3f0d Cleaned up the AT config updater, should work for any setup of the MCP w + +Build 6.4.0.382: + LexManos: Fixed beds not working properly when respawning. + +Build 6.4.0.381: + Christian: + Remove EntityFX patch - moved to FML. Patch SuspiciousClasses to add "forge" + + Update FML: fa56701 + fa56701 Fix MC-2497 - derpy torch flames. Moved from forge. Everyone should benefit. + 96935bb Fix an NPE in TileEntity trying to generate a crash report. Make suspicious classes just return the obvious. Fix NPE for FML crash report on server. Clean up dead pa + +Build 6.4.0.380: + Christian: Fix the derpy torch flames properly. Closes MC-2497 properly ;) + +Build 6.4.0.379: + Christian: + Update to MC 1.4.5 + Update FML: 43d3042 + 43d3042 Clean up a patch + fec221f Update FML for MC 1.4.5 + b0f0635 Fix for ModLoader static overrides not displaying. + 23a2513 Fix up derpy file name handling: closes #127 Fix up duping childmods: cl + a6eaa2b Fix spelling issue. + c6a0741 FML setup should now download and verify all the minecraft files needed + 5a1930e Small fix to some MCP metadata for pre2 + 418deba Update to MC 1.4.4 + 4ff2cff Fix bug when a modloader mod is run on a dedicated server and has a conn + +Build 6.3.0.378: + Christian: + Some liquid events. Non-API breaking. Add them at your leisure. This helps liquids know + what's happening to them. In case they're volatile or something ;) + +Build 6.3.0.377: + Christian: Another difference + +Build 6.3.0.376: + Christian: + Fix fillLiquidContainer - return null, not the empty container for + previous API compatibility + +Build 6.3.0.375: + LexManos: Update FML to fix ModLoader/addOverride functionality. + +Build 6.3.0.374: + kinglemming: + Fixed oversights in liquid registry, added functionality for instant checks as requested by CJ. + Liquid list return is now secure. + + Signed-off-by: King Lemming + Christian: Change name to LiquidContainerRegistry. Fix up missing API. This better be it now! + +Build 6.3.0.373: + kinglemming: + Liquid Manager Rewrite - slightly more memory usage, loads more efficient at runtime. + Added default Lava and Water registrations to Liquid Manager. + Removed method which relied on flawed assumption that a given liquid only had a single type of container. + + Signed-off-by: King Lemming + Christian: Rename some liquid stuff for more sensible naming. Tweak API slightly. + +Build 6.3.0.372: + Christian: + Add in the basic IBlockLiquid interface. The actual block implementation + will follow. + +Build 6.3.0.371: + Christian: + Add an ItemStack sensitive version of getIconForRenderPass, defers to + existing by default. Should allow NBT data to affect multipass icon rendering. + +Build 6.3.0.370: + Christian: Change getLeft to getRotation, around any axis. + +Build 6.3.0.369: + Christian: Some new stuff on the liquid API for better RP2 interaction. Coming soon: blocks! + +Build 6.3.0.367: + Christian: Tweak liquidcontainer API for sidedness capability + +Build 6.3.0.366: + LexManos: Updated FML, Fixed spelling issues in logs, and file name issues. + LexManos: Added saplings and leaves to the ore dict. PR: #242 + LexManos: Mods can use custom textures for Slot background overlay, instead of only items.png PR #245 and #246 + LexManos: Fix issue where players would spawn in the ground. + LexManos: Allow for modders to decide whether or not players are positioned on ridingEntities similarly to pigs PR #244 + LexManos: Fix breaking despite cancel in creative mode for PlayerInteractEvent OR #247 + +Build 6.3.0.364: + Christian: + As agreed, liquid API from BuildCraft has been migrated to minecraft forge. There will be cleanups to follow, + including sided handling and client rendering tweaks. Stay tuned! + Tweak forgedirection for a couple of naming constants + +Build 6.3.0.363: + Christian: Add toLeft rotational data to ForgeDirection + +Build 6.3.0.362: + LexManos: New field in ForgeDirection to hold just the valid directions. And made getOrientation a bit more efficient. + +Build 6.3.0.361: + LexManos: Fix entity items rendering on the ground. + LexManos: Fix crops not droping seeds properly. + +Build 6.3.0.360: + LexManos: Update to 1.4.4 + LexManos: Bumped version number for 1.4.4 + +Build 6.2.1.358: + LexManos: Ore Dictionary Improvements, replaces vanilla recipes with OreDict recipes for some vanilla items. Thanks Covert. + +Build 6.2.1.357: + LexManos: Made Item constructor public, and made setTextureFile chainable, requires mods to recompile, but as this is for 1.4.3 i'm not concerned. + +Build 6.2.1.356: + Christian: + Temporary update for 1.4.3 + Update FML: bd2123c + bd2123c Clean up some patch fuzz + c2a603c Update joined.exc file from latest conf + db12af4 Update to 1.4.3 + LexManos: + Readdaed teleporter sensitive versions of the teleport function + Added per-world list of custom teleporters, Modders, use World.Load to populate this list. + Changed the definition of our version schemes. + +Build 6.0.1.355: + Christian: + Update FML: 8356fe9 + 8356fe9 FUUUUUU! Stupid ticking. STOP REGISTERING TICK HANDLERS IN YOUR CONSTRUC + 6edce8b Patch a file handle leak in RegionFileCache handling when under memory p + ca2bbe0 Update MCP mapings again, yay bad syncs. + c8941a7 Updated MCP mapings. + 5e20c03 StartServer is now useable in merged code base. + +Build 6.0.1.354: + LexManos: Update FML: Updated MCP mapings, and fixed StartServer + +Build 6.0.1.353: + Christian: + Update FML: b19e882 + b19e882 Remove some debug, closes #123 + 9d7d32a Fix up tick management outside of mod loading phases for ModLoader mods. + d512539 Negatively cache failed class lookups, should help with @SideOnly performance issues. + +Build 6.0.1.351: + Christian: + This update fixes some world corrupting vanilla error handling, mostly caused by + mods doing something derpy. Hopefully, your world saves will thank me. + Note that if the mod does derp, it's data is lost. It's not FML or Minecraft Forge's + responsibility if "DirtChest 2000 Mk5" can't write their TileEntity method correctly + and you lose your 100000 diamonds. + + Update FML: a3a93f3 + a3a93f3 Fix some whitespace issues, handle possibly bugged entities as well + a7eb5dc Vanilla/mod bug fixes: CME on entity processing, TileEntity resetting chunk on save/load. + +Build 6.0.1.350: + LexManos: Fix cast issue when mods attempt to make fake worlds. + LexManos: Fix a vanilla bug related to certian seeds and stronholds. + LexManos: Cleanup some debug in the script, and fix version number for the current build. + +Build 6.0.1.349: + LexManos: Change logs should now be bundled with downloads, as well as avalible on files.minecraftforge.net + +Build 6.0.1.348: + Christian: + Update FML:b23081d + b23081d Support for ModLoader 1.4.2. Good job Risu! + 66db4ec Add in an exclusion list tag for @Mod. The backend code isn't yet implemented, but shows the basic idea. + +Build 6.0.1.345: + LexManos: EntityLiving.experianceValue private->public for Issue #225 + LexManos: Changeable name tag render distance for PR: 174 + LexManos: Remove some debug code + LexManos: New hook to allow items to be on multiple creative tabs PR 176 + LexManos: Fix issue where scroll bar would not render when switching tab pages. + LexManos: Added metadata sensitve experience to furnace recipies and added Item callback to determine experience gain. + LexManos: Exposed functions for adding superflat presets. + LexManos: New hook to allow for custom beacon support blocks. + CovertJaguar: + Added vanilla wood + dye to the Ore Dict + + Should help simplify interaction between mods that add similar items. + LexManos: Added Stonghold, Village, and Spawn biome management helpers for PR 207 + LexManos: Fix compile issue. + +Build 6.0.1.343: + csendek: Add event to cancel or change chat messages sent from server + csendek: Add event to cancel or change chat messages sent from server + +Build 6.0.1.342: + LexManos: Pickblock will new compare NBT data, should allow mods to refine there result better. + LexManos: Added system to place all configs that use Forge's Configuration function into a single file on disc. Optional config to enable this. Blame MattaBase for this idea.. + +Build 6.0.1.341: + LexManos: Fix ItemSeed placement to take into account the IPlantable interface. + +Build 6.0.1.339: + LexManos: Added a per-world MapStorage feature that provides a method to store data files associated with a specific world, as well as fixes the issue with villagers loosing there village. {Where villagers wouldn't go inside at night} + +Build 6.0.1.338: + pahimar: Update patches/common/net/minecraft/src/SlotCrafting.java.patch + Christian: + Fix the accessor and type on World.getPersistentChunksFor() + Update FML: 8bd98c3 + 8bd98c3 Fix a small problem with the new MCP container- it can cause NPEs. Nice. + 34cc42d Fix up some javadoc complaints + +Build 6.0.1.337: + Christian: + MCP information is now included in Minecraft Forge. They deserve the credit :) + + Update FML: 09eade4 + 09eade4 Update build - include MCP information in the source pack + 9bfe7df MCP deserves lots of credit. So here it is. + +Build 6.0.1.332: + Christian: + Update FML: 8006b77 + 8006b77 Fix instantiation bug + 7cc91cf Simple InterMod comms. Send a message using FMLInterModComms.sendMessage(). Receive messages through an @IMCCallback + 24d7285 Update for MC 1.4.2 + cedf3d5 Duplicate Mod display screen. + +Build 6.0.1.331: + LexManos: Downgrade to FML 415, issue with new IMC system. + +Build 6.0.1.330: + LexManos: Update to 1.4.2, obf stayed the same, so only small revision. + +Build 6.0.0.329: + LexManos: Update World patch to fix map provider issue. + +Build 6.0.0.328: + Christian: + Add an access transform for Block.setBlockBounds - should help a lot of code that uses this. + + Update FML: d915f39 + d915f39 Fix typo in access transformer + 346691c Fix the merge for forge + 6dadc1d Fix up references to minecraftDir in obf code + 8a55f68 Update FML for Minecraft 1.4.1 + 5645fa5 First update to 1.4.1, patches need updating. + ff0f00f Add some null checks, and throw descriptive exception when SideTransformer prevents a class from loading. + +Build 6.0.0.327: + LexManos: Update to MC 1.4.1 and Forge 6.0.0 + +Build 5.0.0.326: + LexManos: Fix color issues with Dyed Leather armor. + +Build 5.0.0.325: + LexManos: Remove deprecated code. + LexManos: Cleanup mirrored things in ShapedOreRecipe to address issue 208 and issue 210 + LexManos: Fix up the setHandeled/setHandled for events, it is now a generalized setResult, the meaning of which is defined by each event. + +Build 5.0.0.324: + LexManos: Fix NPE issue when mods add null EntityFX's to be rendererd. + +Build 5.0.0.323: + Christian: + Update FML: 7a34246 + 7a34246 Ship a client only class so the merge works both sides. + +Build 5.0.0.322: + Christian: Fix install.py so it can be installed properly from src distribution + +Build 5.0.0.321: + Christian: + Update FML (entire change log since last by me): 62a6b52 + 62a6b52 Fix RenderRegistry render ID - now at 36 Fix SpriteMaps - they're running out fast! Switch to forge if you can! RenderBiped now has an armo + b845cde Fix up FML python script for forge + 2c36dfb Update to MCP pre 3. Fixes some weirdnesses with explosions. + acd880d Merge branch '1.4' + e6f57e5 Update for MCP release + b1de0fc Remove fuzz from patches for INetworkManager change + ad44619 Fix for new names INetworkManager and ITexturePack. I also provide refactoring scripts for both, for your use... + 3a94211 Add a script to ignore git complaining about the eclipse workspace changing - run when you first open the eclipse workspace + 9386e23 Update gitignore - ignore the files that will change or be deleted + 10b318c Add in "starter" image for eclipse workspace + 995d5b7 Eclipse workspace fixup 2? + bbb12c8 Clean up eclipse workspace- part 1 + b50058e Clean up a bit of patch fuzz + 4a0bfa9 Fix CommonHandler for rename of the server thread class + 4d1ec66 Update with RC2 MCP. Use the joined.exc file directly since MCP now provides it. + b52e3d0 Fix exception for CodecMus + a1011c9 Fix some compilation issues. Requires resolving the worldclient abstract method + 0ebd4f3 Inital patch update to 1.4 + 89c68c4 Moved into EntityVillager + e4702cb Fix line ending detection during checkout. + 6e64fd7 We don't need logging here... + 014b3f4 remove useless -Server projects + 7628c67 Updated the AT config and Marker config for 1.4 obf + 54a322c Updae build to copy files that may decompile differently but are actually the same, and updated for 1.4 values. + aadf396 Update MCP Merge config. + 81e1855 Pull in MCP's 1.4 conf files. + 5686fd4 Fix error in merging of exec's + +Build 5.0.0.320: + LexManos: FML Update for 1.4 + LexManos: Fix recompile call for 1.4 MCP change + LexManos: Update Forge's AT for 1.4 names. + LexManos: Update for new names in 1.4 + LexManos: Remove final from 'villageCollectionObj' to allow for delayed setup of Map source objects. + LexManos: Moved to common where it should be + LexManos: No longer needed, getRenderDistance removed because Vanilla has it now, TileEntity.func_82115_m + LexManos: Forge spawn protection removed, now a vanilla feature. + LexManos: Patches that applied with little to no functional changes. + LexManos: Updated Render patches, Bipeds now have the ability to have helmets, of either blocks, or the new 'heads' + LexManos: BlockSnow now pretty much just passes harvestBlock to it's super. + LexManos: Entities have a new function to determine explosion strength that they create, and implemented Item frame pickblock. + LexManos: Patches removing forge spawn protection, now a vanilla feature. + LexManos: BlockCrops is now the parent class of multiple types of crops, Wheat, Potatoes, and Carrots, updated getBlockDropped patch to reflect. + LexManos: Removed Forge's TileEntity.getRenderDistance, now a vanilla feature: TileEntity.func_82115_m + LexManos: Teleporting has a new function (func_82448_a), made it so that you can supply your own teleporter to that function, and so it works with dimension movement factors. + LexManos: Updated World patch, there are a lot of new things happening int he constructor, xcomp should probably vet this. + LexManos: Updated Forge version to 5.0.0, for 1.4 + LexManos: Update release script for mcp changes, releases now build. + +Build 4.3.5.318: + LexManos: Remove some test code. + LexManos: Bump version to 4.3, final for 1.3.2 + +Build 4.2.5.317: + LexManos: Added ability for mods to cleanly define and display new creative tabs. + +Build 4.2.5.316: + Christian: Fix classloading issue preventing JRockit from running forge + +Build 4.2.5.315: + Christian: + Forge build change: the universal jar, if installed alongside a server jar file, can be executed to load forge. No server side merging required! + Update FML: 989ab3e + 989ab3e Update build.xml - add a classpath to the manifest. This means the universal jar is now a server side launche + 88f1dc9 Typos! + +Build 4.2.5.314: + Christian: + Update FML: 470a185 + 470a185 Try and avoid an NPE in crash reports + 0029518 Fix logging problems- log death messages and re-route the server through FML logs properly. + fe7a832 Fix the test mod + a2bc30b Coremods can be specified via the command line: fml.coreMod.load= This will help with developing coremods + bae1f74 Fix classpath for server + 887aa27 Add in the ability for a client to throw a custom exception that displays a custom gui instead of the default error message. + e17f267 Update FML internal classpath. Helpful for coremod devs + 3b9972a Don't use File to separate the last element of the path. It's a URL, they're always separated by '/' + 5c96afe Changed RelauchLibraryManager so that files with different paths on the same baseURL can be implemented in one ILibrarySet. + 1bca393 FML as a whole is now subject to transformers. + 27cf731 Bonus extra character. thanks randomitter! + 94c84cd Merge pull request #116 from Vazkii/patch-1 + c2d3195 Add Null check to FMLClientHandler.sendPacket + +Build 4.2.5.313: + LexManos: Make Item.createEntity only call when its specifically a EntityItem, not a subclass of it. + +Build 4.2.5.312: + LexManos: New Block hook to determine if it can be destroied by the ender dragon, for PR 199 + LexManos: Ship forgeversion.properties with release zips. Same format as fmlversion.properties. + LexManos: Dll files are binary as well. + +Build 4.2.5.311: + LexManos: Fill out the .gitattributes to help with line endings how they should be. + LexManos: Change the Crafting damage check to be the same as the usage damage check. (>= -> >) + LexManos: Allow hook into GuiSlot for background rendering for PR #203 + +Build 4.2.5.310: + Christian: Reorganize the forced chunks a bit- offload the cost of immutable map building to the mods, rather than the chunk tick + +Build 4.2.5.307: + Christian: Remove @SideOnly from removePotionEffect. Hi RichardG! + +Build 4.2.5.306: + LexManos: Add some accessors to teh ChunkLoader tickets. + +Build 4.2.5.305: + ohai.iChun: Fix not passing right render pass to Item class. + +Build 4.2.5.303: + Christian: Fix bounds checking on chunkcache. Should fix a bunch of rp2 and maybe other extended tile entity code + +Build 4.2.5.302: + Christian: + Use weak references to the worlds in our maps. WorldClient would otherwise + leak all over the show. + +Build 4.2.5.299: + mehvids: Add some of the model subsystem to the server. The part that doesn't require openGL. This allows for systems that dual models as collision/selection boxes etc. + xcompwiz: + Improves DimensionManager + + Adds handling for unloading and hotloading of worlds, fixes some typos, + allows for dimensions to be unregistered (allowing save specific + dimension registrations), general changes to match these features. + xcompwiz: + Adds world unloading and hotloading calls + + Adds world unloaded message to MinecraftServer on save. + Adds world unloading calls to chunk provider/manager when all chunks are + unloaded. + Adds call in MinecraftServer getWorld to hotload world if it isn't + loaded. + xcompwiz: + MapStorage Fix + + Fixes setting and timing of map storage object to allow for the + WorldProvider to use it during initialization + Forces single instance of map storage object (per side) + Moves setting of spawn to after provider setup + xcompwiz: + Lighting Time fix + + score_under's lighting fix that limits and fairly distributes the amount + of time spent on recalculating lighting + xcompwiz: + Server player concurrency fix + + Fixes an issue where the server can move a player while the player is + moving, process the player's last move (putting the player back where + they were before the teleport), and then complain about the player + moving too fast when the client catches up to it's new position. Also + fixes this issue while riding an entity. Only affects player + client/server movement sync. + Christian: + Remove dead WorldInfo patch. Tweak dimension code a bit for better naming, and use the new FML world loading facilities + Update FML: d0e7c9e + d0e7c9e Update patches *sigh* + f3e1cac Add in a savehandler strategy for reading and writing data to the world save. This service is only available to coremods via the WorldAccessConta + 51fb513 Add in some bukkit supporting code. Most of this is unimplemented until the bukkit coremod is complete. + 65c9fdd New stuff on the ModLoader! Risu has been busy. Closes #114 + c1d4458 Mods can now declare a range of minecraft versions they will run against + Christian: Update forge to 4.2 + +Build 4.1.4.298: + LexManos: Fix issue where light would not properly recalculate. + LexManos: Fix issue where mushrooms would not check the proper soil block. + +Build 4.1.4.297: + LexManos: Expanded DungeonHooks to allow for adding of custom DungeonLoot values directly, allowing for better control over the generated items. + +Build 4.1.4.296: + LexManos: Made PlayerEvent.BreakSpeed fire when a player cannot harvest the block. Issues #191 and #188 + +Build 4.1.4.295: + Christian: Dormant chunk cache might actually work now, and not mix chunks across worlds + Christian: + Update FML: ca1ca4f + ca1ca4f Fix maps supporting greater than byte() dimension sizing + 15ee8bf Fix language registry additions, closes #113 + a08b5b1 Merge pull request #112 from pahimar/master + 8dac58f Added ability to query the Language Registry by key and language for specific localized text, as well as loading in localization text f + +Build 4.1.4.294: + LexManos: Fix buckets, need to rethink for bukkit compatibility. + LexManos: Fix vanilla bug where the player would load chunks outside its range that would be 'abandoned' and never unloaded. + LexManos: Forgot comment, you see nothing... + +Build 4.1.4.292: + Christian: + A few requested features of ForgeChunkManager. Mods can specify a + chunkloading config directly in the config file, including chunk + loading overrides if they wish (and the config allows them). + Also added "player" tied tickets that bind to the player and not the + mod's quota. + +Build 4.1.4.291: + LexManos: Missing updates from last commit + LexManos: Location aware version og Block.lightOpacity for PR #169 + +Build 4.1.4.290: + LexManos: Fix bug in last commit that caused block to not break. + LexManos: Added preliminarty Player Interact event heavily based on the bukkit event. + +Build 4.1.4.289: + LexManos: Add PlayerEvent.HarvestCheck and PlayerEvent.BreakSpeed for dealing with things related to a player harvesting a block. + +Build 4.1.4.288: + LexManos: Fix bug where breaking texture would not apply to top/bottom of beds. + +Build 4.1.4.287: + Christian: Add in an "EntityEvent.EnteringChunk" event. Useful for your entity chunkloading stuff. + +Build 4.1.4.286: + LexManos: Support for no BOM. + +Build 4.1.4.285: + Christian: + Update FML: f083707 + f083707 Extreme headless mode is back! + +Build 4.1.4.284: + Christian: + Update FML: dd39ae5 + dd7502a Fix parent child counts showing properly. Closes #107 thanks scott! + b36d447 It's useMetadata, not usesMetadata. thanks myrathi and psx. closes #110 + efb1066 Fix random shuffling when manipulating biomes by using a LinkedHashSet to preserve iteration order. Closes #111 + Christian: + Some more tweaks to the chunkloading code. The world.load event fires slightly later- once the entity watcher is + set up, so entities can actually load into the server world. Also, tickets actually save and load properly + and null entities don't break the server + +Build 4.1.4.282: + LexManos: > != >= + +Build 4.1.4.281: + LexManos: Fix Configuration.getItem to return pre-shifted values suitible to pass into Item constructors. + +Build 4.1.4.280: + LexManos: Fire off PlayerDestroyItemEvent for crafting contianer items that get damaged to much. PR #183 + +Build 4.1.4.279: + LexManos: Configuration will now attempt to detect the encoding of the file using the Byte Order Mark. + LexManos: + Changed Configuration to use overloaded methods, and changed the order of arguments to be Category, Key, Value instead of Key, Category, Value to hopefully help cleanup some peopels code. + Added function to get a free Item id. Will only accept values that are not in the block space. Needs testing. + Marked all the old getOrCreate* functions as deprecated. + +Build 4.1.4.278: + Christian: Fix some errors if the config is unparseable. It should log an exception and carry on with defaults. + Christian: Support quoting in property and category names for almost all possible characters allowed + Christian: Fix up some config file handling to be even more resilient. + +Build 4.1.4.277: + Christian: + More modifications to the ticket callback handling system. There are up to two callbacks during world loading now. One to allow + selective preference for ticket types. The other to actually allow the mod to force chunks. + +Build 4.1.4.276: + Christian: + Update FML: dd39ae5 + dd39ae5 Try and fix the newline capture so consoles show on the server on windows again + b39f808 Readd ancient searge name so dan200 and computercraft can run again. REMOVE THAT CODE DAN. + Christian: + Some changes to the ForgeChunkManager. + Null modData is allowed now. + The entity id is actually properly persisted in the ticket now. + There is a new "orderedLoadingCallback" that allows you to provide a preferred ticket loading order in case of "excess tickets". Also, tickets + that are not in the returned list are now unregistered. + There is a way to resort the chunks in the forced chunklist on a ticket now. + Log the dormant cache configuration + +Build 4.1.4.275: + Christian: Simple chunkloading implementation + Christian: Working cross dimensional implementation of chunkloading for Forge. + Christian: + A lot of tweaks to the chunkloading for entity behaviour. Entities are now bound by a new + persistent id they *all* have, on the server side. + Christian: Remove @SideOnly flag for function now required on the server + Christian: Fix NPE in ForgeChunkManager + Christian: And a concurrentmodificationexception in the same code + Christian: + Simple chunk caching capability for the chunkloader. This will store "dormant" chunks in a + configurable cache, potentially saving the cost of reloading them from disk. + Christian: Delete some debug code + Christian: Some more fixes for chunkloading code. Works very reliably now. + Christian: + Update FML: a2c059e + a2c059e Fix missing import. Thanks ichun :( + 19316a0 Version file searching should work for directories too + fbc7a5c Fix bug causing NPE if non-whitelisted player joins an FML server without FML installed + e9cfd10 Merge pull request #103 from iChun/patch-2 + 1424883 Fixed ModTextureAnimation not updating and not binding to correct image. + +Build 4.1.4.274: + mitchpetrie29: + Update patches/common/net/minecraft/src/WorldProvider.java.patch + + Fixed WorldProvider.setDimension() setting the wrong variable. + LexManos: Fix patch errors in merge of last PR -.- + +Build 4.1.4.272: + LexManos: Fix accedental doubling of shift, Fixes saplings/flowers planting a space above where they should + +Build 4.1.4.271: + LexManos: New Plant API that allows for custom plants/soils. + +Build 4.1.3.270: + LexManos: Added new hooks for modifying the items generated in chests during world gen. + +Build 4.1.2.269: + LexManos: Redirect a lot of functions through WorldProvider for Mystcraft, allowing them to be overriden by the provider. + +Build 4.1.2.268: + CovertJaguar: Fixed Entity Item render helper + +Build 4.1.2.267: + ohai.iChun: Fix pick block key giving invalid spawn eggs + ohai.iChun: Logic derped + ohai.iChun: Logic derp (again) + +Build 4.1.2.266: + LexManos: Added side sensitivity to standard EntityDiggingFX, added Block functions to override spawning of digging and breaking effects. + +Build 4.1.2.265: + LexManos: Fix potential NPE in Custom item entity span code caused by item id misconfigurations. + +Build 4.1.2.264: + LexManos: Fix recursion issue with new special item entity code. + +Build 4.1.2.263: + Christian: + Update FML: 6c746ec + 6c746ec Tidy code + aacbfeb Change version.properties search slightly, allow access to found file from the preinit event + 1513b36 Add in the capability to read an internal version as .version from a file in the zip call versi + 35852a6 Fix up reversed assignment for version fallback + +Build 4.1.2.261: + pahimar: Changes to how PotionEffects are removed, now each PotionEffect can specify which ItemStacks can remove it's effect + pahimar: Inverted logic derp + +Build 4.1.2.260: + LexManos: Package all of paulscode/ with the universal jar to help mac users who cant understand how to merge folders -.- + +Build 4.1.2.259: + LexManos: Bump version to 4.1.2 to mark the end of todays changes. + +Build 4.1.1.258: + LexManos: Fix potential issue with custom events where the constructor is not visible from the EventBus class, Should never arise but meh. + LexManos: Read/Write config files as UTF-8 instead of ANSII, should fix issue with Turkish people. + LexManos: Allow for respawning in different dimensions. + LexManos: Move spawn fuzz to WorldProvider/WorldType, useful for VoidWorld types. + +Build 4.1.1.257: + LexManos: Make EntityJoinWorldEvent Cancelable properly + LexManos: Move Forge init message to MinecraftForge.initalize + LexManos: Add ability for Items to create custom Entities for themselves when added to the world, PR: #151 + +Build 4.1.1.256: + admin: Allow flight,player sensitive + +Build 4.1.1.255: + LexManos: Fix a few patch fuzzes + LexManos: Implemented isBlockFoliage for pull #141 + +Build 4.1.1.254: + LexManos: Clean up some javadoc warnings. + LexManos: + New EntityItem related events + Fixed player death event in SMP + Added Player specific drops event + Added generic EntityJoinWorldEvent + +Build 4.1.1.253: + LexManos: Fix FillBucketEvent to work with stacked buckets. New change in 1.3 + LexManos: EntityLiving variation of drawBlockDamageTexture to allow for Non-player viewports. + +Build 4.1.1.252: + Christian: Remove all references to ModLoader + Christian: + Update FML: 89b8236 + 89b8236 Fix onConnectionClosed not being called on the client side of a connection + +Build 4.1.1.251: + LexManos: Bump version to 4.1.1 + +Build 4.0.0.250: + Christian: + Update FML: 290a3c9 + 290a3c9 Merge pull request #94 from iChun/patch-1 + 9485dc5 Fix handleTinyPacket using short instead of int. + Christian: + Update FML: 70f55c5 + 70f55c5 Add in exclusion list for IFMLLoadingPlugin. + 1c1716d Remove debug cruft + d567f79 To properly align with packet9respawn, make packet1login's dimension an int as well + ecd4e46 Attempt to build some protocol negotiation, and fix packet1login so that the dimension is a short, matching packet9respawn + 16fe495 Compatibility level is now passed from server to client - and the client tracks it. This means certain packet changes can be made without b + 4f70d23 Fix dependency checking: you can depend on specific versions of FML + +Build 4.0.0.249: + Christian: + Update FML: e6abb69 + e6abb69 Fix up tiny packet handler to actually work + e862052 Allow javax to be shipped by mods. Should allow some more modloader mods to work unaltered + 4071ad1 Add in a little bit of protocol cleanup. Start work on allowing multiple protocol versions + 6061964 Give a way to build the packet131mapdata packet correctly populated + b818769 Capture and leverage Packet131MapData + +Build 4.0.0.248: + LexManos: Fix placing torches and the like on inverted woden slabs. + +Build 4.0.0.247: + Christian: + Update FML: 12bc4ba + 12bc4ba Make console logging pass through a single logging thread to avoid concurrency problems with launchers and stuff + 8fccfa2 Overlooked chat message support *sigh*. Fixes wierd mods that communicate through custom chat messages rather than + a697d04 Rescan mod packages where there was a possible mod identified to try and make sure we load it. Fixes Matmos r16 + +Build 4.0.0.246: + Christian: + Update FML: 9d812f1 + 9d812f1 And handle the other way to globally register an entity + 869cf78 Fix up mods trying to register entities outside of modloading. Now you'll get a big fat warning for doing such a de + 186680c Fix CJB mod compatibilty for real. Gui container registration can now happen in the constructor. YUK! + 5aed6d9 Fix compatibility with ModLoader dispenser hook. Fixes a bug with IDispenseHandler too - though it means that inter + 3d7a665 Fix headless operation, hopefully + +Build 4.0.0.245: + Christian: + Update FML: 10a7169 + + 10a7169 Fix up trying to re-add stuff to the classpath when it's already there + 0eb7180 Fix out of range entity id handling for ModLoader mods a bit more. Thanks Herobrine mod! + b1b4c61 Expose GuiMerchantButton + 359cfb5 Log a big fat warning for the developer in the case the network version is not acceptable to the mod itself. (This can happen because of a bad range specifier for example) + +Build 4.0.0.243: + Christian: + Update FML: 8656fd5 + 8656fd5 Also, make missing entity not blow things up + 25a4dcb Fix entity tracker "update" packet not computing correctly. Should work now.. + +Build 4.0.0.242: + Christian: + Update FML: c90a853 + c90a853 Fix up addRenderer to catch exceptions from the basemod, also, addrenderer now supplies a list of the default renderers from MC for editing and will note the + 18069d8 Change download location for FML libraries to files.minecraftforge.net, add an encoding param to the javac command line to force utf 8 + a40f4a7 Add in random jar/zip files to the classpath. UGH this is so fucking ugly it's not funny. + 5b6460b Use a null socket and try to prefer the result of getLocalHost in the broadcast data. + +Build 4.0.0.240: + Christian: + Update FML: c0d1348 + c0d1348 Add in an ItemRenderer null check so FML can run render adding mods + 482c163 Inverted boolean logic. Grrr. + 221d113 ModLoader mob spawns use packet 24- build a bypass system so that they can still use it + f19f426 Remove debug statements + +Build 4.0.0.239: + Christian: + Update FML: 9dd9b6e + 9dd9b6e Fix keybindings not loading properly from gamesettings file after restart + +Build 4.0.0.238: + LexManos: Fix silk touch on Ender Chests. + +Build 4.0.0.237: + t.tomkins: + Update patches/common/net/minecraft/src/NetServerHandler.java.patch + + Update patches/common/net/minecraft/src/NetServerHandler.java.patch + + Server mods can now use noClip to push players through solid blocks without is being an invalid move and resetting the players position. + + Useful for creating semi-solid blocks like quicksand. + +Build 4.0.0.236: + LexManos: Fix Issue #140: Custom items not properly having texture applied for partical effects. + +Build 4.0.0.235: + Christian: + Update FML: acb0b21 + acb0b21 Fix so we always send received packets to handlers. Renders 250 filtering useless unless i can figure a way to intercept + +Build 4.0.0.234: + Christian: + Update FML: b17dd3c + b17dd3c Some tests + fa66ffa Fix trying to load the client side packet handler, when on the server, hopefully? + b106420 Fix up network negotiation - now it will disconnect with a nice error screen if there are missing mods on the client vs se + +Build 4.0.0.233: + Christian: + Update FML: c971adb + c971adb Fix missing addCommand call: thanks "spawnwolf test command" + d6326de Fix a couple of modloader mods. Thanks! + 483667c Some functionality fixes for @Instance injection. + 8bef512 Versions now have two flavours: the @Mod(version) which is the "programmatic version" and is used for all version relationship calculatio + 501009c Always for ML mods into "public" class accessibility - we don't call from the default package like ML does. + d3d4308 Add in a convenience method for getting a class instance based on existence of another Mod. Useful for soft dependencies. + +Build 4.0.0.232: + Christian: + Update FML: 2d9b88b + 2d9b88b And more mod sorting fixes. + 93d5934 Actually *use* the sorted mod list + +Build 4.0.0.231: + LexManos: Fix FillBucketEvent to actually fire. + +Build 4.0.0.230: + LexManos: Fix call to createTileEntity on blocks that extend BlockContainer. + +Build 4.0.0.229: + Christian: + Update FML: 180a279 + 180a279 Merge pull request #82 from Chicken-Bones/master + cf38461 The access transformer will now handle classes in packages. + 2c85539 Reverse the meaning of state in fml.modStates system property and fmlModState.properties - it was very derpy before. Now: true is enabled, false is disabled, as you would expect + d651189 Actually fix the corrupt JSON problem + f6a8cd5 Fix isModLoaded for "disabled" mods, and the toposort as well + 3bde961 A bit more information for dependency handling + 6396bea Fix up handing corrupt mcmod.info + 6bc6def Fix a problem with network ids + 7328610 Fix up version handling properly. Hopefully, and the error screen. + 9fcc452 Only active mods should have dependencies checked, and be sorted + 26302a6 Fix oddity with Screen, print a version out in the sorted list! + +Build 4.0.0.228: + Christian: + Update FML: 62dbfb3 + 62dbfb3 Fix metadata + +Build 4.0.0.227: + Christian: + Update FML: b91cbe9 + b91cbe9 Fix up versioned dependencies so they work a lot better, also add in a missing mods screen + +Build 4.0.0.226: + Christian: + Update FML: 93b8ba9 + 93b8ba9 Fix missing serverSendPacket + 23fdbbd Trading support for ModLoader - thanks Herblore! + d7a74d8 Close the jar, for cleanliness sake + 58e6dd9 Fix authors - it'll read both "authors" and "authorList" from the json now + 907cf2d More ML compatibility - fix up dragon mounts, thanks! + ee48a36 Fix up loading mods that are grandchildren of BaseMod + c6f362b Fix entity handling for ModLoader mods, thanks parachute mod! + +Build 4.0.0.225: + LexManos: Fix lighting issue for air related to 4096 fix. + +Build 4.0.0.224: + LexManos: Made helper hooks for EntityLiving and EntityRenderer hooks for Optifine + LexManos: Removed deprecated ISpawnHandler, that never worked in 1.3.2 so noone should be using it. See FML's replacement. + +Build 4.0.0.223: + Christian: + Update FML: 6e01c59 + 6e01c59 Merge ChickenBones pull into FML - adds player trackers + a0cbd37 More precise error handling when an invalid class is present + 12323e2 Fix textures not applying properly + 789a4a3 Fix up entity spawning - hopefully they won't warp anymore. + a87d045 Add in a helper on the server start event for adding commands to the server. + 82e9309 Move villager trading hook up a bit. thanks sengir. + 8deaa37 Fix LAN to try hard to find a real network interface, not just localhost most of the time + b5363e3 Update build to not bother building client jar. Universal is everything now. + +Build 4.0.0.222: + LexManos: Pickblock now replaces the currently selected item if it could not find a empty space. + +Build 4.0.0.221: + dvrabel: + Use original minecart drag co-efficients for regular carts. + + Since the amount of speed lost is 1 - co-eff, rounding 0.997 to 0.99 + makes a big difference to the distance a minecart will travel (less + than half of the distance in vanilla 1.25). + +Build 4.0.0.220: + LexManos: + Update FML to 304: + Client side only classes are properly annotated, and denied loading on server side + Added missing client side only ModLoader.getContainerGUI function + Guis work for FML mods now. + Fixed MLProp handeling of null info + Fix up dispenser handling, add in new params for the dispenser: breaks IDispenseHandler, sorry + Christian: + Update FML: 28a10ac + 28a10ac Null protection for ticks() -- probably should uses EnumSet.noneOf() but you can also use null now to stop ticking. closes #77 + c349d51 Automatic mod entity registration into the global entity list. This might break entity code out there, sorry, but this way for most entities you no longer need to manage the global mod entity stuff at all. just remove it. FML will take care of the rest (note, worlds won't load the old entities) + ef01745 Add in a utility function that *might* tell you the context you're running in on either client or server: FMLCommonHandler.getEffectiveSide + c97d6a6 Try and stop sendPacketToAllAround from being crashy + 2062273 Mods can add mod specific crash information to the crash report now Forge needs to implement MinecraftForge.getCrashCallable + 6e6436e Fix up dispenser handling, add in new params for the dispenser: breaks IDispenseHandler, sorry + 38f4a22 Fix up MLProp handling for null info + 3a8b047 GUIs working in FML for ML mods + 52483ee Support gui opening for Shelf mod + dce1cbc Updated MCPMerger to annotate unique classes with there sides, and SideTransformer to null out any class that is loaded on the wrong side. + +Build 4.0.0.217: + LexManos: Updated onItemUseFirst call to include the new hit vector information, and updated readme. + +Build 4.0.0.216: + LexManos: Added missing server side onBlockStartBreak hook, fixes Sheers. + +Build 4.0.0.215: + LexManos: Fixed Forge's 4096 block filler initalization. + +Build 4.0.0.214: + LexManos: Fix IndexOutOfBounds exception, Major derp. + +Build 4.0.0.213: + Christian: + Update FML: 46c563a + + 46c563a Expose more of the village construction parts for building village piece + 1380c2e Allow access to the type "ComponentVillage" + 71a3818 Documentation and registration for villager stuff + e3a343c Fix javadoc derp + 195b1a0 Villager trading, manipulation and village enhancement. Still WIP but sh + 69e66c3 Fix exception based logging to actually log the exception! + +Build 4.0.0.212: + Christian: + Update FML: + 885637c Fix up keyboard events for modloader + 90a7c8f Pickup notification + +Build 4.0.0.211: + LexManos: Changed order in which EntityItemPickupEvent is called, it will no longer be called if the 'delay' on the item is still active. Also EntityItems that are in the world with invalid item stacks will now kill themselves. + +Build 4.0.0.210: + mitchel.pyl: Adds a SkyProvider class that can handle the rendering of the sky + +Build 4.0.0.209: + Christian: + Move and add a few AT for forge: rail and leaves stuff mostly + Update FML (reorg some AT for FML vs forge): + 2171c0c Update fml_at with new transforms + 924a6f9 Fix derp where client sided packet handler would be created on a dedi server env + ad4cffb Add in support for "dummy" keybindings- ones that are added to the list but never do anything so the mod can handle it all themselves. + cf77ffb Don't complain about minecraft source code being in "net.minecraft.src". Derp. + b2fdcd7 Fix ModLoader add XP Smelting + 094ce2a Actually register client/server packetspecs as their correct sides! fixes #71 + +Build 4.0.0.208: + LexManos: Fix MC packet bugs for remote servers that use blocks with ids > 256 + +Build 4.0.0.207: + LexManos: Fixed bug in EntityMinecart that would cause them to fall through the ground at the bottom of slopes. + +Build 4.0.0.206: + Christian: + Update FML: + + e8cb2c1 Error if channel name is invalid - either too short, or too long + 9c6c56c Add a connect and read timeout for downloading libraries. This should really stop the "waiting forever" at startup screen. + 0d5affe GIANT FAT WARNINGS if you use any code in net.minecraft.src or any subpackage thereof. Get it out of there, now! + 13f210f Fix up ML GUI ticking. Thanks sharose! + +Build 4.0.0.205: + LexManos: Fixed EntityEvent.CanUpdate + LexManos: Fix EntityItemPickupEvent 'pop' sound spamming. + LexManos: Added timeout to MC's download of sound resouces. + LexManos: Update WorldProvider.path diff. + +Build 4.0.0.204: + Christian: + Update fml: + c61ad51 Organize ALL the imports + c0842b0 Expose the server in serverstart event + 2851079 Fix up directory injection of log file locations + 5197524 Refer to FMLLog, not FMLRelaunchLog + 78efd1a Tidy up server launch - reflection not required anymore + eee0a99 Also, log what the directory discoverer finds for mcmod.info + 10c96c3 And log the exception if it has a problem reading the jar file + 07cc3fb Fix jar loader failing to inject any metadata at all if mcmod.info is not found. + e31f143 Change install.cmd to install.bat, why, cuz people are .... Updated readme to mention needing server and client. + +Build 4.0.0.200: + LexManos: Allow white space in the property name. + Christian: + Update FML to include some ML compatibility fixes. Minimap should run, assuming he + recompiles against standard ML interfaces. + This updates to official MCP 7.2, so you'll need to rebuild your workspace (some + small but important patches to MCP went in) + +Build 4.0.0.199: + Christian: Update FML, make the .sh scripts executable + +Build 4.0.0.196: + LexManos: Update FML to 285 + +Build 4.0.0.194: + draake: Added additional sound events to allow manipulation of a sound source at its creation. + draake: Removed SoundSetListenerEvent implementation. + +Build 4.0.0.193: + LexManos: Fix potential index exception in ForgeDirection + LexManos: Whops + +Build 4.0.0.192: + LexManos: Rename Orientation to ForgeDirection {Damn MCP naming a class Direction already} + +Build 4.0.0.191: + LexManos: Update FML again for mod screen blending fix. + +Build 4.0.0.190: + LexManos: Updated Orientation with new helper functionality. + LexManos: Fix ItemBlock placement, should fix RP Deployers placing blocks 1 tile down. + LexManos: Seperated block placmenet logic in ItemBlock as immibis requested: https://github.com/MinecraftForge/MinecraftForge/pull/110 + LexManos: New Command event. + LexManos: Fix issue with default getContainerItemStack + LexManos: Add render distance property to TileEntity. + +Build 4.0.0.189: + LexManos: Updated FML, should fix the new included eclipse workspace. + +Build 4.0.0.188: + LexManos: Cleanup repo, delete old code + LexManos: Update FML to 278, MC 1.3.2 + LexManos: Cleaned up forge scripts, and updated AT config for 1.3.2, deleted any reference to server specific code. + LexManos: Updated patches to 1.3.2 + LexManos: Fixed bug in DimensionManager that would cause Index error for custom dimensions, also made WorldProviders aware of what dimension they are. + +Build 4.0.0.187: + LexManos: Readded patch to allow for use of custom teleporter for transfering dimensions. + +Build 4.0.0.186: + LexManos: Update FML with entity spawning fixes + +Build 4.0.0.185: + LexManos: Updated FML, should fix 'derp?' RuntimeError + +Build 4.0.0.184: + LexManos: Fix PickBlock 'ghost item' bug when picking with a item selected. + +Build 4.0.0.183: + LexManos: Update FML, Tons of bug fixes and proper merging of client and server. + LexManos: Delete Forge server projects + LexManos: Update debug settings to use Client's internal MinecraftServer.main to debug dedi-server env. + LexManos: Update release script to create universal binary distro. + +Build 4.0.0.182: + j.marini: Fix bug where default bonemeal behavior wouldn't trigger. Only return if the event was canceled. + +Build 4.0.0.181: + LexManos: Update FML, new AT features, and error info. + +Build 4.0.0.180: + LexManos: Fixed ItemRenderer not grabbing custom texture files properly for block items + LexManos: Updated FML + LexManos: Delete dead IGuiHandler + LexManos: Update AT config to expose some block functions and a few extras. + +Build 4.0.0.179: + LexManos: Should fix commands.py patching not working properly first run. + +Build 4.0.0.178: + LexManos: + Updated FML, Should fix a lot of installing issues for MCP. + Made patches error and not apply if the target file is not found. + Updated Event Transformer to add a default constructor... + Fixed 4096 setup code in MinecraftForge.initalize() + +Build 4.0.0.177: + LexManos: Fix issue in install script for users with spaces in there paths. + +Build 4.0.0.176: + LexManos: Update FML, server should run now. Still issue with NPE with no mods installed. + LexManos: Updated FML, fixed custom tool hooks, and spawn protection/player reach hooks. + +Build 4.0.0.173: + LexManos: Fixed Diemsnion API related NPEs, and updated FML to 231. + +Build 4.0.0.172: + LexManos: Get rid of all old patches + LexManos: Added a better eclipse workspace for deving Forge + LexManos: inital push of updated setup script and cleaned up forge.py + LexManos: Dump old mcp config + LexManos: New Start.java which allows the user to login using a legit account for testing on servers. + LexManos: Committing inital work on generating sanitized MCP conf data. + LexManos: Add the direct copied files from MCP conf + LexManos: Add newids to that list + LexManos: Helper function grab all unique searge names that are shared client and server + LexManos: Added merging fields/methods/param csv files. And updated FML to 197 + LexManos: Remove eclipse files from old eclipse projects + LexManos: Updated build.py + LexManos: Update FML + LexManos: + Moved logo to new client folder + Added blank Access Transformer config for Forge + Implemented version storage + Added basic dummy FML mod container to remove the need for mod metadata file + Added beggining work on Forge event system + Updated and moved EnumHelper + LexManos: Updated update_patches.py, and made first patch! + LexManos: Moved paulscode to new client folder + LexManos: First push of some small patches and introduction of basic events. As well as the first cases for Forge's Access Transformer + LexManos: Missed a file + LexManos: Moved in OreDictionary stuff to new system. IOreHandler is replaced by OreDictionary.OreRegisterEvent + LexManos: Renamed MinecraftForge.eventBus to EVENT_BUS as it's constant. + LexManos: Implemented BonemealEvent (IBonemealHandler replacement), and bonemeal making grass. + LexManos: Implemeneted adding grass seeds, as well as IShearable for BlockTallGrass + LexManos: More progress on converting patches from 1.2.5 + LexManos: Some more patch migration before bed. + LexManos: + More patches converted. + Refactored some of the events to be a better hiarachy. + LexManos: A bulk of more patches converted, updated fml + LexManos: Moved some files. + LexManos: More work, moved over packet stuff, need to change everything to use new NetworkMod system + LexManos: More conversions, added all the entity living events. + LexManos: Finished World and EntityMinecart patches. + LexManos: Removed a lot of old files + LexManos: Updated Client side patches for the new Merged MCP workspace. + LexManos: Nope, unneeded patch + LexManos: Cleaned up some more, fixed infinite loop with cancelable annotation, Client now compiles and enters world just fine. + LexManos: Delete conf, server compile, update fml, and fix install script. + LexManos: Copy forge files over in install. + LexManos: Update fml + LexManos: Moved over Configuration + LexManos: Fix oreientation bug causing levers not being able to place. + LexManos: Added new pick block hook for blocks and entites to allow for better grained control of the result. + LexManos: Include Forge's AT config into redist zips. + LexManos: Update fml, impelemnted Diemsnion API stuff. + LexManos: Updated FML, updated patches + +Build 3.4.9.171: + Christian: Normalize the repo + LexManos: Rebase + LexManos: Bumped version to 3.4.9, final commit for 1.2.5. + +Build 3.3.8.170: + someh4x0r: Fix BlockTrapDoor.disableValidation on server + +Build 3.3.8.164: + LexManos: Should fix NPE on older ISoundHandlers EXA: http://minecraftforge.net/forum/index.php/topic,759.html + +Build 3.3.8.163: + Christian: Update fml with recent tick fix + +Build 3.3.8.162: + truebrain: + -Add: sync serverPos[XYZ] on spawning of entity + + This fixes the issue that, up to 400 ticks from getting in range, + entities have a wrong offset (because server and client don't agree on + the position to calculate relative updates from) + truebrain: -Fix: check for null where needed + truebrain: -Codechange: applied LexManos' request + +Build 3.3.8.161: + LexManos: Fixed a improper rounding in EntityMinecart + LexManos: Made WorldGenMinable metadata sensitive. + +Build 3.3.8.160: + Christian: Update fml to 175- fixes some weird ticking behaviours for ML mods, adds in new ticking behaviours for smart mods + +Build 3.3.8.159: + LexManos: Moved licenses and credits into install folder. + LexManos: Removed symlink files, shouldn't be in the repo. + LexManos: Updated some remaining scripts to call there python versions. + +Build 3.3.8.158: + LexManos: Fix furnaces not smelting the proper number of results after the first one. Damn you tahg, fix this! Keeps falling through my cracks. + +Build 3.3.8.157: + Christian: + Fix server check "blockHasTileEntity" used to determine if getDescriptionPacket + is sent for the block to be metadata sensitive. Thanks iChun! + +Build 3.3.8.156: + Christian: Fix ghost players who appear if they don't have the 4096 fix installed + +Build 3.3.8.155: + LexManos: Fix container creative to not add Blocks above 256 unless it's told to. + +Build 3.3.8.154: + Christian: + Fix world provider behaviour: WorldProvider.byDimension should always return + a new instance- otherwise you can end up with worlds overwriting one another + +Build 3.3.8.153: + LexManos: Fixed isBlockReplaceable and placing ItemBlocks' + +Build 3.3.8.152: + LexManos: Fucking spelling nazis + +Build 3.3.8.151: + LexManos: Fix bitmask bug related to 4096 in multi-block change. + LexManos: Updated FML to build 153 + +Build 3.3.8.150: + LexManos: Fix NPE related to server/client not having block ids synced properly. + LexManos: Add option to randomize potential spawn locations to have a more randomly dispersed spawn patern, useful for games like FTB vs. + LexManos: Added configuration option to disable the darkroom mechanic. For servers who wish to not risk destruction at one broken pipe. + +Build 3.3.8.148: + LexManos: FML 150, more tick related work. + +Build 3.3.8.147: + LexManos: Close inputstream + +Build 3.3.8.146: + LexManos: More bugfixes related to portal generation. Should be all now. + +Build 3.3.8.145: + LexManos: Some 4096 I missed in custom renderers. + LexManos: Updated to FML 149, should fix all ticking issues with ModLoader mods + LexManos: Fix Vanilla bug where nether portals would not work above 127 + +Build 3.3.8.144: + LexManos: Updated to FML build #142, fixed FML compilation issue causing missing files when reobfing. + +Build 3.3.8.143: + LexManos: Updated release script to automatically inject version info into .info file. + +Build 3.3.8.142: + LexManos: Updated to FML 141, should fix ticking issues with certian mods, and crash issue with TropiCraft + +Build 3.3.8.141: + LexManos: Bumped version number for new IEntityLiving interface. + +Build 3.3.7.140: + pahimar: Typo in the new EntityLivingHandler code + +Build 3.3.7.139: + LexManos: Made setFailsafeFieldValue public for Rob + LexManos: Implemented enchanced EntityLiving events. Thanks Atomic for parts of it. + +Build 3.3.7.138: + LexManos: Few more cases for 4096, thanks TrueBrain + +Build 3.3.7.137: + LexManos: Forgot Configuration in 4096 change. + +Build 3.3.7.136: + LexManos: Configurable kick message when you don't have forge. + LexManos: Initial 4096 fix based of mDiyo's work. + +Build 3.3.7.135: + LexManos: Fixed bug in new entity sound hook. + +Build 3.3.7.134: + LexManos: Updated to FML #135 {Fixed ModList rendering issue, and incorrect arument on crafting hook} + LexManos: Added new ISoundHandler.onPlaySoundAtEntity hook. Should be backwards compatible with any older ISoundHandler implementations. + LexManos: New onChunkUnload event for TileEntities, for psxlover. + LexManos: Bumped version number to 3.3.7 for full release. + +Build 3.2.6.132: + LexManos: Fixed concurent modification exception in the ore registry. + +Build 3.2.6.131: + LexManos: Fix for potential concurancy modification exceptions + +Build 3.2.6.130: + LexManos: Fixed possible NPE when blocks havent fully initalized yet. + +Build 3.2.6.129: + LexManos: Updated FML to 132, TextureFX fix, and bumped revision to 6. + +Build 3.2.5.128: + LexManos: Added bouncer functions for functions we removed. Makes MagicLauncher shut up about missing functions {not actually missing}, and therefor makes users stop thinking its a life or death error. + +Build 3.2.5.127: + LexManos: New Ore Dictionary recipies. Allows for simpler Ore Dictionary integration with recipies. IOreHandler should no longer be used. + +Build 3.2.5.126: + LexManos: Updated to FML 130 + LexManos: Added hackish workaround for Tessellator.textureID to provent crashing while we wait for Optifine to update. + +Build 3.2.5.125: + LexManos: Server side of ITextureProvider for Block/Item for compilations sake. + +Build 3.2.5.124: + LexManos: Backwards compatibility fix for ITextureProvider + +Build 3.2.5.123: + LexManos: Updated FML to 121 to fix world tick issues. + +Build 3.2.5.122: + LexManos: Updated MCP mapings. Moved the bulk of custom logic from RenderItem to ForgeHooksClient. + LexManos: All Items and Blocks now implement ITextureProvider, and have a setTextureFile(String) function, to support cleaner code in Mods and in Forge. + LexManos: Tag each Tessellator with it's associated texture ID. + +Build 3.2.5.121: + LexManos: Added kick info to disconnect event, updated to FML 120, keybindings, better image rendering in ModList ui. + +Build 3.2.5.120: + LexManos: Fix bug in cart functions where would always return null. + +Build 3.2.5.119: + LexManos: Fixed some inverted logic causing tress to not gen correctly. + +Build 3.2.5.118: + LexManos: Update FML to 117 + +Build 3.2.5.117: + LexManos: New Hooks addedf for custom tree/leaves. And better interaction with trees growing and rerplacing certain blocks. Should allow for ExtraBiomes to behave nicer, and RedPower to make there blocks un-breakable by trees. + LexManos: Also, new hook in last commit for blocks to determine if they are able to be replaced by ores, for any mod that adds new world gen. Bumped revision up. + +Build 3.2.4.116: + LexManos: We now bundle CodexIBXM from PaulsCode. See http://paulscode.com http://www.paulscode.com/forum/index.php?topic=4.0 and the included license files for more info. + LexManos: Updated to FML 115, added Forge Logo to the client dist, and in-game ModInfo page. + +Build 3.2.4.115: + LexManos: Updated to FML build 114 + +Build 3.2.4.114: + LexManos: Included fmlversion.properties in the release zips. + +Build 3.2.4.111: + LexManos: Added FML ReadMe, Credits, and License to release zips + +Build 3.2.4.110: + LexManos: Update FML to 92, this include full client side support, ModLoader nolonger needed. + LexManos: Added new source clean step to fix linux vs windows astyle issues. + LexManos: Cleaned up names for Minecraft Forge's text files so they dont clash with other mods. Fixed up the release script to include the license text, and executable permissions for install.sh. + LexManos: Added FML mod info file + LexManos: Updated MCP Mapings and patches. + LexManos: Updated patches for FML, moved some extranious code to Forge classes instead of patches. + LexManos: Updated to FML Build 95 + +Build 3.2.3.108: + LexManos: Bump version number for official release. + +Build 3.1.3.107: + LexManos: Fixed AudioMod compatibility with MultiMC style launchers. + +Build 3.1.3.106: + LexManos: Bit masked the entity ID to change the range from -127-127 to 0-255 + +Build 3.1.3.105: + LexManos: Updated MCP Mapings + +Build 3.1.3.104: + LexManos: Added forge identifier to statistics collection. + +Build 3.1.3.103: + LexManos: Fix for furnaces not smelting the final item in full stacks. + +Build 3.1.3.102: + CovertJaguar: static final vars are inlined during the compile step, making the version variables useless at runtime. + LexManos: Fixed Levers droping off the backs of stairs client side. + +Build 3.1.3.101: + LexManos: New block hooks for creating custom beds. + +Build 3.1.3.100: + cpw: Update to FML 74: fixes an important issue with MLProp + +Build 3.1.3.99: + LexManos: Bumped revision to 3 + +Build 3.1.2.98: + LexManos: Fixed Vinella mob spawning bug that prevented mobs from spawning on the top most chunk. Added new Block function to determine if a Mob can naturally spawn on the block. Add new hook to allow for special case handeling on natural entity spawn. + +Build 3.1.2.97: + LexManos: Fix for loading Minecart Entities in worlds that were last accessed before Forge was installed. + +Build 3.1.2.96: + LexManos: Moved MLMP compatibility functions to ModCompatibilityClient, and fixed issue where no vehicles would be spawned. + +Build 3.1.2.95: + LexManos: + New ISoundHandler interface, useful for adding custom sounds and dealign with sound based events. + Includes basuic AudioMod compatibility. + +Build 3.1.2.94: + LexManos: Fixed vinella bugs when trying to access chunk information with a y < 0 + +Build 3.1.2.93: + LexManos: Updated to FML build #73 + LexManos: Added MLMP hook invocation for vehicle spawn and opening GUI's to provide compatibility for clients that have both ModLoaderMP and forge installed. + +Build 3.1.2.92: + LexManos: Exposed TileEntityData packet to TileEntities. And added helper sender function. + +Build 3.1.2.91: + LexManos: Added metadata sensitive Chunk constructor for Bioxx + +Build 3.1.2.90: + LexManos: Added MinecraftApplet.clas to the force output list because users cant understand the concept of only replacing files they are told to. And bumped version to 3.1.2 + +Build 3.0.1.89: + LexManos: made the ID in PacketEntitySpawn unsigned. + LexManos: Added generic packet sending function to MinecraftForge class. + LexManos: Fixed shift-clicking issue with items that utilized the new ItemStack sensitive smelting system. + LexManos: Implemented a 'small' packet system for those mods that need to send rapid, small data packets and who are concered about the overhead of the 250 payload packet. It uses packet 131. + +Build 3.0.1.88: + LexManos: Implemented RichardG's Paged Achivement list GUI modifications. + +Build 3.0.1.87: + t.tomkins: Edits enable use of EntityPlayer.canHarvestBlock (for PlayerAPI) when the ToolClass has no rules for the block. + +Build 3.0.1.86: + LexManos: MAX_ENTITY_RADIUS Now works on the Y axis + LexManos: Respawning in dimensions should now properly set the dimension ID for the new player instance. + +Build 3.0.1.85: + LexManos: Fix for vanilla crash for chunk generation with block ID's above 127. + +Build 3.0.1.84: + cpw: Update fml to build 68: fixes a ticking issue and soft vs hard dependencies + +Build 3.0.1.83: + LexManos: + Changed entity Forge spawning code works to be more in line with normal spawning: + (World, double, double double) constructor is nolonger called, normal (World) constructor, and setPositionAndRotation is called afterwords. + yaw, pitch, and yawHead is sent (if the entity isn't a EntityLiving yawHead isn't used) + The datawatcher data is also sent like a normal Entity. + +Build 3.0.1.82: + LexManos: Fixed bug in BlockFire's old fields. + LexManos: Added variable entity radius to World, to be used if a mod make really large entities. + +Build 3.0.1.81: + LexManos: Fixed TileEntity bug that was causing Ghost tile entities. + +Build 3.0.1.80: + LexManos: Multi-pass item rendering now uese proper render pass number. + +Build 3.0.1.79: + LexManos: Added slope velocity hook for Covert + +Build 3.0.1.78: + LexManos: Fixed bugs in the Dimension transfer code, Now displays proper join message, and respawning in dimensions other then 0 works. + +Build 3.0.1.77: + CovertJaguar: Added a function for checking block harvest levels without having to resort to reflection. + LexManos: Try to fix jenkins build. + +Build 3.0.1.75: + LexManos: Added ItemStack sensitive burn time hook. + +Build 3.0.1.74: + LexManos: + Added new Item function to allow for multiple rendering passes. + Fixed a vinella bug where item layters would not line up for EntityItem's + Added new IItemRendere helper flag for 3d block translations. + +Build 3.0.1.73: + cpw: Update fml to 62- provision a server console command and fix mod loading order + cpw: Update FML for new hooks: onPlayerLogout and onPlayerDimensionChanged + LexManos: + Rewrote IItemRenderer to be a more generic and expandable version, Breaks previous interfaces, but this should be the last time the interface changes. + Implemented the MapRender hook ChickenBones requested. + +Build 3.0.0.72: + cpw: Fix separated login/announce handler + cpw: FML 59: don't send a zero length register packet, add mod channels + +Build 3.0.0.71: + cpw: Update to FML 57: fixes FML not calling it's login handler code + +Build 3.0.0.70: + LexManos: MCP Conf update for 1.2.5 + LexManos: Initial patch update to FML and MC 1.2.5 + LexManos: Deleted patches + LexManos: Fixed update_patches.py to now delete old patch files that have no working src relation + LexManos: Updated repo scripts to python, allowing more flexability and less code duplication. + LexManos: Finished up converting the source dist install scripts to python. Fixed a couple issues with the other scripts. + cpw: Update patches for FML fix. + cpw: Fix release script to import "inject_version" + cpw: Add in recent fml with fixes + cpw: Delete the old one too + LexManos: Rewrote the login code to delay full login untill forge fnishes negotiating network IDs. Should fix entities not having proper ID mapings. + LexManos: Added ChickenBones's request ITextureLoadHandler hook + LexManos: Updated patch for mapings + LexManos: Implemented ISaveEventHandler as ChickenBones's requested. + LexManos: Add server spawn protection config option as per someh4x0r's request. + LexManos: Couple of output fixups and added script to be executed by Jenkins during the build. First test build. + LexManos: Changed IGuiHandler's signature to be compatible with both sides. Took out ModLoaderMp reference in README. + +Build 2.0.0.68: + LexManos: Fix some shadowing warnings. + LexManos: Some cleanups to update_patches, should run properly on any system now. + LexManos: Add IChunkLoadHandler.canEntityUpdate() function to allow entities to update while in custom loaded chunks. + LexManos: Implemented a chat event handler system to allow for manipulating and handeling the various chat/command events. + +Build 2.0.0.67: + LexManos: Changed update_patches script to use python for the bulk, Prevents making 1800 temporary useless files. + LexManos: Fixed camelcasing in IConnectionHandler, ment to do during first upgrade. + +Build 2.0.0.66: + LexManos: Fixed typo bug in MinecraftForge.getEntityTrackerInfo + +Build 2.0.0.65: + LexManos: + Updated to MC: 1.2.4 MLMP: 1.2.4 v1 + Removed all code that was marked as deprecated, IE: ICustomItemRenderer, and the functions in Configuration + +Build 1.4.1.64: + LexManos: Reworked EntityPlayerMP.openGui to hopefully be more compatible with PlayerAPI + +Build 1.4.1.63: + LexManos: Cleanup the EffectRenderer patches, Allows custom food items to have the proper particals. Cleaned up special case class in favor of basic java generics. + +Build 1.4.1.62: + CovertJaguar: Added the ability to define custom categories for config files. + CovertJaguar: Removed createCategory() function and changed it to create categories as they are encountered. + LexManos: Updated MCP mapings + LexManos: + Fixed a couple of bugs in the Configuration categories pull request. + Added helper functions to Property for standard int/boolean usage. + LexManos: Added rider sit pull request. + +Build 1.4.1.61: + LexManos: Fixed NPE on CustomPayload packets with 0 data + LexManos: Changed logic in Configuration to allow for extended block ID mods easier access to change that. Just use reflection to change Configuration.configBlocks to whatever length you want. + LexManos: Implemented Pheenixm pull request allowing for more control over the camera. + LexManos: + Added MinecraftForge.isClient() function that returns true if you are in the Minecraft Client, (As defined as net.minecraft.client.Minecraft existing) false otherwise. + Fixed a typo on PacketEntitySpawn that caused speed to be assigned improperly. + A little code cleanup. + +Build 1.4.1.60: + LexManos: Fixed a few typos that CovertJaguire found in The Forge entity handeling code. And re-wrote the connection sequance so that clients get a list of mod ids before anything else. + +Build 1.4.1.59: + LexManos: Readded the deprecated interface ICustomItemRenderer. Added method to enforce deprecation cross Minecraft versions. + +Build 1.4.1.58: + newthead: Added new item render interfaces to Forge client + newthead: Added hook for rendering equipped items + newthead: Clarified render option for inventory items + newthead: Added remaining item render hooks, and fixed a static method access + newthead: Added render code for inventory items and entity items. + newthead: Cleanup/fix item render hooks + newthead: Added additional flag for rendering entity item bobbing + newthead: Merged item rendering interfaces into a single IItemRenderer + newthead: Updated render hooks and registration to use the IItemRenderer interface + newthead: Modified patches to use new item render hooks + newthead: Merged item rendering interfaces into a single IItemRenderer + CovertJaguar: Fix for network code. + newthead: Changed render hook checks to all use ItemStack instead of itemID + newthead: Reverted vanilla texture binding to an explicit if() statement based on item ID + LexManos: Fixed dyes showing twice in creative list + LexManos: Bumped version number to 1.4.1 + +Build 1.4.0.57: + LexManos: Fixed tile entities not properly being removed for blocks that do not extend BlockContainer, or override BlockContainer.onBlockRemoval + +Build 1.4.0.56: + LexManos: Fixed excessive need for user interaction in the install script. + LexManos: Fixed a class to a deprecated method to fix tool effectiveness. + +Build 1.4.0.55: + LexManos: Reworked the workspace scripts so the build should fail on compile errors. This build should fail as a test. + LexManos: Fixed IOException not found error in CovertJaguires pull request. Updated scripts so that build should now be fixed + +Build 1.4.0.53: + CovertJaguar: Added throws clause to ISpawnHandler functions to keep the functions consistent with similar functions and increase ease of use. Exceptions are already being caught everywhere these functions are called, so no further changes required. + LexManos: Fixed onTakenFromCrafting hooks to be called once per stack taken. Sadly due to how shift-click is handled, the passed in item stack is not garenteed to be the stack that the result was added to. + +Build 1.4.0.52: + LexManos: Fixed forgotten type identifier in clean_src + LexManos: New EntityInteract hook for handeling player vs entity interaction on the global level vs the item level. + LexManos: Fixed sides of grass not getting biome colors + LexManos: Fixed type on patch conversion messing up tile entities + LexManos: Proper fix for SDK's invalid bit shifts of parameters for chunk population + LexManos: Made BlockStairs, BlockFarmland, and BlockStep have proper sided-solidity. Can now place torches on any solid side of those blocks. + +Build 1.4.0.51: + cpw: + Fix worldgen doubleshifting in ModLoaderMP until SDK fixes it. + + This means mods can generate surface and nether in SMP again. + +Build 1.4.0.50: + eloraam: Fixed a merge error. + LexManos: + New script to fix decompile differences between windows and linux/osx. + Removed the MLProp special case, no longer needed as MLProp decompiles fine. + Updated patches to work on all systems. + Added warning and exit if the user does not say yes to the cleanup. + +Build 1.4.0.49: + eloraam: MCP Update. Fixed a few small bugs in the linux scripts. + +Build 1.4.0.48: + LexManos: Fixed the inverted logic in the missing mod check. + LexManos: Fixed a wrong argument for dimensions, should fix entity tracking. + LexManos: Custom dimensions should now honor the canRespawnHere function for respawning. + +Build 1.4.0.47: + LexManos: Fix up Configuration ids to only work for 256 ids until Jeb finishes the 4096 conversion. + +Build 1.4.0.46: + LexManos: Fixed a bug where vines were not shearable. + +Build 1.4.0.45: + CovertJaguar: Fixed a minor bug with the Minecart Dictionary. + +Build 1.4.0.44: + LexManos: 1.4.0 official release. + +Build 1.3.4.42: + LexManos: Updated to MLMPv3 + +Build 1.3.4.41: + LexManos: Hack-fix for players getting stuck during logins. Detailed fix when bug is actually tracked down. + LexManos: Implemented ChickenBone's Chunk handler + +Build 1.3.4.39: + LexManos: Fixed client side bonemeal on grass only making flowers + LexManos: Updated to latest MCP + +Build 1.3.4.38: + LexManos: Fixed MLMP thinking Network mods need a client side when they dont. + LexManos: Fixed a generic tile entity line i missed on the server side. + LexManos: Removed improper tile entity negation + +Build 1.3.4.37: + LexManos: Updated to SDK MLMP v2 + +Build 1.3.4.36: + LexManos: Fixed missing double array in MLMP's packet server side. Also, fixed the creative code again, brain failed. + +Build 1.3.4.35: + LexManos: Got my comparitor turned around + LexManos: Updated to SDK's 1.2.3 MLMP, Mush cleaner, no longer supporting Flan's. + +Build 1.3.4.34: + LexManos: Updated gitignore, fixed digging particles, fixed creative container showing to many blocks, fixed wrong argument for custom renderers. + +Build 1.3.4.33: + LexManos: Updated MCP's patch files. Fixes hangs on running MC as applet. + LexManos: ItemBlock now implements ITextureProvider so that blocks with custom textures will showup properly when being held. + +Build 1.3.4.32: + LexManos: Fixed NPE in the login handler + LexManos: Fixed directory issues in the setup script + LexManos: Cleanup of ModLoaderMP and proper update to the latest version of ModLoader + +Build 1.3.4.31: + LexManos: Fixed missing space in linux scripts + LexManos: No longer mark forge packets as chunk packets. + LexManos: Updated MCP mapings files + +Build 1.3.4.30: + LexManos: Updated scripts so that we use Fernflower now. Added a small python script to download fernflower for the user. And the scripts exit out if it fails. + LexManos: Deleted modLoaderMP.patch, unneeded now that we use Fernflower + LexManos: Updated eclipse project for MCP 1.2.3's inclusion of the Start folder in the src folder. + LexManos: Updated The Json enum helper to point to the new packaged names. And fixed a casing change in ModLoader + LexManos: Made mod_MinecraftForge extend NetworkMod, and changed NetworkMod to extend BaseModMP server side. + LexManos: Fixed unneeded imports in ForgePacket + LexManos: removed unneeded import, and fixed casing of args in IShearable + LexManos: Deleted EntityPigZombie patches, Who needed these? Why could you not do this via reflection? + LexManos: Conf for 1.2.3 + LexManos: Same patch diff, files. + LexManos: No longer needed, bug was fixed + LexManos: Client side initial patch update to Fernflower and MC 1.2.3 + LexManos: Bit of a cleanup of the client patches + LexManos: Couple of things I missed client side + LexManos: Deleted unneeded server side patches, Packet250 bug was fixed. And the others got moved to AnvilSaveHandler + LexManos: First push of server side patch updates for 1.2.3. MLMP is still not updated so it does not include those changes, and will not compile. + LexManos: Small imports cleanup + LexManos: Missed damageCarryover on the server + LexManos: Made the scripts forge updating md5s/mcp/names + LexManos: Updated for MLMP 1.2.3 v1 + +Build 1.3.4.29: + LexManos: Bumped version to 1.3.4, final commit for Minecraft v1.1 + +Build 1.3.3.28: + LexManos: Fixed bug in build script that caused the Minecraft/MinecraftServer classes to not be included. + +Build 1.3.3.27: + LexManos: Client side of the new Dimension support. + +Build 1.3.3.26: + thedeveducer: Fixed spelling mistake ('Frequancy') + LexManos: Fixed ITextureprovider for multi-textured items when rendering on the GUI. + LexManos: Fixed compile error for the spelling pull request. + +Build 1.3.3.24: + LexManos: Fixed up Shearable blocks to play nicer with sub-classes. + LexManos: Fixed line endings in windows update_patches + LexManos: Deleted Deprecated interfaces. + LexManos: Ran AStyle over forge code for uniform code formatting, and refactored old code a bit to have cleaner names. + +Build 1.3.3.23: + connor: People may think the server needs the mods to continue and not the client. + +Build 1.3.3.22: + LexManos: Fixed a bug in update_patches that caused apostrphies to be removed. Causing the last patch to be generated incorrectly. + +Build 1.3.3.21: + LexManos: + Initial attempt at server side extra dimensions support. + Mods must register there dimensions on load, by calling DimensionManager.registerDimension(uniqueID, WorldProvier, boolean) + Mods are resposible for writing there own transporter blocks. + Initial commit, needs some more testing and design thoughts. + +Build 1.3.3.20: + LexManos: Added new Item.getIconIndex context sensitive version. + LexManos: Implemented a response to Methuselah96's Arrow hook request. See IArrowNockHandler and IArrowLooseHandler + +Build 1.3.3.19: + LexManos: Changed the layout of the missing mods gui a little. Still needs a lot of work to look good. + LexManos: Marked forge packets as 'chunk' packets. Giving them a higher priority making the initial mod list check more reliable. + LexManos: Introduced some debugging info into Forge packets. And a debug flag in the client and server packet handlers. + LexManos: Moved Client side EntityPlayer.openGui work code to EntityPlayer for compatibility between player API. + +Build 1.3.3.16: + eloraam: Linux scripts fixed, TE bug fix. + eloraam: Fixed linux scripts, fixed TE bug. + +Build 1.3.3.15: + LexManos: Exposed getters for NetServerHandler.playerEntity and NetworkManager.netHandler + LexManos: + Introuduced NetworkMod, a BaseMod extension and replacement for BaseModMP. All mods that are designed to work in the server environment should extend this. + NetworkMods will be assigned unique ModIDs by the server, and those IDs will be sent to the client upon connection. + Refactored Forge packets to the net.minecraft.src.forge.packets package. And introduced the base ForgePacket class. + Added initial ModList request/response. + LexManos: + Expanded the Mod check to test for missing mods and display a GUI screen for the client if it is missing any. + The client now downloads NetworkMod ID's from the server upon connecting. + LexManos: Implemented a generic EntityPlayer.openGui system, and the network backend for it to work on server and client. + +Build 1.3.3.14: + LexManos: + Fixed up the install scripts. The linux script no longer needs sed. Should fix some issues on OSX's without gsed. + Also forge sources will only be copied to sides that were downloaded. + Also, install scripts now prompt for input to cleanup. + +Build 1.3.3.13: + LexManos: Split mod_MinecraftForge so that Clients arnt required to have MLMP installed if they don't use a MP mod. + +Build 1.3.3.12: + LexManos: Update MCP Mapings + LexManos: Small update to update_patches.bat, to skip patch reject files. + LexManos: Bumped version to 1.3.3 + +Build 1.3.2.10: + LexManos: + Refactored so that ISpecialArmor items do not see the factor of 25 on the damage. + The value returned form ISpecialArmor.getProperties is now copied, so mod items are free to re-use there return values. + +Build 1.3.2.9: + LexManos: + Reworked ISpecialArmor to provide better functionality as requested by IC2 devs. + Armor can now be prioritized over other armor. + It can deal with damaging it's own itemstacks. + Also impkemented the ISpecialArmor.getArmorDisplay + +Build 1.3.2.8: + LexManos: Lowered the amount of build log spam, and fixed the inject_version script for use on other systems. + LexManos: Fixed ITextureProvider support for items that have multiple colored overlays. + LexManos: Added Item.onLeftClickEntity hook. Used to intercept and cancel the 'attack' action within items. + LexManos: Implemented item.onBlockStartBreak call for creative single player. + LexManos: Implimented a new IShearable system. This allows mods to create both new shear-like items/blocks. As well as new Entities/Blocks that work with other mod's shear-like items. + +Build 1.3.2.7: + LexManos: Missed a caluse, ISpecialArmor should work as intended now. And not destroy Armor instanatly. + +Build 1.3.2.6: + LexManos: + Implmented Sengir's IPickupHandler. + http://www.mod-buildcraft.com/forums/topic/hook-intercept-item-pickups-by-player-entities/?view=all + +Build 1.3.2.5: + LexManos: + Merged in the change to ISpecialArmor to introduce the DamageSource argument. + As well as the concept of damage absorption vs reduction. + +Build 1.3.2.4: + LexManos: + Created a Entity tracking ans spawning system. + Mod creators should call MinecraftForge.registerEntity to register a entity. + All entity ID numbers are Mod Unique. Meaning two mods can have Entity #1. + Added client and server side packet handlers for the 'Forge' channel. For use in internal packets such as the new Spawn packet. + Updated the build scripts to copy over unique server source files now that there actually are some. + For modders: + If you have a entity that used MLMP's 'owner' system, you should have your entity implement IThrowableEntity + If you have a entity that implments MLMLP's ISpawnable, you should implement ISpawnHandler. + They provide the same functionality, just in a cleaner, more orginized way and will be the method used when we eventually drop MLMP. + +Build 1.3.2.3: + LexManos: Fixed return value for un/registerChannel. Now returns properly indicate when un/register commands should be sent. + +Build 1.3.2.2: + LexManos: + Setup .gitignore for eclipse bin dirs. + Fixed line endings in install.sh + Added mod_MinecraftForge for simpler logging of minecraft version in crash reports + Added new hooks for connection events, See IConnectionHandler for more details. + Added Packet250CustomPayload handeling and channel registraction management, see MessageManager and IPacketHandler for more details. + Forge now uses unsed fields in C->S Packet1Login to identify itself. None Forge clients will get a graceful disconnect message instead of the 'Unknown packet 230' + diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..e9b9fd5a --- /dev/null +++ b/gradle.properties @@ -0,0 +1,3 @@ +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +# This is required to provide enough memory for the Minecraft decompilation process. +org.gradle.jvmargs=-Xmx3G diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..30d399d8d2bf522ff5de94bf434a7cc43a9a74b5 GIT binary patch literal 52271 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 z%0D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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..e18cba72 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Sep 14 12:28:28 PDT 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip diff --git a/gradlew b/gradlew new file mode 100644 index 00000000..91a7e269 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java new file mode 100644 index 00000000..1ae24b85 --- /dev/null +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -0,0 +1,176 @@ +package electroblob.wizardry; + +import electroblob.wizardry.item.ItemSpectralBow; +import electroblob.wizardry.packet.PacketCastContinuousSpell; +import electroblob.wizardry.packet.PacketCastSpell; +import electroblob.wizardry.packet.PacketClairvoyance; +import electroblob.wizardry.packet.PacketGlyphData; +import electroblob.wizardry.packet.PacketNPCCastSpell.Message; +import electroblob.wizardry.packet.PacketPlayerSync; +import electroblob.wizardry.packet.PacketTransportation; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.translation.I18n; +import net.minecraft.world.World; +import net.minecraftforge.common.config.Property; + +/** + * The common proxy for wizardry, serving the usual purpose of dealing with all things that need to be handled + * differently on the client and the server. A lot of the methods here appear to do absolutely nothing; this is + * because they do client-only things which are only handled in the client proxy. + * @see {@link electroblob.wizardry.client.ClientProxy} + * @author Electroblob + * @since Wizardry 1.0 + * */ +@SuppressWarnings("deprecation") +public class CommonProxy { + + // SECTION Registry + // =============================================================================================================== + + public void registerRenderers(){} + + public void initialiseLayers(){} + + public void registerKeyBindings(){} + + public void registerSpellHUD(){} + + public net.minecraft.client.model.ModelBiped getWizardArmourModel(){ return null; } + + public void initMixedFontRenderer(){} + + // SECTION Particles + // =============================================================================================================== + + /** + * Spawns a custom particle of the specified type. + * + * @param type EnumParticleType of the particle + * @param world Reference to the World object + * @param x Particle x position + * @param y Particle y position + * @param z Particle z position + * @param velX Particle x velocity + * @param velY Particle y velocity + * @param velZ Particle z velocity + * @param maxAge Lifetime of the particle in ticks + * @param r Red component of particle colour; will be clamped to between 0 and 1 + * @param g Red component of particle colour; will be clamped to between 0 and 1 + * @param b Red component of particle colour; will be clamped to between 0 and 1 + * @param doGravity Whether the particle is affected by gravity (only affects SPARKLE at the moment) + * @param radius The radius of the particle's motion, for cirular motion particles + */ + public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b, boolean doGravity, double radius){ + // Does nothing since particles are client-side only + } + + /** Spawns a custom particle of the specified type. doGravity defaults to false and radius defaults to 0. + * Note that some of these settings may not affect the particle; some particles are always affected by + * gravity, for instance. + * + * @param type EnumParticleType of the particle + * @param world Reference to the World object + * @param x Particle x position + * @param y Particle y position + * @param z Particle z position + * @param velX Particle x velocity + * @param velY Particle y velocity + * @param velZ Particle z velocity + * @param maxAge Lifetime of the particle in ticks + * @param r Red component of particle colour; will be clamped to between 0 and 1 (unless this is a MAGIC_FIRE particle, in which case this is the scale) + * @param g Red component of particle colour; will be clamped to between 0 and 1 + * @param b Red component of particle colour; will be clamped to between 0 and 1 + */ + public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b){ + this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, r, g, b, false, 0); + } + + /** Spawns a custom particle of the specified type. Colour defaults to white, doGravity defaults to false and radius + * defaults to 0. Note that some of these settings may not affect the particle; some particles are always affected by + * gravity, for instance. + * + * @param type EnumParticleType of the particle + * @param world Reference to the World object + * @param x Particle x position + * @param y Particle y position + * @param z Particle z position + * @param velX Particle x velocity + * @param velY Particle y velocity + * @param velZ Particle z velocity + * @param maxAge Lifetime of the particle in ticks + */ + public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge){ + this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, 1, 1, 1, false, 0); + } + + public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){} + + // SECTION Items + // =============================================================================================================== + + public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack) { + return null; + } + + /** Returns the translated name of the scroll, taking spell discovery into account. If, for some reason, this gets + * called server-side, it uses the deprecated server version of I18n, with a warning. Since any likely server-side + * use of this method will be for text-based logic purposes (like Bibliocraft's book checking system), and since no + * particular player instance can be accessed, spell discovery is ignored. */ + public String getScrollDisplayName(ItemStack scroll){ + + // I have now learnt that the server side I18n always translates to the default en_US, so I could just return + // a hardcoded name in English instead. + Wizardry.logger.info("A mod has called ItemScroll#getItemStackDisplayName from the server side. Using the" + + "deprecated server-side translation methods as a fallback."); + + // Displays [Empty slot] if spell is continuous. + Spell spell = Spell.get(scroll.getItemDamage()); + if(spell.isContinuous) spell = Spells.none; + + return I18n.translateToLocalFormatted("item.wizardry:wizardry:scroll.name", I18n.translateToLocal("spell." + spell.getUnlocalisedName())).trim(); + } + + public double getConjuredBowDurability(ItemStack stack){ + return ((ItemSpectralBow)WizardryItems.spectral_bow).getDefaultDurabilityForDisplay(stack); + } + + // SECTION Packet Handlers + // =============================================================================================================== + + public void handlePlayerSyncPacket(PacketPlayerSync.Message message){} + public void handleGlyphDataPacket(PacketGlyphData.Message message){} + public void handleCastSpellPacket(PacketCastSpell.Message message){} + public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){} + public void handleNPCCastSpellPacket(Message message){} + public void handleTransportationPacket(PacketTransportation.Message message){} + public void handleClairvoyancePacket(PacketClairvoyance.Message message){} + + // SECTION Misc + // =============================================================================================================== + + public void setToNumberSliderEntry(Property property){} + //public void setToEntityNameEntry(Property property){} + + /** Plays a sound which moves with the given entity. + * + * @param entity The source of the sound + * @param sound The SoundEvent to play + * @param volume Volume relative to 1 + * @param pitch Pitch relative to 1 + * @param repeat Whether to repeat the sound for as long as the entity is alive (or until stopped manually) + */ + public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){} + + /** Gets the client side world using Minecraft.getMinecraft().theWorld. Only to be called client side! + * Returns null on the server side. */ + public World getTheWorld(){ return null; } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/Settings.java b/src/main/java/electroblob/wizardry/Settings.java new file mode 100644 index 00000000..8d56dce6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/Settings.java @@ -0,0 +1,507 @@ +package electroblob.wizardry; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import electroblob.wizardry.packet.PacketSyncSettings; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.text.translation.I18n; +import net.minecraftforge.common.config.ConfigCategory; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +/** Singleton class which deals with everything related to wizardry's config file. To access individual settings, use + * {@link Wizardry#settings}. Also stores a few string constants for easy access. + *

+ * As part of the 1.2 update and code overhaul, the way the config settings work in multiplayer has been tightened up. + * Importantly, there are three different types of config options: + *

+ *

  • Server-only settings. These only affect server-side code and hence are not synced. Changing these locally only + * has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world. Examples + * include worldgen, mob drops and commands. + *
  • Synchronised settings. These settings affect both client-side AND server-side code, and are synchronised with + * each client on login via {@link Settings#sync(EntityPlayerMP)}. Changing these locally + * only has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world. + * Examples include discovery mode and crafting recipes. Note that as far as users are concerned, + * there is no difference in behaviour between server-only and synchronised settings. + *
  • Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys + * its own values for these, and changing them on a dedicated server will have no effect. These are usually only display + * and controls settings.
  • + *

    + * Each of the settings fields in this class is marked with one of the above categories to indicate which it belongs + * to. This in turn dictates which logical side it should be called from: client, server or both. Do not access a + * config setting from the wrong side, because it may cause unexpected or strange behaviour. + * @since Wizardry 1.2 + * @author Electroblob */ +// NOTE: We could convert over to the @Config system IF it is sufficiently complete in this Forge version for my purposes. +// (For one, I know that the LangKey annotation is not applicable to type declarations in 1.10.2, unlike in 1.11.2) +//@Config(modid = Wizardry.MODID) +@SuppressWarnings("deprecation") // Used server I18n deliberately; we want to write the comments in english. +public final class Settings { + + // Category names + /** The unlocalised name of the spells config category. */ + public static final String SPELLS_CATEGORY = "spells"; + /** The unlocalised name of the resistances config category. */ + public static final String RESISTANCES_CATEGORY = "resistances"; + /** The unlocalised name of the client config category. */ + public static final String CLIENT_CATEGORY = "client"; + /** The unlocalised name of the commands config category. */ + public static final String COMMANDS_CATEGORY = "commands"; + /** The unlocalised name of the worldgen config category. */ + public static final String WORLDGEN_CATEGORY = "worldgen"; + /** The unlocalised name of the global config category. */ + public static final String GLOBAL_CATEGORY = "global"; + + /** The wizardry config file. */ + private Configuration config; + + // Server-only settings. These only affect server-side code and hence are not synced. Changing these locally only + // has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world. + + // Worldgen + /** [Server-only] The rarity of wizard towers, used by the world generator. Larger numbers are rarer. */ + public int towerRarity = 8; + /** [Server-only] List of dimension ids in which to generate crystal ore. */ + public int[] oreDimensions = {0}; + /** [Server-only] List of dimension ids in which to generate crystal ore. */ + public int[] flowerDimensions = {0}; + /** [Server-only] List of dimension ids in which to generate crystal ore. */ + public int[] towerDimensions = {0}; + /** [Server-only] Whether or not wizardry loot should generate in dungeon chests. Note that this does not + * affect the generation of loot in wizard towers. */ + public boolean generateLoot = true; + + // Entities' drops, targeting, damage, etc. + /** [Server-only] Chance (out of 200) for mobs to drop spell books. */ + public int spellBookDropChance = 3; + /** [Server-only] Whether or not players can teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. */ + public boolean teleportThroughUnbreakableBlocks = false; + /** [Server-only] Whether to allow players to damage their designated allies using magic. */ + public boolean friendlyFire = true; + /** [Server-only] Whether to allow players to disarm other players using the telekinesis spell. */ + public boolean telekineticDisarmament = true; + /** [Server-only] Whether summoned creatures can revenge attack their caster if their caster attacks them. */ + public boolean minionRevengeTargeting = true; + /** [Server-only] List of names of entities which summoned creatures are allowed to attack, in addition to the defaults. */ + public String[] summonedCreatureTargetsWhitelist = {}; + /** [Server-only] List of names of entities which summoned creatures are specifically not allowed to attack, overriding the defaults and the whitelist. */ + public String[] summonedCreatureTargetsBlacklist = {"creeper"}; + /** [Server-only] Global damage scaling factor for all player magic damage. */ + public double playerDamageScale = 1.0f; + /** [Server-only] Global damage scaling factor for all npc magic damage. */ + public double npcDamageScale = 1.0f; + + // Commands (these don't need synchronising since typing a command always queries the server). + /** [Server-only] The maximum allowed multiplier for the /cast command. This limit is here to stop people from accidentally + * breaking their worlds! */ + public double maxSpellCommandMultiplier = 20d; + /** [Server-only] The name of the /cast command. */ + public String castCommandName = "cast"; + /** [Server-only] The name of the /discoverspell command. */ + public String discoverspellCommandName = "discoverspell"; + /** [Server-only] The name of the /ally command. */ + public String allyCommandName = "ally"; + /** [Server-only] The name of the /allies command. */ + public String alliesCommandName = "allies"; + + // Synchronised settings. These settings affect both client-side AND server-side code. Changing these locally + // only has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world. + + // Recipes (only need syncing for display in the wizard's handbook) + /** [Synchronised] Whether or not firebombs should be craftable. */ + public boolean firebombIsCraftable = true; + /** [Synchronised] Whether or not poison bombs should be craftable. */ + public boolean poisonBombIsCraftable = true; + /** [Synchronised] Whether or not poison bombs should be craftable. */ + public boolean smokeBombIsCraftable = true; + /** [Synchronised] Whether to require a magic crystal in the blank scroll crafting recipe (in case it conflicts with another mod). */ + public boolean useAlternateScrollRecipe = false; + + // Gamemodes + /** [Synchronised] When set to true, spells a player hasn't cast yet will be unreadable until they are cast (on a per-world basis). Has no effect when in creative mode. Spells of + * identification will be unobtainable in survival mode if this is false. */ + public boolean discoveryMode = true; + + // Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys + // its own values for these, and changing them on a dedicated server will have no effect. + + // Controls + /** [Client-only] Whether the player can switch between spells on a wand by scrolling with the mouse wheel while + * sneaking. */ + public boolean enableShiftScrolling = true; + + // Display + /** [Client-only] Whether to show summoned creatures' names and owners above their heads. */ + public boolean showSummonedCreatureNames = true; + /** [Client-only] The position of the spell HUD. */ + public GuiPosition spellHUDPosition = GuiPosition.BOTTOM_LEFT; + + /** Set of constants for each of the four positions that the spell HUD can be in. */ + public enum GuiPosition { + + BOTTOM_LEFT("Bottom left"), + TOP_LEFT("Top left"), + TOP_RIGHT("Top right"), + BOTTOM_RIGHT("Bottom right"); + + /** Constant array storing the names of each of the constants, in the order they are declared. */ + public static final String[] names; + + static { + names = new String[values().length]; + for(GuiPosition position : values()){ + names[position.ordinal()] = position.name; + } + } + + /** The readable name for this GUI position that will be displayed on the button in the config GUI. */ + public final String name; + + GuiPosition(String name){ + this.name = name; + } + + /** Gets a GUI position from its string name (ignoring case), or BOTTOM_LEFT if the given name is not a valid position. */ + public static GuiPosition fromName(String name){ + + for(GuiPosition position : values()){ + if(position.name.equalsIgnoreCase(name)) return position; + } + + Wizardry.logger.info("Invalid string for the spell HUD position. Using default (bottom left) instead."); + return BOTTOM_LEFT; + } + + } + + // As of Wizardry 1.1, all keys used in the config file itself are now hardcoded, not localised. The localisations + // are done in the config GUI. The config file has to be written in one language or it will end up with multiple + // options for different languages. + + // These methods are package-protected to stop anyone else from calling them. + + /** Called from preInit to initialise the config file. The first part of the config file has to be done here (as is + * conventional) so that the various registries can change what they do accordingly. The spell part of the config + * has to be done in the init method.*/ + void initConfig(FMLPreInitializationEvent event){ + + config = new Configuration(event.getSuggestedConfigurationFile()); + config.load(); + + Wizardry.logger.info("Setting up main config"); + + setupGeneralConfig(); + + config.save(); + } + + /** Called from init to initialise the parts of the config file that depend on other mods. For example, the spell + * config is done here and not in preInit because all spells must be registered before it is added, including + * those in other mods. */ + void initConfigExtras(){ + + Wizardry.logger.info("Setting up spells config for " + Spell.getTotalSpellCount() + " spells"); + + setupSpellsConfig(); + + config.save(); + } + + /** Called to save changes to the config file after it has been edited in game from the menus. */ + void saveConfigChanges(){ + + Wizardry.logger.info("Saving in-game config changes"); + + setupGeneralConfig(); + setupSpellsConfig(); + + config.save(); + } + + /** Sends a packet to the specified player's client containing all the synchronised settings. */ + public void sync(EntityPlayerMP player){ + Wizardry.logger.info("Synchronising config settings for " + player.getName()); + IMessage message = new PacketSyncSettings.Message(this); + WizardryPacketHandler.net.sendTo(message, player); + } + + public ConfigCategory getConfigCategory(String name){ + return config.getCategory(name); + } + + private void setupSpellsConfig(){ + + config.addCustomCategoryComment(SPELLS_CATEGORY, "Set a spell to false to disable it. Disabled spells will still have their associated spell book (mainly so the spell books don't all change) and can still be bound to wands, but cannot be cast in game, will not appear in any subsequently generated chests or wizard trades and will not drop from mobs. Disable a spell if it is causing problems, conflicts with another mod or creates an unintended exploit."); + + Property property; + + for(Spell spell : Spell.getSpells(Spell.allSpells)){ + property = config.get(SPELLS_CATEGORY, spell.getRegistryName().toString(), true, + I18n.translateToLocal("spell." + spell.getUnlocalisedName() + ".desc")); + // Uses the same config key as the spell name, because - well, that's what it's called! + property.setLanguageKey("spell." + spell.getUnlocalisedName()); + spell.setEnabled(property.getBoolean()); + } + + } + + private void setupGeneralConfig(){ + + // This trick is borrowed from forge; it sorts the config options into the order you want them. + List propOrder = new ArrayList(); + + Property property; + + config.addCustomCategoryComment(Configuration.CATEGORY_GENERAL, "Please note that changing some of these settings may make the mod very difficult to play."); + + property = config.get(Configuration.CATEGORY_GENERAL, "towerRarity", 8, "Rarity of wizard towers. Higher numbers are rarer. Set to 0 to disable wizard towers completely.", 0, 50); + property.setLanguageKey("config.wizardry.tower_rarity"); + property.setRequiresWorldRestart(true); + Wizardry.proxy.setToNumberSliderEntry(property); + towerRarity = property.getInt(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "spellBookDropChance", 3, "The chance for mobs to drop a spell book when killed. The greater this number, the more often they will drop. Set to 0 to disable spell book drops. Set to 200 for guaranteed drops.", 0, 200); + property.setLanguageKey("config.wizardry.spell_book_drop_chance"); + Wizardry.proxy.setToNumberSliderEntry(property); + spellBookDropChance = property.getInt(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "oreDimensions", new int[]{0}, "List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!"); + property.setLanguageKey("config.wizardry.ore_dimensions"); + property.setRequiresWorldRestart(true); + oreDimensions = property.getIntList(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "flowerDimensions", new int[]{0}, "List of dimension ids in which crystal flowers will generate."); + property.setLanguageKey("config.wizardry.flower_dimensions"); + property.setRequiresWorldRestart(true); + flowerDimensions = property.getIntList(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate."); + property.setLanguageKey("config.wizardry.tower_dimensions"); + property.setRequiresWorldRestart(true); + towerDimensions = property.getIntList(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "generateLoot", true, "Whether to generate wizardry loot in dungeon chests."); + property.setLanguageKey("config.wizardry.generate_loot"); + property.setRequiresWorldRestart(true); + generateLoot = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "firebombIsCraftable", true, "Whether firebombs can be crafted or not."); + property.setLanguageKey("config.wizardry.firebomb_is_craftable"); + property.setRequiresMcRestart(true); + firebombIsCraftable = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "poisonBombIsCraftable", true, "Whether poison bombs can be crafted or not."); + property.setLanguageKey("config.wizardry.poison_bomb_is_craftable"); + property.setRequiresMcRestart(true); + poisonBombIsCraftable = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "smokeBombIsCraftable", true, "Whether smoke bombs can be crafted or not."); + property.setLanguageKey("config.wizardry.smoke_bomb_is_craftable"); + property.setRequiresMcRestart(true); + smokeBombIsCraftable = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "useAlternateScrollRecipe", false, "Whether to require a magic crystal in the shapeless crafting recipe for blank scrolls. Set to true if another mod adds a conflicting recipe."); + property.setLanguageKey("config.wizardry.use_alternate_scroll_recipe"); + property.setRequiresMcRestart(true); + useAlternateScrollRecipe = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "teleportThroughUnbreakableBlocks", false, "Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell."); + property.setLanguageKey("config.wizardry.teleport_through_unbreakable_blocks"); + teleportThroughUnbreakableBlocks = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "showSummonedCreatureNames", true, "Whether to show summoned creatures' names and owners above their heads."); + property.setLanguageKey("config.wizardry.show_summoned_creature_names"); + showSummonedCreatureNames = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "friendlyFire", true, "Whether to allow players to damage their designated allies using magic."); + property.setLanguageKey("config.wizardry.friendly_fire"); + friendlyFire = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "telekineticDisarmament", true, "Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items."); + property.setLanguageKey("config.wizardry.telekinetic_disarmament"); + telekineticDisarmament = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "discoveryMode", true, "For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false."); + property.setLanguageKey("config.wizardry.discovery_mode"); + property.setRequiresWorldRestart(true); + discoveryMode = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "enableShiftScrolling", true, "Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings."); + property.setLanguageKey("config.wizardry.enable_shift_scrolling"); + property.setRequiresWorldRestart(false); + enableShiftScrolling = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "minionRevengeTargeting", true, "Whether summoned creatures can revenge attack their owner if their owner attacks them."); + property.setLanguageKey("config.wizardry.minion_revenge_targeting"); + property.setRequiresWorldRestart(false); + minionRevengeTargeting = property.getBoolean(); + propOrder.add(property.getName()); + + // These two aren't sliders because using a slider makes it difficult to fine-tune the numbers; the nature of a + // scaling factor means that 0.5 is as big a change as 2.0, so whilst a slider is fine for increasing the damage, + // it doesn't give fine enough control for values less than 1. + property = config.get(Configuration.CATEGORY_GENERAL, "playerDamageScaling", 1.0, "Global damage scaling factor for the damage dealt by players casting spells, relative to 1.", 0, 20); + property.setLanguageKey("config.wizardry.player_damage_scaling"); + playerDamageScale = property.getDouble(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "npcDamageScaling", 1.0, "Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1.", 0, 20); + property.setLanguageKey("config.wizardry.npc_damage_scaling"); + npcDamageScale = property.getDouble(); + propOrder.add(property.getName()); + + // This one isn't a slider either because people are likely to want exact values ("it must be at most 50.3" is a bit strange!). + property = config.get(Configuration.CATEGORY_GENERAL, "castCommandMultiplierLimit", 20.0, "Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned!", 1, 255); + property.setLanguageKey("config.wizardry.cast_command_multiplier_limit"); + maxSpellCommandMultiplier = property.getDouble(); + propOrder.add(property.getName()); + + property = config.get(Configuration.CATEGORY_GENERAL, "summonedCreatureTargetsWhitelist", new String[0], "List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard)."); + property.setLanguageKey("config.wizardry.summoned_creature_targets_whitelist"); + property.setRequiresWorldRestart(true); + //Wizardry.proxy.setToEntityNameEntry(property); + summonedCreatureTargetsWhitelist = property.getStringList(); + // Converts all strings in the list to lower case, to ignore case sensitivity, and trims them. + for(int i=0; i propOrder1 = new ArrayList(); + + config.addCustomCategoryComment(RESISTANCES_CATEGORY, "Settings which allow entities to be made immune to certain types of magic. In multiplayer, the server/LAN host settings will apply."); + + property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToFire", new String[]{}, "List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard)."); + property.setLanguageKey("config.wizardry.mobs_immune_to_fire"); + property.setRequiresMcRestart(true); + //Wizardry.proxy.setToEntityNameEntry(property); + // Converts all strings in the list to lower case, to ignore case sensitivity, and trims them. + for(int i=0; i randomNames = new HashMap(Spell.getTotalSpellCount()); + public Map randomDescriptions = new HashMap(Spell.getTotalSpellCount()); + + // Required constructors + public SpellGlyphData() { + this(NAME); + } + + public SpellGlyphData(String name){ + super(name); + } + + /** Generates random names and descriptions for any spells which don't already have them. */ + public void generateGlyphNames(World world){ + + for(Spell spell : Spell.getSpells(Spell.allSpells)){ + if(!randomNames.containsKey(spell)) randomNames.put(spell, generateRandomName(world.rand)); + } + + for(Spell spell : Spell.getSpells(Spell.allSpells)){ + if(!randomDescriptions.containsKey(spell)) randomDescriptions.put(spell, generateRandomDescription(world.rand)); + } + + this.markDirty(); + } + + private String generateRandomName(Random random){ + + String name = ""; + + for(int i=0; i names = new ArrayList(); + List descriptions = new ArrayList(); + + for(Spell spell : Spell.getSpells(Spell.allSpells)){ + names.add(this.randomNames.get(spell)); + descriptions.add(this.randomDescriptions.get(spell)); + } + + PacketGlyphData.Message msg = new PacketGlyphData.Message(names, descriptions); + + WizardryPacketHandler.net.sendTo(msg, player); + + } + + /** Helper method to retrieve the random glyph name for the given spell from the map stored in the given world. */ + public static String getGlyphName(Spell spell, World world){ + Map names = SpellGlyphData.get(world).randomNames; + return names == null ? "" : names.get(spell); + } + + /** Helper method to retrieve the random glyph description for the given spell from the map stored in the given world. */ + public static String getGlyphDescription(Spell spell, World world){ + Map descriptions = SpellGlyphData.get(world).randomDescriptions; + return descriptions == null ? "" : descriptions.get(spell); + } + + @Override + public void readFromNBT(NBTTagCompound nbt){ + + this.randomNames = new HashMap(); + this.randomDescriptions = new HashMap(); + + NBTTagList tagList = nbt.getTagList("spellGlyphData", NBT.TAG_COMPOUND); + + for(int i=0; i + * Forge seems to have separate classes to hold the Capability<...> instance ('key') and + * methods for getting the capability, but in my opinion there are already too many classes to deal with, so I'm not + * adding any more than are necessary, meaning those constants and values are kept here instead. + * @since Wizardry 1.2 + * @author Electroblob */ +// On the plus side, having to rethink this class allowed me to clean it up a lot. +public class WizardData implements INBTSerializable { + + /** Static instance of what I like to refer to as the capability key. Private because, well, it's internal! */ + // This annotation does some crazy Forge magic behind the scenes and assigns this field a value. + @CapabilityInject(WizardData.class) + private static final Capability WIZARD_DATA_CAPABILITY = null; + + private final EntityPlayer player; + + // This one is still necessary, because I can't override the equip animation for items that aren't from Wizardry. + private Map imbuementDurations; + + public boolean hasSpiritWolf; + public boolean hasSpiritHorse; + + /** Whether this player is currently casting a continuous spell via commands. Not saved over world reload + * and reset on player death. */ + private Spell currentlyCasting; + /** The time for which this player has been casting a continuous spell via commands. Increments by 1 each tick. + * Not saved over world reload and reset on player death. */ + private int castingTick; + /** SpellModifiers object for the current continuous spell cast via commands. Not saved over world reload and + * reset on player death. */ + private SpellModifiers spellModifiers; + /** Coordinates for the saved transportation stone circle location. Will be null if no location is saved. */ + private BlockPos stoneCircleLocation; + /** Dimension id which the saved stone circle is in. */ + private int stoneCircleDimension; + /** Time left until the player teleports under the effect of transportation */ + private int tpCountdown; + + /** Coordinates for the saved clairvoyance location. Will be null if no location is saved. */ + private BlockPos clairvoyanceLocation; + /** Dimension id which the saved clairvoyance point is in. */ + private int clairvoyanceDimension; + + public EntityShield shield; + + public WeakReference selectedMinion; + + /** Set of this player's discovered spells. Do not write to this list directly, use + * {@link WizardData#discoverSpell(Spell)} instead. */ + public Set spellsDiscovered; + + private Set allies; + /** List of usernames of this player's allies. May not be accurate 100% of the time. This is here so that a player + * can view the usernames of their allies even when those allies are not online. + * Do not use this for any other purpose than displaying the names! */ + public Set allyNames; + + private Set soulboundCreatures; + + public WizardData(EntityPlayer player){ + this.player = player; + this.imbuementDurations = new HashMap(); + this.spellsDiscovered = new HashSet(); + // All players can recognise magic missile. This is not done using discoverSpell because that seems to cause + // a crash on load occasionally (probably something to do with achievements being initalised) + this.spellsDiscovered.add(Spells.magic_missile); + this.hasSpiritWolf = false; + this.hasSpiritHorse = false; + this.currentlyCasting = Spells.none; + this.spellModifiers = new SpellModifiers(); + this.castingTick = 0; + this.stoneCircleDimension = 0; + this.clairvoyanceDimension = 0; + this.setTpCountdown(0); + this.allies = new HashSet(); + this.allyNames = new HashSet(); + this.soulboundCreatures = new HashSet(); + } + + public boolean hasSpellBeenDiscovered(Spell spell){ + return spellsDiscovered.contains(spell) || spell instanceof None; + } + + /** + * Adds the given spell to the list of discovered spells for this player. Automatically takes into account + * whether the spell has been discovered. Use this method rather than adding directly to the list because it + * handles achievements. + * @param spell The spell to be discovered + * @return True if the spell had not already been discovered; false otherwise. + */ + public boolean discoverSpell(Spell spell){ + + if(spellsDiscovered == null){ + spellsDiscovered = new HashSet(); + } + // The 'none' spell cannot be discovered + if(spell instanceof None) return false; + // Tries to add the spell to the list of discovered spells, and returns false if it was already present + if(!spellsDiscovered.add(spell)) return false; + // If the spell had not already been discovered, achievements can be triggered and the method returns true + if(spellsDiscovered.containsAll(Spell.getSpells(Spell::isEnabled))){ + this.player.addStat(WizardryAchievements.all_spells); + } + + for(Element element : Element.values()){ + if(element != Element.MAGIC && spellsDiscovered.containsAll(Spell.getSpells(new Spell.TierElementFilter(null, element)))){ + this.player.addStat(WizardryAchievements.element_master); + } + } + + return true; + } + + /** Sets the player's saved transportation stone location and dimension. */ + public void setStoneCircleLocation(BlockPos pos, int dimensionID){ + this.stoneCircleLocation = pos; + this.stoneCircleDimension = dimensionID; + } + + /** Returns the coordinates of the associated player's saved transportation stone circle. */ + public BlockPos getStoneCircleLocation(){ return stoneCircleLocation; } + /** Returns the dimension ID of the associated player's saved transportation stone circle. */ + public int getStoneCircleDimension(){ return stoneCircleDimension; } + + public int getTpCountdown() { return tpCountdown; } + + public void setTpCountdown(int tpCountdown) { this.tpCountdown = tpCountdown; } + + /** Sets the player's saved clairvoyance location. */ + public void setClairvoyancePoint(BlockPos pos, int dimensionID){ + this.clairvoyanceLocation = pos; + this.clairvoyanceDimension = dimensionID; + } + + /** Returns the coordinates for the saved clairvoyance location. Will be null if no location is saved. */ + public BlockPos getClairvoyanceLocation(){ return clairvoyanceLocation; } + + /** Returns the dimension ID for the saved clairvoyance location. Will be null if no location is saved. */ + public int getClairvoyanceDimension(){ return clairvoyanceDimension; } + + /** Overwrites the imbuement duration associated with the given imubement for this player, or creates it if there + * was none previously. + * @throws IllegalArgumentException if the given {@link Enchantment} is not an {@link Imbuement}. */ + public void setImbuementDuration(Enchantment enchantment, int duration){ + // It is best to throw an exception here, because otherwise the error would either go unnoticed (if non-imbuements + // were ignored) or cause a ClassCastException later (if non-imbuements were allowed to be added). + if(enchantment instanceof Imbuement){ + this.imbuementDurations.put((Imbuement) enchantment, duration); + }else{ + throw new IllegalArgumentException("Attempted to set an imbuement duration for something that isn't an Imbuement! (This exception has been thrown now to prevent a ClassCastException from occurring later.)"); + } + } + + /** Returns the imbuement duration associated with the given imbuement for this player, or 0 if it does not exist. */ + public int getImbuementDuration(Enchantment enchantment){ + // Need to check that i is not null, otherwise it throws an NPE when Java auto-unboxes it. + // What's nice here is that the map simply accepts objects as keys, so there's no need to cast or throw exceptions. + Integer i = this.imbuementDurations.get(enchantment); + // If i is null, returns 0; otherwise returns i, auto-unboxed to an int. + return i == null ? 0 : i; + } + + /** Decrements the duration for each conjured item by 1, and removes from the map any that are 0 or less or that + * the player no longer has. Also deletes the item from the player's inventory if it runs out of time. */ + private void updateImbuedItems(){ + + Set activeImbuements = new HashSet(); + + // For each item in the player's inventory + for(ItemStack stack : player.inventory.mainInventory){ + if(stack != null && stack.isItemEnchanted()){ + + Map enchantments = EnchantmentHelper.getEnchantments(stack); + + Iterator> iterator = enchantments.entrySet().iterator(); + // For each of the item's enchantments + while(iterator.hasNext()){ + Enchantment enchantment = iterator.next().getKey(); + // Ignores the enchantment unless it is an imbuement + if(enchantment instanceof Imbuement){ + int duration = this.getImbuementDuration(enchantment); + // If the imbuement is still active: + if(duration > 0){ + // Decrements the timer + this.imbuementDurations.put((Imbuement)enchantment, duration-1); + // Adds this imbuement to the set of imbuements that need to be kept + activeImbuements.add((Imbuement)enchantment); + // Otherwise: + }else{ + // Removes the enchantment from the enchantment map + iterator.remove(); + // Applies the new enchantment map to the item + EnchantmentHelper.setEnchantments(enchantments, stack); + } + } + } + } + } + // Removes all imbuements from the map that are no longer active + this.imbuementDurations.keySet().retainAll(activeImbuements); + } + + /** Adds the given player to the list of allies belonging to the associated player, or removes the player if + * they are already in the list of allies. Returns true if the player was added, false if they were removed. */ + public boolean toggleAlly(EntityPlayer player){ + if(this.isPlayerAlly(player)){ + this.allies.remove(player.getUniqueID()); + // The remove method uses .equals() rather than == so this will work fine. + this.allyNames.remove(player.getName()); + return false; + }else{ + this.allies.add(player.getUniqueID()); + this.allyNames.add(player.getName()); + return true; + } + } + + /** Returns whether the given player is in this player's list of allies, or is on the same team as this player. */ + public boolean isPlayerAlly(EntityPlayer player){ + return this.allies.contains(player.getUniqueID()) || this.player.isOnSameTeam(player); + } + + /** Adds the given entity to this player's list of soulbound creatures, and returns whether it succeeded. */ + public boolean soulbind(EntityLivingBase target){ + return this.soulboundCreatures.add(target.getUniqueID()); + } + + /** Returns whether the given entity has been soulbound to this player. */ + public boolean isCreatureSoulbound(EntityPlayer target){ + return this.soulboundCreatures.contains(target.getUniqueID()); + } + + /** Damages all creatures soulbound to this player by the given amount, and removes from the list any that no + * longer exist. */ + public void damageAllSoulboundCreatures(float damage){ + + for(Iterator iterator = this.soulboundCreatures.iterator(); iterator.hasNext();){ + + Entity entity = WizardryUtilities.getEntityByUUID(this.player.worldObj, iterator.next()); + + if(entity == null) iterator.remove(); + + if(entity instanceof EntityLivingBase){ + // Retaliatory effect + if(entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(this.player, DamageType.MAGIC, true), damage)){ + // Sound only plays if the damage succeeds + player.playSound(SoundEvents.ENTITY_WITHER_HURT, 1.0F, player.worldObj.rand.nextFloat() * 0.2F + 1.0F); + } + } + } + } + + /** Starts casting the given spell with the given modifiers. */ + public void startCastingContinuousSpell(Spell spell, SpellModifiers modifiers){ + + this.currentlyCasting = spell; + this.spellModifiers = modifiers; + + if(!this.player.worldObj.isRemote){ + PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(), + spell.id(), this.spellModifiers); + WizardryPacketHandler.net.sendToDimension(message, this.player.worldObj.provider.getDimension()); + } + } + + /** Stops casting the current spell. */ + public void stopCastingContinuousSpell(){ + + this.currentlyCasting = Spells.none; + this.castingTick = 0; + this.spellModifiers.reset(); + + if(!this.player.worldObj.isRemote){ + PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(), + Spells.none.id(), this.spellModifiers); + WizardryPacketHandler.net.sendToDimension(message, this.player.worldObj.provider.getDimension()); + } + } + + /** Returns whether this player is currently casting a continuous spell via commands. */ + public boolean isCasting(){ + return this.currentlyCasting != null && this.currentlyCasting != Spells.none; + } + + /** Returns the continuous spell this player is currently casting via commands, or the 'none' spell if they aren't + * casting anything. */ + public Spell currentlyCasting(){ + return currentlyCasting; + } + + /** Called from the event handler each time the associated player is updated. */ + public void update(){ + + if(this.selectedMinion != null && this.selectedMinion.get() == null) this.selectedMinion = null; + + // This new system removes a lot of repetitive event handler code and inflexible variables which had duplicate + // functions, just for different enchantments. + updateImbuedItems(); + + if(!player.worldObj.isRemote){ + if(getTpCountdown() == 1){ + player.setPositionAndUpdate(this.stoneCircleLocation.getX() + 0.5, this.stoneCircleLocation.getY(), + this.stoneCircleLocation.getZ() + 0.5); + player.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, 50, 0)); + IMessage msg = new PacketTransportation.Message(player.getEntityId()); + WizardryPacketHandler.net.sendToDimension(msg, player.worldObj.provider.getDimension()); + } + + if(getTpCountdown() > 0){ + setTpCountdown(getTpCountdown() - 1); + } + } + + if(this.currentlyCasting != null && this.currentlyCasting.isContinuous){ + this.currentlyCasting.cast(player.worldObj, player, EnumHand.MAIN_HAND, castingTick++, this.spellModifiers); + }else{ + this.castingTick = 0; + } + } + + /** + * Returns the WizardData instance for the specified player. + */ + public static final WizardData get(EntityPlayer player){ + return player.getCapability(WIZARD_DATA_CAPABILITY, null); + } + + /** Called from the event handler each time the associated player entity is cloned, i.e. on respawn or when + * travelling to a different dimension. Used to copy over any variables that should persist over player death. + * This is the inverse of the old onPlayerDeath method, which reset the variables that shouldn't persist. + * @param data The old WizardData whose variables are to be copied over. + * @param respawn True if the player died and is respawning, false if they are just travelling between dimensions. */ + public void copyFrom(WizardData data, boolean respawn){ + // TODO: What happens with spirit wolf and spirit horse? + this.hasSpiritHorse = data.hasSpiritHorse; + this.hasSpiritWolf = data.hasSpiritWolf; + this.allies = data.allies; + this.allyNames = data.allyNames; + this.clairvoyanceDimension = data.clairvoyanceDimension; + this.clairvoyanceLocation = data.clairvoyanceLocation; + this.selectedMinion = data.selectedMinion; + // Curse of soulbinding is lifted when the caster dies, but not when they switch dimensions. + if(!respawn) this.soulboundCreatures = data.soulboundCreatures; + this.spellsDiscovered = data.spellsDiscovered; + this.stoneCircleDimension = data.stoneCircleDimension; + this.stoneCircleLocation = data.stoneCircleLocation; + + // Imbuements are lost on death so their durations do not persist. + // Command spell casting is reset on death so the associated variables do not persist. + // tpCountdown is reset both when the player dies and when they switch dimensions. + + } + + /** Sends a packet to this player's client to synchronise necessary information. Only called server side. */ + public void sync(){ + if(this.player instanceof EntityPlayerMP){ + int id = -1; + if(this.selectedMinion != null && this.selectedMinion.get() instanceof Entity) id = ((Entity)this.selectedMinion.get()).getEntityId(); + IMessage msg = new PacketPlayerSync.Message(this.spellsDiscovered, id); + WizardryPacketHandler.net.sendTo(msg, (EntityPlayerMP)this.player); + } + } + + @Override + public NBTTagCompound serializeNBT() { + + NBTTagCompound properties = new NBTTagCompound(); + + // ...so Java 8 allows you to do stuff like this: + properties.setTag("imbuements", WizardryUtilities.mapToNBT(this.imbuementDurations, + imbuement -> new NBTTagInt(Enchantment.getEnchantmentID((Enchantment)imbuement)), NBTTagInt::new)); + + properties.setBoolean("hasSpiritWolf", this.hasSpiritWolf); + properties.setBoolean("hasSpiritHorse", this.hasSpiritHorse); + + if(this.stoneCircleLocation != null) properties.setLong("stoneCircleLocation", this.stoneCircleLocation.toLong()); + properties.setInteger("stoneCircleDimension", this.stoneCircleDimension); + properties.setInteger("tpCountdown", this.tpCountdown); + + if(this.clairvoyanceLocation != null) properties.setLong("clairvoyanceLocation", this.clairvoyanceLocation.toLong()); + properties.setInteger("clairvoyanceDimension", this.getClairvoyanceDimension()); + + // THIS is why I wrote the list/map <-> NBT methods. Look how neat this is! + properties.setTag("allies", WizardryUtilities.listToNBT(this.allies, WizardryUtilities::UUIDtoTagCompound)); + properties.setTag("allyNames", WizardryUtilities.listToNBT(this.allyNames, NBTTagString::new)); + properties.setTag("soulboundCreatures", WizardryUtilities.listToNBT(this.soulboundCreatures, WizardryUtilities::UUIDtoTagCompound)); + + // Might be worth converting this over to WizardryUtilities.listToNBT. + int[] spells = new int[this.spellsDiscovered.size()]; + int i=0; + for(Spell spell : this.spellsDiscovered){ + spells[i] = spell.id(); + i++; + } + properties.setIntArray("discoveredSpells", spells); + + return properties; + } + + @Override + public void deserializeNBT(NBTTagCompound nbt) { + + if(nbt != null){ + + this.imbuementDurations = WizardryUtilities.NBTToMap(nbt.getTagList("imbuements", NBT.TAG_COMPOUND), + (NBTTagInt tag) -> (Imbuement)Enchantment.getEnchantmentByID(tag.getInt()), NBTTagInt::getInt); + + this.hasSpiritWolf = nbt.getBoolean("hasSpiritWolf"); + this.hasSpiritHorse = nbt.getBoolean("hasSpiritHorse"); + + this.stoneCircleLocation = BlockPos.fromLong(nbt.getLong("stoneCircleLocation")); + this.stoneCircleDimension = nbt.getInteger("stoneCircleDimension"); + this.tpCountdown = nbt.getInteger("tpCountdown"); + + this.clairvoyanceLocation = BlockPos.fromLong(nbt.getLong("clairvoyanceLocation")); + this.clairvoyanceDimension = nbt.getInteger("clairvoyanceDimension"); + + this.allies = new HashSet(WizardryUtilities.NBTToList(nbt.getTagList("allies", NBT.TAG_COMPOUND), + WizardryUtilities::tagCompoundToUUID)); + + this.allyNames = new HashSet(WizardryUtilities.NBTToList(nbt.getTagList("allyNames", NBT.TAG_STRING), + NBTTagString::getString)); + + this.soulboundCreatures = new HashSet(WizardryUtilities.NBTToList(nbt.getTagList("soulboundCreatures", NBT.TAG_COMPOUND), + WizardryUtilities::tagCompoundToUUID)); + + this.spellsDiscovered = new HashSet(); + for(int id : nbt.getIntArray("discoveredSpells")){ + spellsDiscovered.add(Spell.get(id)); + } + } + } + + /** This is a nested class for a few reasons: firstly, it makes sense because instances of this and WizardData go + * hand-in-hand; secondly, it's too short to be worth a separate file; and thirdly (and most importantly) it allows + * me to access WIZARD_DATA_CAPABILITY while keeping it private. */ + public static class Provider implements ICapabilitySerializable { + + private final WizardData data; + + public Provider(EntityPlayer player){ + data = new WizardData(player); + } + + @Override + public boolean hasCapability(Capability capability, EnumFacing facing) { + return capability == WIZARD_DATA_CAPABILITY; + } + + @Override + public T getCapability(Capability capability, EnumFacing facing) { + + if(capability == WIZARD_DATA_CAPABILITY){ + return WIZARD_DATA_CAPABILITY.cast(data); + } + + return null; + } + + @Override + public NBTTagCompound serializeNBT() { + return data.serializeNBT(); + } + + @Override + public void deserializeNBT(NBTTagCompound nbt) { + data.deserializeNBT(nbt); + } + + } + + // Ended up deleting IWizardData because it was unnecessary. This is the comment that was at the start of it: + + /* I'm not going to lie, I will never find the capabilities system even remotely intuitive so this is a bare-minimum + * approach just to get things working (four classes where one would have done?!) At one point I considered simply + * wrapping my old IEEP inside a single-field capability, but I eventually decided I would at least *try* to do it + * properly. + * + * "...without having to directly implement many interfaces." - Forge Docs. I still can't see what's wrong with + * implementing many interfaces; surely that's what Java interfaces are designed for? + * + * Other things I find annoying: + * - IStorage. It's completely redundant in the majority of cases, and I don't understand why we need yet another + * separate class. + * - Making an interface, only to implement it once and once only. This completely defeats the point of interfaces. + * - The EnumFacing parameter, which is again redundant for everything that isn't a tile entity. So much for a clean, + * neat system. + * + * What Forge has effectively done is conflated two different functions: attaching data to stuff and cross-mod + * integration/soft dependencies. I think this is bad design; it would have been better to keep the two features separate. + * + * Here's my current understanding of how the capability system works: + * - You make an interface which defines the things your capability can do (this class). I will call this the TEMPLATE. + * - You implement that interface with your default implementation (WizardData). This is the closest analog to your old + * IEEP implementation class. THIS CLASS STORES ALL THE VARIABLES, and hence has one instance for each instance of whatever + * it is attached to. I will call this the DATA. + * - The DATA class implements INBTSerializable (assuming you want it to be saved, which is nearly always the case) + * - Despite its name, Capability does NOT represent a capability itself. Instead, it acts as a sort of identifier/key, + * the idea being that you can access a particular instance of your DATA given the key (which tells forge that you want a + * capability of type TEMPLATE) and the object you want the DATA for. This is what Entity.getCapability(...) does. + * + * To really understand what's going on though, you need to sift through Forge's verbose data structures and find where + * capabilities are actually hooked into vanilla: + * - Anything that implements ICapabilityProvider will have a private CapabilityDispatcher field. This holds other + * ICapabilityProviders. (I know. This inheritance pattern DOES NOT MAKE SENSE, because these could, in theory, be OTHER + * ENTITIES!) + * - This field is assigned a value through Forge's event factory, which, as we are all familiar with, calls all the + * methods marked with @SubscribeEvent. These methods add individual ICapabilityProviders to a Map stored in the event, + * which the event factory then wraps in a CapabilityDispatcher (which is itself an ICapabilityProvider) for the object + * that called it. + * - In your event handler, you return a custom ICapabilityProvider which is effectively bolted on to the player, and + * duplicates the ICapabilityProvider methods so you can hook into them and return an instance of your DATA class. + * - Where before there was a simple collection of IEEPs stored in the player, there is now a tree of ICapabilityProviders: + * + * - Entity/TileEntity/ItemStack + * - Vanilla ICapabilityProviders, mostly IItemHandlers, stored as fields. + * - CapabilityDispatcher, stored as a field. + * - Custom ICapabilityProviders + * - Custom CapabilityDispatchers + * - ... + * + * Most importantly, EACH PLAYER HOLDS THEIR OWN INSTANCE OF THIS TREE. + * + * When a capability is retrieved, the following process happens: + * 1. For the Entity/TileEntity/ItemStack instance, ICapabilityProvider.getCapability(...) is called. + * 2. The request propogates through the tree and finds the requested capability. */ + +} diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java new file mode 100644 index 00000000..9e30a715 --- /dev/null +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -0,0 +1,265 @@ +package electroblob.wizardry; + +import org.apache.logging.log4j.Logger; + +import electroblob.wizardry.command.CommandCastSpell; +import electroblob.wizardry.command.CommandDiscoverSpell; +import electroblob.wizardry.command.CommandSetAlly; +import electroblob.wizardry.command.CommandViewAllies; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryRegistry; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.item.Item; +import net.minecraft.nbt.NBTBase; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.AchievementPage; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.Capability.IStorage; +import net.minecraftforge.common.capabilities.CapabilityManager; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.Mod.Instance; +import net.minecraftforge.fml.common.SidedProxy; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.event.FMLServerStartingEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.common.registry.GameRegistry; +import net.minecraftforge.fml.common.registry.GameRegistry.Type; + +@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, guiFactory = "electroblob." + Wizardry.MODID + ".WizardryGuiFactory") +public class Wizardry { + + /** Wizardry's mod ID. */ + public static final String MODID = "wizardry"; + /** Wizardry's mod name, in readable form. */ + public static final String NAME = "Electroblob's Wizardry"; + /** The version number for this version of wizardry. The following system is used for version numbers: + *

    [major Minecraft version].[major mod version].[minor mod version/patch]

    + * The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same features as + * Wizardry 2.1, but they are for different versions of Minecraft and have separate minor versioning. 1.x.x + * represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft + * 1.11.x versions, and so on. */ + public static final String VERSION = "2.1.0"; + + // IDEA: Improve the algorithm that finds a place to summon creatures to take walls into account. + // IDEA: Replace all uses of Math.cos and Math.sin with MathHelper versions + // IDEA: API feature that automatically injects custom wand upgrades into wizardry's loot tables + // IDEA: Support for the @e selector in the /cast command (the methods already exist, just plug them in) + // IDEA: Dispensers shooting spells from scrolls! Imagine the possibilities! + // == Rendering overhaul! == + // IDEA: Make spirit animals fade away when dispelled + // IDEA: Use your newfound knowledge of OpenGL to render animated boxes around entities being buffed, similar to creeper charge + // IDEA: Redo RenderArc so it looks like lightning (it's literally a load of translucent boxes inside each other) + // IDEA: The arcane workbench could use a few particles + // IDEA: Add a box to the wizard armour model so that the robes bend when the wearer is sneaking + // IDEA: Flash particle (I think it exists in vanilla somewhere) on spell impact + // IDEA: Dust particles spray out from projectiles as they move + // IDEA: Colour fading for particles + // IDEA: Make lightning and other effects particles. There's no reason why you can't pass in a player argument and have the particles move with them! + + /* Minor bugs that need fixing at some point: + * - Player skin hat layer shows through wizard hats + * - Wizard armour breaks rather than just running out of mana (I can't seem to replicate this bug, but I have had + * it happen to me before...) + * - Shift-clicking a stack of special upgrades when in the arcane workbench causes the whole stack to be + * transferred when it should be just one (this is a bug with vanilla as well - try putting a stack of bottles into + * a brewing stand). I have at least made it so only one gets used now, so it has no impact on the game. + * - When a spell is on cooldown, you can't break blocks when holding a wand. */ + + // FIXME: Wizardry enchantments appear on enchanted books in dungeon chests when they shouldn't. + + // TODO: So somehow I have managed to overlook the fact that health is actually a float. What this means is that + // I can make the healing spells use damage multipliers - hurrah! + + // TODO: Switch from IInventory to IItemHandler (Or don't. It's only useful for automation really.) + // TODO: Triggering of inbuilt Forge events in relevant places? + // TODO: Implement custom events + // TODO: Rearrange the config gui and file + + // TODO: Have particles obey Minecraft's particle setting where appropriate + // (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java) + + // NOTE: Add melee upgrades to loot tables when they are added. + + /** Static instance of the {@link Settings} object for Wizardry. */ + public static final Settings settings = new Settings(); + + /** Static instance of the {@link Logger} object for Wizardry. */ + public static Logger logger; + + //private static Pattern entityNamePattern; + + // EventManager + WizardryWorldGenerator generator = new WizardryWorldGenerator(); + + // The instance of wizardry that Forge uses. + @Instance(Wizardry.MODID) + public static Wizardry instance; + + // Location of the proxy code, used by Forge. + @SidedProxy(clientSide="electroblob.wizardry.client.ClientProxy", serverSide="electroblob.wizardry.CommonProxy") + public static CommonProxy proxy; + + @EventHandler + public void preInit(FMLPreInitializationEvent event){ + + logger = event.getModLog(); + + // The array in question no longer exists, so I'm pretty sure this isn't necessary any more. + // expandPotionTypesArray(); + + settings.initConfig(event); + + // Yes - by the looks of it, having an interface is completely unnecessary in this case. + CapabilityManager.INSTANCE.register(WizardData.class, new IStorage(){ + // These methods are only called by Capability.writeNBT() or Capability.readNBT(), which in turn are + // NEVER CALLED. Unless I'm missing some reflective invocation, that means this entire class serves only + // to allow capabilities to be saved and loaded manually. What that would be useful for I don't know. + // (If an API forces most users to write redundant code for no reason, it's not user friendly, is it?) + // ... well, that's my rant for today! + @Override public NBTBase writeNBT(Capability capability, WizardData instance, EnumFacing side){ return null; } + @Override public void readNBT(Capability capability, WizardData instance, EnumFacing side, NBTBase nbt){} + }, WizardData.class); + + WizardryRegistry.registerTileEntities(); + + WizardryRegistry.registerEntities(this); + // The check for the generateLoot setting is now done within this method. + WizardryRegistry.registerLoot(); + + // NOTE: Will need to be moved to init for 1.12, as will anything that needs to be after the registry events. + WizardryTabs.sort(); + + // Moved to preInit, because apparently it has to be here now. + proxy.registerRenderers(); + + } + + @EventHandler + public void init(FMLInitializationEvent event){ + + settings.initConfigExtras(); + + proxy.registerKeyBindings(); + + // Event Handlers + GameRegistry.registerWorldGenerator(generator, 0); + MinecraftForge.EVENT_BUS.register(new WizardryKeyHandler()); + MinecraftForge.EVENT_BUS.register(instance); + proxy.registerSpellHUD(); // This can't easily be converted to use the new @Mod.EventBusSubscriber system + NetworkRegistry.INSTANCE.registerGuiHandler(this, new WizardryGuiHandler()); + WizardryPacketHandler.initPackets(); + + // Achievements + AchievementPage.registerAchievementPage(WizardryAchievements.WIZARDRY_ACHIEVEMENT_PAGE); + + // Recipes + WizardryRegistry.registerRecipes(); + + proxy.initMixedFontRenderer(); + } + + @EventHandler + public void postInit(FMLPostInitializationEvent event){ + // This needs to be here or it won't necessarily include all the mods' entities. + // TODO: Re-implement this when the Forge bug is fixed. + /* Doesn't seem to be doing anything... + String entityNames = ""; + for(Object name : EntityList.classToStringMapping.values()){ + if(name instanceof String){ + entityNames = entityNames + name + '|'; + } + } + // Cuts off the last '|' + entityNames = entityNames.substring(0, entityNames.length()-1); + entityNamePattern = Pattern.compile(entityNames); + */ + proxy.initialiseLayers(); + } + + @EventHandler + public void serverStarting(FMLServerStartingEvent event){ + event.registerServerCommand(new CommandCastSpell()); + event.registerServerCommand(new CommandSetAlly()); + event.registerServerCommand(new CommandViewAllies()); + event.registerServerCommand(new CommandDiscoverSpell()); + } + + @SubscribeEvent + public void onConfigChanged(net.minecraftforge.fml.client.event.ConfigChangedEvent.OnConfigChangedEvent event){ + if(event.getModID().equals(Wizardry.MODID)){ + settings.saveConfigChanges(); + // All of the synchronised settings require a world restart anyway so this doesn't need syncing. + } + } + + // 2.1 changed some item ids, so this fixes them for existing worlds + // NOTE: Needs changing to RegistryEvent.MissingMapping in 1.12, or just removing since nobody updates minecraft + // versions when using mods. + @EventHandler + public static void onMissingMappingEvent(FMLMissingMappingsEvent event){ + // Just get, not getAll, since the mod id didn't change! + for(FMLMissingMappingsEvent.MissingMapping mapping : event.get()){ + if(mapping.type == Type.ITEM && mapping.resourceLocation.getResourceDomain().equals(Wizardry.MODID)){ + + Item replacement = null; + + switch(mapping.resourceLocation.getResourcePath()){ + + case "wand_basic": replacement = WizardryItems.magic_wand; break; + case "wand_basic_fire": replacement = WizardryItems.basic_fire_wand; break; + case "wand_basic_ice": replacement = WizardryItems.basic_ice_wand; break; + case "wand_basic_lightning": replacement = WizardryItems.basic_lightning_wand; break; + case "wand_basic_necromancy": replacement = WizardryItems.basic_necromancy_wand; break; + case "wand_basic_earth": replacement = WizardryItems.basic_earth_wand; break; + case "wand_basic_sorcery": replacement = WizardryItems.basic_sorcery_wand; break; + case "wand_basic_healing": replacement = WizardryItems.basic_healing_wand; break; + case "wand_apprentice": replacement = WizardryItems.apprentice_wand; break; + case "wand_apprentice_fire": replacement = WizardryItems.apprentice_fire_wand; break; + case "wand_apprentice_ice": replacement = WizardryItems.apprentice_ice_wand; break; + case "wand_apprentice_lightning": replacement = WizardryItems.apprentice_lightning_wand; break; + case "wand_apprentice_necromancy": replacement = WizardryItems.apprentice_necromancy_wand; break; + case "wand_apprentice_earth": replacement = WizardryItems.apprentice_earth_wand; break; + case "wand_apprentice_sorcery": replacement = WizardryItems.apprentice_sorcery_wand; break; + case "wand_apprentice_healing": replacement = WizardryItems.apprentice_healing_wand; break; + case "wand_advanced": replacement = WizardryItems.advanced_wand; break; + case "wand_advanced_fire": replacement = WizardryItems.advanced_fire_wand; break; + case "wand_advanced_ice": replacement = WizardryItems.advanced_ice_wand; break; + case "wand_advanced_lightning": replacement = WizardryItems.advanced_lightning_wand; break; + case "wand_advanced_necromancy": replacement = WizardryItems.advanced_necromancy_wand; break; + case "wand_advanced_earth": replacement = WizardryItems.advanced_earth_wand; break; + case "wand_advanced_sorcery": replacement = WizardryItems.advanced_sorcery_wand; break; + case "wand_advanced_healing": replacement = WizardryItems.advanced_healing_wand; break; + case "wand_master": replacement = WizardryItems.master_wand; break; + case "wand_master_fire": replacement = WizardryItems.master_fire_wand; break; + case "wand_master_ice": replacement = WizardryItems.master_ice_wand; break; + case "wand_master_lightning": replacement = WizardryItems.master_lightning_wand; break; + case "wand_master_necromancy": replacement = WizardryItems.master_necromancy_wand; break; + case "wand_master_earth": replacement = WizardryItems.master_earth_wand; break; + case "wand_master_sorcery": replacement = WizardryItems.master_sorcery_wand; break; + case "wand_master_healing": replacement = WizardryItems.master_healing_wand; break; + case "upgrade_storage": replacement = WizardryItems.storage_upgrade; break; + case "upgrade_siphon": replacement = WizardryItems.siphon_upgrade; break; + case "upgrade_condenser": replacement = WizardryItems.condenser_upgrade; break; + case "upgrade_range": replacement = WizardryItems.range_upgrade; break; + case "upgrade_duration": replacement = WizardryItems.duration_upgrade; break; + case "upgrade_cooldown": replacement = WizardryItems.cooldown_upgrade; break; + case "upgrade_blast": replacement = WizardryItems.blast_upgrade; break; + case "upgrade_attunement": replacement = WizardryItems.attunement_upgrade; break; + // If it didn't match any of the ones that changed, do nothing. + default: return; + } + // No need to log, Forge does that. + mapping.remap(replacement); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/WizardryEventHandler.java b/src/main/java/electroblob/wizardry/WizardryEventHandler.java new file mode 100644 index 00000000..8cae85ed --- /dev/null +++ b/src/main/java/electroblob/wizardry/WizardryEventHandler.java @@ -0,0 +1,938 @@ +package electroblob.wizardry; + +import java.util.List; +import java.util.Map; + +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.enchantment.Imbuement; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.entity.construct.EntityBubble; +import electroblob.wizardry.entity.construct.EntityDecay; +import electroblob.wizardry.entity.living.EntityEvilWizard; +import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.entity.living.ISpellCaster; +import electroblob.wizardry.entity.living.ISummonedCreature; +import electroblob.wizardry.item.IConjuredItem; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.item.ItemWizardArmour; +import electroblob.wizardry.potion.ICustomPotionParticles; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryEnchantments; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Clairvoyance; +import electroblob.wizardry.spell.FreezingWeapon; +import electroblob.wizardry.spell.Intimidate; +import electroblob.wizardry.spell.MindControl; +import electroblob.wizardry.spell.ShadowWard; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.IElementalDamage; +import electroblob.wizardry.util.IndirectMinionDamage; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.MinionDamage; +import electroblob.wizardry.util.WandHelper; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityCreature; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.monster.EntityCreeper; +import net.minecraft.entity.monster.IMob; +import net.minecraft.entity.passive.EntityPig; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.init.Blocks; +import net.minecraft.init.SoundEvents; +import net.minecraft.inventory.ContainerPlayer; +import net.minecraft.inventory.ContainerWorkbench; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemBow; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemSword; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EntityDamageSource; +import net.minecraft.util.EntityDamageSourceIndirect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import net.minecraft.world.storage.loot.LootEntry; +import net.minecraft.world.storage.loot.LootEntryTable; +import net.minecraft.world.storage.loot.LootPool; +import net.minecraft.world.storage.loot.RandomValueRange; +import net.minecraft.world.storage.loot.conditions.LootCondition; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.event.LootTableLoadEvent; +import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.event.entity.EntityStruckByLightningEvent; +import net.minecraftforge.event.entity.item.ItemTossEvent; +import net.minecraftforge.event.entity.living.LivingAttackEvent; +import net.minecraftforge.event.entity.living.LivingDeathEvent; +import net.minecraftforge.event.entity.living.LivingDropsEvent; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.event.entity.living.LivingHurtEvent; +import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; +import net.minecraftforge.event.entity.player.BonemealEvent; +import net.minecraftforge.event.entity.player.EntityItemPickupEvent; +import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.event.entity.player.PlayerEvent.BreakSpeed; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.world.BlockEvent; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent; + +// TODO: This class is waaaay too long. We need to either: +// - Split it into several separate handlers, each with a logical area to deal with +// - Remove most of the stuff, and have individual spell, item, block, entity, etc. classes handle their own events +// - Keep all the methods, but delegate near-repeated behaviours to their individual spell/potion/whatever classes + +/** + * Wizardry's main event handler class for common code. + * @author Electroblob + * @since Wizardry 1.0 + */ +@Mod.EventBusSubscriber +public final class WizardryEventHandler { + + @SubscribeEvent + // The type parameter here has to be Entity, not EntityPlayer, or the event won't get fired. + public static void onCapabilityLoad(AttachCapabilitiesEvent event){ + + if(event.getObject() instanceof EntityPlayer) + event.addCapability(new ResourceLocation(Wizardry.MODID, "WizardData"), new WizardData.Provider((EntityPlayer)event.getObject())); + + // This demonstrates why capabilities are badly structured: The following code compiles, but what it does is put + // a player into a CapabilityDispatcher, which is in turn stored in that very same player, which makes no sense + // at all! + //event.addCapability(new ResourceLocation(Wizardry.MODID, "WizardData"), event.getObject()); + } + + @SubscribeEvent + public static void onPlayerCloneEvent(PlayerEvent.Clone event){ + + WizardData newData = WizardData.get(event.getEntityPlayer()); + WizardData oldData = WizardData.get(event.getOriginal()); + + newData.copyFrom(oldData, event.isWasDeath()); + } + + @SubscribeEvent + public static void onWorldLoadEvent(WorldEvent.Load event){ + if(!event.getWorld().isRemote && event.getWorld().provider.getDimension() == 0){ + // Called to initialise the spell glyph data when a world loads, if it isn't already. + // NOTE: Do we actually need this, or can we just let it initialise the first time it is needed? (see below) + SpellGlyphData.get(event.getWorld()); + } + } + + // IDEA: Config option allowing users to specify loot locations + private static final String[] LOOT_INJECTION_LOCATIONS = { + "minecraft:chests/simple_dungeon", + "minecraft:chests/abandoned_mineshaft", + "minecraft:chests/desert_pyramid", + "minecraft:chests/jungle_temple", + "minecraft:chests/stronghold_corridor", + "minecraft:chests/stronghold_crossing", + "minecraft:chests/stronghold_library", + "minecraft:chests/igloo_chest" + }; + + @SubscribeEvent + public static void onLootTableLoadEvent(LootTableLoadEvent event){ + if(Wizardry.settings.generateLoot){ + for(String location : LOOT_INJECTION_LOCATIONS){ + if(event.getName().toString().matches(location)){ + event.getTable().addPool(getAdditive("wizardry:chests/dungeon_additions")); + } + } + } + } + + private static LootPool getAdditive(String entryName){ + return new LootPool(new LootEntry[] { getAdditiveEntry(entryName, 1) }, new LootCondition[0], new RandomValueRange(1), new RandomValueRange(0, 1), Wizardry.MODID + "_additive_pool"); + } + + private static LootEntryTable getAdditiveEntry(String name, int weight){ + return new LootEntryTable(new ResourceLocation(name), weight, 0, new LootCondition[0], Wizardry.MODID + "_additive_entry"); + } + + /* There is a subtle but important difference between LivingAttackEvent and LivingHurtEvent - LivingAttackEvent + * fires immediately when attackEntityFrom is called, whereas LivingHurtEvent only fires if the attack actually + * succeeded, i.e. if the entity in question takes damage (though the event is fired before that so you can cancel + * the damage). Things are processed in the following order: + * * LivingAttackEvent * + * - Invulnerability + * - Already-dead-ness + * - Fire resistance + * - Helmets vs. falling things + * - Hurt resistant time + * - Invulnerability (again) + * * LivingHurtEvent * + * - Armour + * - Potions + * - Health is finally changed + * Of course, there are no guarantees that other mods hooking into these two events will be called before or after + * yours, but you can have some degree of control by choosing which event to use. + * EDIT: Actually, there are. Firstly, you can set a priority in the @SubscribeEvent annotation which defines how + * early (higher priority) or late (lower priority) the method is called. Methods with the same priority are sorted + * alphabetically by mod id (so it's safe to assume wizardry would be fairly late on!). I wonder if there are any + * conventions for what sort of things take what priority...? */ + + @SubscribeEvent + public static void onLivingAttackEvent(LivingAttackEvent event){ + + // Rather than bother overriding entire attack methods in ISummonedCreature implementations, it's easier (and + // more robust) to use LivingAttackEvent to modify the damage source. + if(event.getSource().getEntity() instanceof ISummonedCreature){ + + EntityLivingBase summoner = ((ISummonedCreature)event.getSource().getEntity()).getCaster(); + + if(summoner != null){ + + event.setCanceled(true); + DamageSource newSource = event.getSource(); + // Copies over the original DamageType if appropriate. + DamageType type = event.getSource() instanceof IElementalDamage ? ((IElementalDamage)event.getSource()).getType() : DamageType.MAGIC; + // Copies over the original isRetaliatory flag if appropriate. + boolean isRetaliatory = event.getSource() instanceof IElementalDamage && ((IElementalDamage)event.getSource()).isRetaliatory(); + + // All summoned creatures are classified as magic, so it makes sense to do it this way. + if(event.getSource() instanceof EntityDamageSourceIndirect){ + newSource = new IndirectMinionDamage(event.getSource().damageType, event.getSource().getSourceOfDamage(), event.getSource().getEntity(), summoner, type, isRetaliatory); + }else if(event.getSource() instanceof EntityDamageSource){ + // Name is copied over so it uses the appropriate vanilla death message + newSource = new MinionDamage(event.getSource().damageType, event.getSource().getEntity(), summoner, type, isRetaliatory); + } + + // Copy over any relevant 'attributes' the original DamageSource might have had. + if(event.getSource().isExplosion()) newSource.setExplosion(); + if(event.getSource().isFireDamage()) newSource.setFireDamage(); + if(event.getSource().isProjectile()) newSource.setProjectile(); + + // For some reason Minecraft calculates knockback relative to DamageSource#getEntity. In vanilla this + // is unnoticeable, but it looks a bit weird with summoned creatures involved - so let's fix that! + if(WizardryUtilities.attackEntityWithoutKnockback(event.getEntity(), newSource, event.getAmount())){ + WizardryUtilities.applyStandardKnockback(event.getSource().getEntity(), event.getEntityLiving()); + ((ISummonedCreature)event.getSource().getEntity()).onSuccessfulAttack(event.getEntityLiving()); + } + + return; + } + } + + // Prevents any damage to allies from magic if friendly fire is enabled + if(!Wizardry.settings.friendlyFire && event.getSource() != null && event.getSource().getEntity() instanceof EntityPlayer + && event.getEntity() instanceof EntityPlayer && event.getSource() instanceof IElementalDamage){ + if(WizardryUtilities.isPlayerAlly((EntityPlayer)event.getSource().getEntity(), (EntityPlayer)event.getEntity())){ + event.setCanceled(true); + // I think this ought to be here, since if the event is cancelled nothing else needs to happen. + return; + } + } + + if(event.getSource() instanceof IElementalDamage){ + if(MagicDamage.isEntityImmune(((IElementalDamage)event.getSource()).getType(), event.getEntity())){ + event.setCanceled(true); + // I would have liked to have done the 'resist' chat message here, but I overlooked the fact that I + // would need an instance of the spell to get its display name! + return; + } + // One convenient side effect of the new damage type system is that I can get rid of all the places where + // creepers are charged and just put them here under shock damage - this is precisely the sort of + // repetitive code I was trying to get rid of, since errors can (and did!) occur. + if(event.getEntityLiving() instanceof EntityCreeper && !((EntityCreeper)event.getEntityLiving()).getPowered() + && ((IElementalDamage)event.getSource()).getType() == DamageType.SHOCK){ + // Charges creepers when they are hit by shock damage + WizardryUtilities.chargeCreeper((EntityCreeper)event.getEntityLiving()); + // Gives the player that caused the shock damage the 'It's Gonna Blow' achievement + if(event.getSource().getEntity() instanceof EntityPlayer){ + ((EntityPlayer)event.getSource().getEntity()).addStat(WizardryAchievements.charge_creeper); + } + } + } + + // Bursts bubble when the creature inside takes damage + if(event.getEntityLiving().getRidingEntity() instanceof EntityBubble && + !((EntityBubble)event.getEntityLiving().getRidingEntity()).isDarkOrb){ + event.getEntityLiving().getRidingEntity().playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f); + event.getEntityLiving().getRidingEntity().setDead(); + } + + // Prevents all unblockable damage while transience is active + if(event.getEntityLiving().isPotionActive(WizardryPotions.transience) && event.getSource() != null && !event.getSource().isUnblockable()){ + event.setCanceled(true); + // Again, I think this ought to be here, since if the event is cancelled nothing else needs to happen. + return; + } + + if(event.getSource() != null && event.getSource().getEntity() instanceof EntityLivingBase){ + + // Cancels the mind trick effect if the creature takes damage + // This has been moved to within the (event.getSource().getEntity() instanceof EntityLivingBase) check so it doesn't + // crash the game with a ConcurrentModificationException. If you think about it, mind trick only ought to be + // cancelled if something attacks the entity since potions, drowning, cacti etc. don't affect the targeting. + if(event.getEntityLiving().isPotionActive(WizardryPotions.mind_trick)){ + event.getEntityLiving().removePotionEffect(WizardryPotions.mind_trick); + } + + // 'Revenge' effects + + EntityLivingBase attacker = (EntityLivingBase)event.getSource().getEntity(); + World world = event.getEntityLiving().worldObj; + + if(event.getEntityLiving().isPotionActive(WizardryPotions.fireskin) && !event.getSource().isProjectile()){ + if(!MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving())) attacker.setFire(5); + } + + if(event.getEntityLiving().isPotionActive(WizardryPotions.ice_shroud) && !event.getSource().isProjectile()){ + if(!MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving())) + attacker.addPotionEffect(new PotionEffect(WizardryPotions.frost, 100, 0)); + } + + if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura) && !event.getSource().isProjectile()){ + if(!world.isRemote){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(event.getEntityLiving().posX, event.getEntityLiving().posY + 1, event.getEntityLiving().posZ, + attacker.posX, attacker.posY + attacker.height/2, attacker.posZ); + world.spawnEntityInWorld(arc); + }else{ + for(int i=0;i<8;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, attacker.posX + world.rand.nextFloat() - 0.5, attacker.getEntityBoundingBox().minY + attacker.height/2 + world.rand.nextFloat()*2 - 1, attacker.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, attacker.posX + world.rand.nextFloat() - 0.5, attacker.getEntityBoundingBox().minY + attacker.height/2 + world.rand.nextFloat()*2 - 1, attacker.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); + } + } + + attacker.attackEntityFrom(MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), DamageType.SHOCK, true), 4.0f); + attacker.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); + } + + // Shadow ward + if(event.getEntityLiving() instanceof EntityPlayer){ + + ItemStack wand = event.getEntityLiving().getActiveItemStack(); + + if(wand != null && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand + && WandHelper.getCurrentSpell(wand) instanceof ShadowWard && !event.getSource().isUnblockable()){ + + event.setCanceled(true); + // This DamageSource.magic and not event.getSource() because the latter would cause an infinite loop. + event.getEntityLiving().attackEntityFrom(DamageSource.magic, event.getAmount()/2); + attacker.attackEntityFrom(MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), DamageType.MAGIC, true), event.getAmount()/2); + } + } + + // Transience + if(attacker.isPotionActive(WizardryPotions.transience)){ + event.setCanceled(true); + } + } + } + + @SubscribeEvent + public static void onLivingHurtEvent(LivingHurtEvent event){ + + // Curse of soulbinding + if(!event.getEntity().worldObj.isRemote && event.getEntityLiving() instanceof EntityPlayer && !event.getSource().isUnblockable()){ + WizardData properties = WizardData.get((EntityPlayer)event.getEntityLiving()); + if(properties != null){ + properties.damageAllSoulboundCreatures(event.getAmount()); + } + } + + // Flaming and freezing swords + if(event.getSource().getEntity() instanceof EntityLivingBase){ + + EntityLivingBase attacker = (EntityLivingBase)event.getSource().getEntity(); + + // Players can only ever attack with their main hand, so this is the right method to use here. + if(attacker.getHeldItemMainhand() != null && attacker.getHeldItemMainhand().getItem() instanceof ItemSword){ + + int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon, attacker.getHeldItemMainhand()); + + if(level > 0 && !MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving())) + event.getEntityLiving().setFire(level*4); + + level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.freezing_weapon, attacker.getHeldItemMainhand()); + // Frost lasts for longer because it doesn't do any actual damage + if(level > 0 && !MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving())) + event.getEntityLiving().addPotionEffect(new PotionEffect(WizardryPotions.frost, level*200, 0)); + } + } + + // Freezing bow + if(event.getSource().getSourceOfDamage() instanceof EntityArrow && event.getSource().getSourceOfDamage().getEntityData() != null){ + + int level = event.getSource().getSourceOfDamage().getEntityData().getInteger(FreezingWeapon.FREEZING_ARROW_NBT_KEY); + + if(level > 0 && !MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving())) + event.getEntityLiving().addPotionEffect(new PotionEffect(WizardryPotions.frost, level*150, 0)); + } + + // Damage scaling + if(event.getSource() != null && event.getSource() instanceof IElementalDamage){ + + if(event.getSource().getEntity() instanceof EntityPlayer){ + event.setAmount((float)(event.getAmount() * Wizardry.settings.playerDamageScale)); + }else{ + event.setAmount((float)(event.getAmount() * Wizardry.settings.npcDamageScale)); + } + } + } + + @SubscribeEvent + public static void onBlockPlaceEvent(BlockEvent.PlaceEvent event){ + + if(event.getPlayer().isPotionActive(WizardryPotions.transience)){ + event.setCanceled(true); + return; + } + + // Spectral blocks cannot be built on + if(event.getPlacedAgainst() == WizardryBlocks.spectral_block){ + event.setCanceled(true); + return; + } + } + + @SubscribeEvent + public static void onBlockBreakEvent(BlockEvent.BreakEvent event){ + + if(event.getPlayer().isPotionActive(WizardryPotions.transience)){ + event.setCanceled(true); + return; + } + + // Makes wizards angry if a player breaks a block in their tower + if(!(event.getPlayer() instanceof FakePlayer)){ + + List wizards = WizardryUtilities.getEntitiesWithinRadius(64, event.getPos().getX(), + event.getPos().getY(), event.getPos().getZ(), event.getWorld(), EntityWizard.class); + + if(!wizards.isEmpty()){ + for(EntityWizard wizard : wizards){ + if(wizard.isBlockPartOfTower(event.getPos())){ + wizard.setRevengeTarget(event.getPlayer()); + event.getPlayer().addStat(WizardryAchievements.anger_wizard); + } + } + } + } + } + + @SubscribeEvent + public static void onEntityStruckByLightningEvent(EntityStruckByLightningEvent event){ + + if(event.getLightning().getEntityData() != null && event.getLightning().getEntityData().hasKey("summoningPlayer")){ + + EntityPlayer player = (EntityPlayer)WizardryUtilities.getEntityByUUID(event.getLightning().worldObj, event.getLightning().getEntityData().getUniqueId("summoningPlayer")); + + if(event.getEntity() instanceof EntityCreeper){ + player.addStat(WizardryAchievements.charge_creeper); + } + + if(event.getEntity() instanceof EntityPig){ + player.addStat(WizardryAchievements.frankenstein); + } + } + + } + + @SubscribeEvent + public static void onLivingUpdateEvent(LivingUpdateEvent event){ + + // TODO: Move the player stuff to a PlayerTickEvent and separate methods out for clarity + + if(event.getEntityLiving() instanceof EntityPlayer){ + + EntityPlayer entityplayer = (EntityPlayer)event.getEntityLiving(); + + if(WizardData.get(entityplayer) != null){ + WizardData.get(entityplayer).update(); + } + + if(entityplayer.openContainer instanceof ContainerWorkbench){ + craftingTableTick(entityplayer); + } + + if(entityplayer.openContainer instanceof ContainerPlayer){ + // Unfortunately I have no choice but to call this method every tick when the player isn't using another + // inventory, since the only thing tracking whether the player is looking at their inventory is the GUI + // itself, which is client-side only. + playerInventoryTick(entityplayer); + } + + testForArmourSet:{ + for(ItemStack stack : entityplayer.getArmorInventoryList()){ + if(stack == null || !(stack.getItem() instanceof ItemWizardArmour)){ + break testForArmourSet; + } + } + entityplayer.addStat(WizardryAchievements.armour_set); + } + + } + + if(event.getEntityLiving().worldObj.isRemote){ + // Behold the power of interfaces! TODO: Backport. + for(PotionEffect effect : event.getEntityLiving().getActivePotionEffects()){ + + if(effect.getPotion() instanceof ICustomPotionParticles && effect.doesShowParticles()){ + + double x = event.getEntityLiving().posX + (event.getEntityLiving().worldObj.rand.nextDouble() - 0.5)*event.getEntityLiving().width; + double y = event.getEntityLiving().getEntityBoundingBox().minY + event.getEntityLiving().worldObj.rand.nextDouble()*event.getEntityLiving().height; + double z = event.getEntityLiving().posZ + (event.getEntityLiving().worldObj.rand.nextDouble() - 0.5)*event.getEntityLiving().width; + + ((ICustomPotionParticles)effect.getPotion()).spawnCustomParticle(event.getEntityLiving().worldObj, x, y, z); + } + } + + // Client-side continuous spell casting for NPCs + + if(event.getEntity() instanceof ISpellCaster && event.getEntity() instanceof EntityLiving){ + + Spell spell = ((ISpellCaster)event.getEntity()).getContinuousSpell(); + + if(spell != null && spell != Spells.none){ + spell.cast(event.getEntity().worldObj, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, 0, + // TODO: This implementation of modifiers relies on them being accessible client-side. + ((EntityLiving)event.getEntity()).getAttackTarget(), ((ISpellCaster)event.getEntity()).getModifiers()); + } + } + + }else{ + + if(event.getEntityLiving().isPotionActive(WizardryPotions.decay) && event.getEntityLiving().onGround && event.getEntityLiving().ticksExisted % Constants.DECAY_SPREAD_INTERVAL == 0){ + + List list = event.getEntityLiving().worldObj.getEntitiesWithinAABBExcludingEntity(event.getEntityLiving(), event.getEntityLiving().getEntityBoundingBox()); + + boolean flag = true; + + for(Object object : list){ + if(object instanceof EntityDecay) flag = false; + } + + if(flag){ + // The victim spreading the decay is the 'caster' here, so that it can actually wear off, otherwise it just gets infected with its own decay and the effect lasts forever. + event.getEntityLiving().worldObj.spawnEntityInWorld(new EntityDecay(event.getEntityLiving().worldObj, event.getEntityLiving().posX, event.getEntityLiving().posY, event.getEntityLiving().posZ, event.getEntityLiving())); + } + } + } + + // Mind Control + // This was added because something got changed in the AI classes which means LivingSetAttackTargetEvent doesn't + // get fired when I want it to... so I'm firing it myself. + if(event.getEntityLiving().isPotionActive(WizardryPotions.mind_control) && event.getEntityLiving() instanceof EntityLiving + && ((EntityLiving)event.getEntityLiving()).getAttackTarget() != null + && !((EntityLiving)event.getEntityLiving()).getAttackTarget().isEntityAlive()) + ((EntityLiving)event.getEntityLiving()).setAttackTarget(null); // Causes the event to be fired + + /* Old AI no longer exists! + + // Mind trick + + if(event.getEntityLiving().isPotionActive(Wizardry.mindTrick) && event.getEntityLiving() instanceof EntityLiving){ + // Old AI (this can't be done in onLivingSetAttackTargetEvent because that only fires for the new AI). + if(event.getEntityLiving() instanceof EntityCreature) ((EntityCreature)event.getEntityLiving()).setTarget(null); + } + + + // Mind control - old AI (this can't be done in onLivingSetAttackTargetEvent because that only fires for the new AI). + mindcontrol: + if(event.getEntityLiving().isPotionActive(Wizardry.mindControl) && event.getEntityLiving() instanceof EntityLiving){ + + NBTTagCompound entityNBT = event.getEntityLiving().getEntityData(); + + if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){ + + Entity caster = WizardryUtilities.getEntityByUUID(event.getEntity().worldObj, UUID.fromString(entityNBT.getString(MindControl.NBT_KEY))); + + if(caster instanceof EntityLivingBase){ + + if(MindControl.findMindControlTarget((EntityLiving)event.getEntityLiving(), (EntityLivingBase)caster, event.getEntity().worldObj)){ + // If it worked, skip setting the target to null. + break mindcontrol; + } + } + } + // If the caster couldn't be found or no valid target was found, this just acts like mind trick. + ((EntityLiving)event.getEntityLiving()).setAttackTarget(null); + } + */ + + // Intimidate + if(event.getEntityLiving().isPotionActive(WizardryPotions.fear) && event.getEntityLiving() instanceof EntityCreature){ + + NBTTagCompound entityNBT = event.getEntityLiving().getEntityData(); + EntityCreature creature = (EntityCreature)event.getEntityLiving(); + + if(entityNBT != null && entityNBT.hasKey(Intimidate.NBT_KEY)){ + + Entity caster = WizardryUtilities.getEntityByUUID(creature.worldObj, entityNBT.getUniqueId(Intimidate.NBT_KEY)); + + if(caster instanceof EntityLivingBase){ + Intimidate.runAway(creature, (EntityLivingBase)caster); + } + } + } + } + + @SubscribeEvent + public static void onBreakSpeedEvent(BreakSpeed event){ + if(event.getEntityPlayer().isPotionActive(WizardryPotions.frost)){ + // Amplifier + 1 because it starts at 0 + event.setNewSpeed(event.getOriginalSpeed() * (1 - Constants.FROST_FATIGUE_PER_LEVEL*(event.getEntityPlayer().getActivePotionEffect(WizardryPotions.frost).getAmplifier() + 1))); + } + } + + private static void playerInventoryTick(EntityPlayer player) { + + // Charges wand using mana flask. It is here rather than in the crafting handler so the result displays + // the proper damage before it is actually crafted. + + boolean flag = false; + ItemStack wand = null; + ItemStack armour = null; + IInventory craftMatrix = ((ContainerPlayer)player.openContainer).craftMatrix; + ItemStack outputItem = ((ContainerPlayer)player.openContainer).craftResult.getStackInSlot(0); + + for(int i = 0; i < craftMatrix.getSizeInventory(); i++){ + if(craftMatrix.getStackInSlot(i) != null){ + ItemStack itemstack = craftMatrix.getStackInSlot(i); + + if(itemstack.getItem() == WizardryItems.mana_flask){ + flag = true; + } + + if(itemstack.getItem() instanceof ItemWand){ + wand = itemstack; + } + + if(itemstack.getItem() instanceof ItemWizardArmour){ + armour = itemstack; + } + } + } + + if(outputItem != null && outputItem.getItem() instanceof ItemWand && flag && wand != null){ + outputItem.setTagCompound((wand.getTagCompound())); + if(wand.getItemDamage()-Constants.MANA_PER_FLASK < 0){ + outputItem.setItemDamage(0); + }else{ + outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK); + } + } + + if(outputItem != null && outputItem.getItem() instanceof ItemWizardArmour && flag && armour != null){ + outputItem.setTagCompound((armour.getTagCompound())); + if(armour.getItemDamage()-Constants.MANA_PER_FLASK < 0){ + outputItem.setItemDamage(0); + }else{ + outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK); + } + } + } + + private static void craftingTableTick(EntityPlayer player) { + + // Charges wand using mana flask. It is here rather than in the crafting handler so the result displays + // the proper damage before it is actually crafted. + + boolean flag = false; + ItemStack wand = null; + ItemStack armour = null; + IInventory craftMatrix = ((ContainerWorkbench)player.openContainer).craftMatrix; + ItemStack outputItem = ((ContainerWorkbench)player.openContainer).craftResult.getStackInSlot(0); + + for (int i = 0; i < craftMatrix.getSizeInventory(); i++){ + if(craftMatrix.getStackInSlot(i) != null){ + ItemStack itemstack = craftMatrix.getStackInSlot(i); + + if(itemstack.getItem() == WizardryItems.mana_flask){ + flag = true; + } + + if(itemstack.getItem() instanceof ItemWand){ + wand = itemstack; + } + + if(itemstack.getItem() instanceof ItemWizardArmour){ + armour = itemstack; + } + } + } + + if(outputItem != null && outputItem.getItem() instanceof ItemWand && flag && wand != null){ + outputItem.setTagCompound((wand.getTagCompound())); + if(wand.getItemDamage()-Constants.MANA_PER_FLASK < 0){ + outputItem.setItemDamage(0); + }else{ + outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK); + } + } + + if(outputItem != null && outputItem.getItem() instanceof ItemWizardArmour && flag && armour != null){ + outputItem.setTagCompound((armour.getTagCompound())); + if(armour.getItemDamage()-Constants.MANA_PER_FLASK < 0){ + outputItem.setItemDamage(0); + }else{ + outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK); + } + } + } + + @SubscribeEvent + public static void onLivingDeathEvent(LivingDeathEvent event){ + + if(event.getSource().getEntity() instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)event.getSource().getEntity(); + + for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){ + + if(stack != null && stack.getItem() instanceof ItemWand && stack.isItemDamaged() && WandHelper.getUpgradeLevel(stack, WizardryItems.siphon_upgrade) > 0){ + int damage = stack.getItemDamage() - Constants.SIPHON_MANA_PER_LEVEL*WandHelper.getUpgradeLevel(stack, WizardryItems.siphon_upgrade) - player.worldObj.rand.nextInt(Constants.SIPHON_MANA_PER_LEVEL); + if(damage < 0) damage = 0; + stack.setItemDamage(damage); + break; + } + } + + if(event.getEntityLiving() == player && event.getSource() instanceof IElementalDamage){ + player.addStat(WizardryAchievements.self_destruct); + } + } + } + + @SubscribeEvent + public static void onPlayerLoggedInEvent(PlayerLoggedInEvent event){ + // When a player logs in, they are sent the glyph data and the server's settings. + if(event.player instanceof EntityPlayerMP){ + SpellGlyphData.get(event.player.worldObj).sync((EntityPlayerMP)event.player); + Wizardry.settings.sync((EntityPlayerMP)event.player); + } + } + + @SubscribeEvent + public static void onEntityJoinWorld(EntityJoinWorldEvent event){ + + if(!event.getEntity().worldObj.isRemote && event.getEntity() instanceof EntityPlayerMP){ + // Synchronises wizard data after loading. + WizardData data = WizardData.get((EntityPlayer)event.getEntity()); + if(data != null) data.sync(); + } + + // Rather long-winded (but necessary) way of getting an arrow just after it has been fired, checking if the bow + // that fired it has the imbuement enchantment, and applying extra damage accordingly. + if(!event.getEntity().worldObj.isRemote && event.getEntity() instanceof EntityArrow){ + + EntityArrow arrow = (EntityArrow)event.getEntity(); + + magicBow: + if(arrow.shootingEntity instanceof EntityLivingBase){ + + EntityLivingBase archer = (EntityLivingBase)arrow.shootingEntity; + + ItemStack bow = archer.getHeldItemMainhand(); + + if(bow == null || !(bow.getItem() instanceof ItemBow)){ + bow = archer.getHeldItemOffhand(); + // Break used because return would skip the entire method, bypassing anything that might be added + // further down. + if(bow == null || !(bow.getItem() instanceof ItemBow)) break magicBow; + } + + // Taken directly from ItemBow, so it works exactly the same as the power enchantment. + int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.magic_bow, bow); + + if(level > 0){ + arrow.setDamage(arrow.getDamage() + (double)level * 0.5D + 0.5D); + } + + if(EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon, bow) > 0){ + // Again, this is exactly what happens in ItemBow (flame is flame; level does nothing). + arrow.setFire(100); + } + + level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.freezing_weapon, bow); + + if(level > 0){ + if(arrow.getEntityData() != null){ + arrow.getEntityData().setInteger(FreezingWeapon.FREEZING_ARROW_NBT_KEY, level); + } + } + } + + } + } + + @SubscribeEvent + public static void onLivingDropsEvent(LivingDropsEvent event){ + // TODO: Really, this should be in a loot table (mob_additions), however I can't seem to find a way of + // automatically adding it to all subclasses of IMob. + // Evil wizards drop spell books themselves + if(event.getEntityLiving() instanceof IMob && !(event.getEntityLiving() instanceof EntityEvilWizard) + // TODO: Backport when you backport the new summoned creature system. + && !(event.getEntityLiving() instanceof ISummonedCreature) && event.getSource().getEntity() instanceof EntityPlayer + && Wizardry.settings.spellBookDropChance > 0){ + + // This does exactly what the entity drop method does, but with a different random number so that the + // spell book doesn't always drop with other rare drops. + int rareDropNumber = event.getEntity().worldObj.rand.nextInt(200) - event.getLootingLevel(); + if(rareDropNumber < Wizardry.settings.spellBookDropChance){ + // Drops a spell book + int id = WizardryUtilities.getStandardWeightedRandomSpellId(event.getEntity().worldObj.rand); + + event.getDrops().add(new EntityItem(event.getEntityLiving().worldObj, event.getEntityLiving().posX, event.getEntityLiving().posY, event.getEntityLiving().posZ, + new ItemStack(WizardryItems.spell_book, 1, id))); + } + } + + for(EntityItem item : event.getDrops()){ + + // Destroys conjured items if their caster dies. + if(item.getEntityItem().getItem() instanceof IConjuredItem){ + item.setDead(); + } + + // Instantly disenchants an imbued weapon if it is dropped when the player dies. + if(item.getEntityItem().isItemEnchanted()){ + + // No need to check what enchantments the item has, since remove() does nothing if the element does not exist. + Map enchantments = EnchantmentHelper.getEnchantments(item.getEntityItem()); + + // Removes the magic weapon enchantments from the enchantment map + // An excellent demonstration of the usefulness of both interfaces and Java 8. + enchantments.entrySet().removeIf(entry -> entry.getKey() instanceof Imbuement); + + // Applies the new enchantment map to the item + EnchantmentHelper.setEnchantments(enchantments, item.getEntityItem()); + } + } + } + + @SubscribeEvent + public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){ + // Mind trick + // If the target is null already, no need to set it to null, or infinite loops will occur. + if((event.getEntityLiving().isPotionActive(WizardryPotions.mind_trick) || event.getEntityLiving().isPotionActive(WizardryPotions.fear)) && event.getEntityLiving() instanceof EntityLiving && event.getTarget() != null){ + ((EntityLiving)event.getEntityLiving()).setAttackTarget(null); + } + + // Mind control + mindcontrol: + if(event.getEntityLiving().isPotionActive(WizardryPotions.mind_control) && event.getEntityLiving() instanceof EntityLiving){ + + NBTTagCompound entityNBT = event.getEntityLiving().getEntityData(); + + if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY + "Most")){ + + Entity caster = WizardryUtilities.getEntityByUUID(event.getEntity().worldObj, entityNBT.getUniqueId(MindControl.NBT_KEY)); + + // If the target that the event tried to set is already a valid mind control target, nothing happens. + if(event.getTarget() != null && WizardryUtilities.isValidTarget(caster, event.getTarget())) break mindcontrol; + + if(caster instanceof EntityLivingBase){ + + if(MindControl.findMindControlTarget((EntityLiving)event.getEntityLiving(), (EntityLivingBase)caster, event.getEntity().worldObj)){ + // If it worked, skip setting the target to null. + break mindcontrol; + } + } + } + // If the caster couldn't be found or no valid target was found, this just acts like mind trick. + // If the target is null already, no need to set it to null, or infinite loops will occur. + if(event.getTarget() != null) ((EntityLiving)event.getEntityLiving()).setAttackTarget(null); + } + } + + @SubscribeEvent + public static void onItemPickupEvent(EntityItemPickupEvent event){ + if(event.getItem().getEntityItem().getItem() == WizardryItems.magic_crystal){ + event.getEntityPlayer().addStat(WizardryAchievements.crystal, 1); + } + } + + @SubscribeEvent + public static void onItemTossEvent(ItemTossEvent event){ + + // Prevents conjured items being thrown by dragging and dropping outside the inventory. + if(event.getEntityItem().getEntityItem().getItem() instanceof IConjuredItem){ + event.setCanceled(true); + event.getPlayer().inventory.addItemStackToInventory(event.getEntityItem().getEntityItem()); + } + + // Instantly disenchants an imbued weapon if it is thrown on the ground. + if(event.getEntityItem().getEntityItem().isItemEnchanted()){ + + // No need to check what enchantments the item has, since remove() does nothing if the element does not exist. + Map enchantments = EnchantmentHelper.getEnchantments(event.getEntityItem().getEntityItem()); + + // Removes the magic weapon enchantments from the enchantment map + enchantments.entrySet().removeIf(entry -> entry.getKey() instanceof Imbuement); + + // Applies the new enchantment map to the item + EnchantmentHelper.setEnchantments(enchantments, event.getEntityItem().getEntityItem()); + } + } + + @SubscribeEvent + public static void onRightClickBlockEvent(PlayerInteractEvent.RightClickBlock event){ + + if(event.getEntityPlayer().isSneaking()){ + + // The event now has an ItemStack, which greatly simplifies hand-related stuff. + ItemStack wand = event.getItemStack(); + + if(wand != null && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Clairvoyance){ + + WizardData properties = WizardData.get(event.getEntityPlayer()); + + if(properties != null){ + // THIS is why BlockPos is a thing - in 1.7.10 this requires a clumsy switch statement. + BlockPos pos = event.getPos().offset(event.getFace()); + + properties.setClairvoyancePoint(pos, event.getWorld().provider.getDimension()); + + if(!event.getWorld().isRemote){ + event.getEntityPlayer().addChatMessage(new TextComponentTranslation("spell.clairvoyance.confirm", Spells.clairvoyance.getNameForTranslationFormatted())); + } + + event.setCanceled(true); + } + } + } + } + + @SubscribeEvent + public static void onBonemealEvent(BonemealEvent event){ + // Grows crystal flowers when bonemeal is used on grass + if(event.getBlock().getBlock() == Blocks.GRASS){ + + BlockPos pos = event.getPos().add(event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8), + event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4), + event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8)); + + if (event.getWorld().isAirBlock(new BlockPos(pos)) && (!event.getWorld().provider.getHasNoSky() || pos.getY() < 127) && WizardryBlocks.crystal_flower.canPlaceBlockAt(event.getWorld(), pos)) + { + event.getWorld().setBlockState(pos, WizardryBlocks.crystal_flower.getDefaultState(), 2); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/WizardryGuiFactory.java b/src/main/java/electroblob/wizardry/WizardryGuiFactory.java new file mode 100644 index 00000000..0f7c0161 --- /dev/null +++ b/src/main/java/electroblob/wizardry/WizardryGuiFactory.java @@ -0,0 +1,36 @@ +package electroblob.wizardry; + +import java.util.Set; + +import electroblob.wizardry.client.GuiConfigWizardry; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraftforge.fml.client.IModGuiFactory; + +public class WizardryGuiFactory implements IModGuiFactory { + + @Override + public void initialize(Minecraft minecraftInstance) + { + + } + + @Override + public Class mainConfigGuiClass() + { + return GuiConfigWizardry.class; + } + + @Override + public Set runtimeGuiCategories() + { + return null; + } + + @SuppressWarnings("deprecation") // It's a bit of Forge that hasn't been tidied up, but we have to implement it. + @Override + public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) + { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/WizardryGuiHandler.java b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java new file mode 100644 index 00000000..ad17f45d --- /dev/null +++ b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java @@ -0,0 +1,66 @@ +package electroblob.wizardry; + +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.item.ItemWizardHandbook; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.tileentity.ContainerArcaneWorkbench; +import electroblob.wizardry.tileentity.ContainerPortableWorkbench; +import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.IGuiHandler; + +public class WizardryGuiHandler implements IGuiHandler { + + /** Incrementable index for the gui ID */ + private static int nextGuiId = 0; + + public static final int SPELL_BOOK = nextGuiId++; + public static final int ARCANE_WORKBENCH = nextGuiId++; + public static final int WIZARD_HANDBOOK = nextGuiId++; + public static final int PORTABLE_CRAFTING = nextGuiId++; + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, + int x, int y, int z) { + if(id == ARCANE_WORKBENCH){ + TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z)); + if(tileEntity instanceof TileEntityArcaneWorkbench){ + return new ContainerArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench) tileEntity); + } + } + else if(id == PORTABLE_CRAFTING){ + return new ContainerPortableWorkbench(player.inventory, world, new BlockPos(x, y, z)); + } + return null; + } + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, + int x, int y, int z) { + if(id == ARCANE_WORKBENCH){ + TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z)); + if(tileEntity instanceof TileEntityArcaneWorkbench){ + return new electroblob.wizardry.client.GuiArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench) tileEntity); + } + } + else if(id == WIZARD_HANDBOOK + && ((player.getHeldItemMainhand() != null && player.getHeldItemMainhand().getItem() instanceof ItemWizardHandbook) + || (player.getHeldItemOffhand() != null && player.getHeldItemOffhand().getItem() instanceof ItemWizardHandbook))){ + return new electroblob.wizardry.client.GuiWizardHandbook(); + } + else if(id == SPELL_BOOK){ + if(player.getHeldItemMainhand() != null && player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){ + return new electroblob.wizardry.client.GuiSpellBook(Spell.get(player.getHeldItemMainhand().getItemDamage())); + }else if(player.getHeldItemOffhand() != null && player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){ + return new electroblob.wizardry.client.GuiSpellBook(Spell.get(player.getHeldItemOffhand().getItemDamage())); + } + } + else if(id == PORTABLE_CRAFTING){ + return new electroblob.wizardry.client.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z)); + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/WizardryKeyHandler.java b/src/main/java/electroblob/wizardry/WizardryKeyHandler.java new file mode 100644 index 00000000..9cfc7ab9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/WizardryKeyHandler.java @@ -0,0 +1,67 @@ +package electroblob.wizardry; + +import org.lwjgl.input.Keyboard; + +import electroblob.wizardry.client.ClientProxy; +import electroblob.wizardry.packet.PacketControlInput; +import electroblob.wizardry.packet.WizardryPacketHandler; +import net.minecraft.client.Minecraft; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.InputEvent; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +public class WizardryKeyHandler { + + boolean NkeyPressed = false; + boolean BkeyPressed = false; + boolean NkeyAlreadyPressed = false; + boolean BkeyAlreadyPressed = false; + + @SubscribeEvent + public void onKeyInput(InputEvent.KeyInputEvent event) { + + // Key pressed + if(Keyboard.getEventKeyState()){ + + if(Wizardry.proxy instanceof ClientProxy){ + + if(ClientProxy.NEXT_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){ + if(!NkeyPressed){ + NkeyPressed = true; + }else{ + NkeyAlreadyPressed = true; + } + if(!NkeyAlreadyPressed){ + // Packet building + IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY); + WizardryPacketHandler.net.sendToServer(msg); + } + } + + if(ClientProxy.PREVIOUS_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){ + if(!BkeyPressed){ + BkeyPressed = true; + }else{ + BkeyAlreadyPressed = true; + } + if(!BkeyAlreadyPressed){ + // Packet building + IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY); + WizardryPacketHandler.net.sendToServer(msg); + } + } + } + } + + // Key released + else{ + if(NkeyPressed){ + NkeyPressed = false; + NkeyAlreadyPressed = false; + }else if(BkeyPressed){ + BkeyPressed = false; + BkeyAlreadyPressed = false; + } + } + } +} diff --git a/src/main/java/electroblob/wizardry/WizardryWorldGenerator.java b/src/main/java/electroblob/wizardry/WizardryWorldGenerator.java new file mode 100644 index 00000000..74fdab00 --- /dev/null +++ b/src/main/java/electroblob/wizardry/WizardryWorldGenerator.java @@ -0,0 +1,1546 @@ +package electroblob.wizardry; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; + +import electroblob.wizardry.entity.living.EntityEvilWizard; +import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.BlockChest; +import net.minecraft.block.BlockColored; +import net.minecraft.block.BlockLeaves; +import net.minecraft.block.BlockLiquid; +import net.minecraft.block.BlockPlanks; +import net.minecraft.block.BlockSlab; +import net.minecraft.block.BlockTorch; +import net.minecraft.block.BlockSlab.EnumBlockHalf; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Biomes; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.EnumDyeColor; +import net.minecraft.item.ItemDoor; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.IChunkGenerator; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.feature.WorldGenMinable; +import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.world.storage.loot.LootTable; +import net.minecraftforge.common.BiomeDictionary; +import net.minecraftforge.common.IPlantable; +import net.minecraftforge.fml.common.IWorldGenerator; + +public class WizardryWorldGenerator implements IWorldGenerator { + + /** The string identifier for wizard tower chests, used in ChestGenHooks. */ + public static final String WIZARD_TOWER = Wizardry.MODID + "wizardTower"; + + @Override + public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider){ + + for(int id : Wizardry.settings.oreDimensions){ + if(id == world.provider.getDimension()) this.addOreSpawn(WizardryBlocks.crystal_ore.getDefaultState(), world, random, chunkX * 16, chunkZ * 16, 16, 16, 5, 7, 5, 30); + } + + for(int id : Wizardry.settings.flowerDimensions){ + if(id == world.provider.getDimension()) this.generatePlant(WizardryBlocks.crystal_flower.getDefaultState(), world, random, chunkX * 16, chunkZ * 16, 2, 20); + } + + if(world.getWorldInfo().isMapFeaturesEnabled()){ + for(int id : Wizardry.settings.towerDimensions){ + if(id == world.provider.getDimension()) this.generateWizardTower(world, random, chunkX * 16, chunkZ * 16); + } + } + } + + /** + * Adds an Ore Spawn to Minecraft. Simply register all Ores to spawn with this method in your Generation method in your IWorldGeneration extending Class + * + * @param The Block to spawn + * @param The World to spawn in + * @param A Random object for retrieving random positions within the world to spawn the Block + * @param An int for passing the X-Coordinate for the Generation method + * @param An int for passing the Z-Coordinate for the Generation method + * @param An int for setting the maximum X-Coordinate values for spawning on the X-Axis on a Per-Chunk basis + * @param An int for setting the maximum Z-Coordinate values for spawning on the Z-Axis on a Per-Chunk basis + * @param An int for setting the maximum size of a vein + * @param An int for the Number of chances available for the Block to spawn per-chunk + * @param An int for the minimum Y-Coordinate height at which this block may spawn + * @param An int for the maximum Y-Coordinate height at which this block may spawn + **/ + public void addOreSpawn(IBlockState state, World world, Random random, int blockXPos, int blockZPos, int maxX, int maxZ, int maxVeinSize, int chancesToSpawn, int minY, int maxY) + { + //int maxPossY = minY + (maxY - 1); + assert maxY > minY: "The maximum Y must be greater than the Minimum Y"; + assert maxX > 0 && maxX <= 16: "addOreSpawn: The Maximum X must be greater than 0 and less than 16"; + assert minY > 0: "addOreSpawn: The Minimum Y must be greater than 0"; + assert maxY < 256 && maxY > 0: "addOreSpawn: The Maximum Y must be less than 256 but greater than 0"; + assert maxZ > 0 && maxZ <= 16: "addOreSpawn: The Maximum Z must be greater than 0 and less than 16"; + + int diffBtwnMinMaxY = maxY - minY; + for(int x = 0; x < chancesToSpawn; x++) + { + int posX = blockXPos + random.nextInt(maxX); + int posY = minY + random.nextInt(diffBtwnMinMaxY); + int posZ = blockZPos + random.nextInt(maxZ); + (new WorldGenMinable(state, maxVeinSize)).generate(world, random, new BlockPos(posX, posY, posZ)); + } + } + + /** + * Generates the specified plant randomly throughout the world. + * @param block The plant block + * @param world The world + * @param random A random instance + * @param x The x coord of the first block in the chunk + * @param z The y coord of the first block in the chunk + * @param chancesToSpawn Number of chances to spawn a flower patch + * @param groupSize The number of times to try generating a flower per flower patch spawn + */ + public void generatePlant(IBlockState state, World world, Random random, int x, int z, int chancesToSpawn, int groupSize){ + + for(int i = 0; i < chancesToSpawn; i++){ + int randPosX = x + random.nextInt(16); + int randPosY = random.nextInt(256); + int randPosZ = z + random.nextInt(16); + for (int l = 0; l < groupSize; ++l) + { + int i1 = randPosX + random.nextInt(8) - random.nextInt(8); + int j1 = randPosY + random.nextInt(4) - random.nextInt(4); + int k1 = randPosZ + random.nextInt(8) - random.nextInt(8); + + BlockPos pos = new BlockPos(i1, j1, k1); + + if(world.isBlockLoaded(pos) && world.isAirBlock(pos) && (!world.provider.getHasNoSky() || j1 < 127) && state.getBlock().canPlaceBlockOnSide(world, pos, EnumFacing.UP)){ + + world.setBlockState(pos, state, 2); + } + } + } + } + + /** + * Generates wizard towers randomly throughout the world. + */ + public void generateWizardTower(World world, Random random, int chunkX, int chunkZ){ + + // Allows the config file to set the rarity value to 0 to disable tower generation completely. + if(Wizardry.settings.towerRarity == 0) return; + + // Compensates for the lack of space in forests. Math.max is required since treeless biomes have treesPerChunk = -999 + //double treeFactor = 70 - Math.max((double)world.getBiomeGenForCoords(chunkX, chunkZ).theBiomeDecorator.treesPerChunk, 0) * 1.5d; + + // Multiplied by 70 to (roughly) retain the old rarity scale + if(random.nextInt((int)(Wizardry.settings.towerRarity * 70)) == 0){ + + BlockPos origin = new BlockPos(chunkX + random.nextInt(16), 0, chunkZ + random.nextInt(16)); + + // Despite what its name suggests, this method does not return the position of a liquid. It is in fact + // exactly what is needed here since it is used for placing villages and stuff, and doesn't include leaves + // or other foliage. + origin = origin.up(world.getTopSolidOrLiquidBlock(origin).getY() - 1); + + int[][][] towerBlueprint = towerBlueprintSmall; + + switch(random.nextInt(4)){ + case 0: towerBlueprint = towerBlueprintSmall; break; + case 1: towerBlueprint = towerBlueprintMedium; break; + case 2: towerBlueprint = towerBlueprintTall; break; + case 3: towerBlueprint = towerBlueprintDouble; break; + } + + // 0 = West, 1 = North, 2 = East, 3 = South (The way you would face when walking out of the door) + EnumFacing orientation = EnumFacing.getHorizontal(random.nextInt(4)); + boolean flip = random.nextBoolean(); + + if(checkSpaceForTower(world, origin, towerBlueprint, orientation, flip)){ + + // == Setup == + + boolean evilWizard = random.nextInt(5) == 0; + + IBlockState wallMaterial = Blocks.COBBLESTONE.getDefaultState(); + BlockPlanks.EnumType woodType = BlockPlanks.EnumType.OAK; + + Biome biome = world.getBiome(origin); + + // The order of these is somewhat important in that biomes can be many types, so the last of these checks + // that is true gets priority. Generally speaking, the later the check, the more specific it is. + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.DENSE)) wallMaterial = Blocks.MOSSY_COBBLESTONE.getDefaultState(); + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.SWAMP)) wallMaterial = Blocks.MOSSY_COBBLESTONE.getDefaultState(); + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.SANDY)) wallMaterial = Blocks.SANDSTONE.getDefaultState(); + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.NETHER)) wallMaterial = Blocks.NETHER_BRICK.getDefaultState(); + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.MOUNTAIN)) wallMaterial = Blocks.STONEBRICK.getDefaultState(); + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.MESA)) wallMaterial = Blocks.HARDENED_CLAY.getDefaultState(); + + // Unfortunately, I can't check all the wood types with the biome dictionary + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.CONIFEROUS)) woodType = BlockPlanks.EnumType.SPRUCE; + if(biome == Biomes.BIRCH_FOREST || biome == Biomes.BIRCH_FOREST_HILLS) woodType = BlockPlanks.EnumType.BIRCH; + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.JUNGLE)) woodType = BlockPlanks.EnumType.JUNGLE; + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.SAVANNA)) woodType = BlockPlanks.EnumType.ACACIA; + // Not technically a tree type, but I think it fits quite well anyway + if(BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.SPOOKY)) woodType = BlockPlanks.EnumType.DARK_OAK; + + IBlockState[] blockStateList = new IBlockState[]{ + null, + Blocks.AIR.getDefaultState(), + Blocks.PLANKS.getDefaultState().withProperty(BlockPlanks.VARIANT, woodType), + Blocks.BOOKSHELF.getDefaultState(), + Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(BlockColored.COLOR, + EnumDyeColor.values()[random.nextInt(EnumDyeColor.values().length)]), + Blocks.WOODEN_SLAB.getDefaultState().withProperty(BlockSlab.HALF, EnumBlockHalf.BOTTOM), + Blocks.WOODEN_SLAB.getDefaultState().withProperty(BlockSlab.HALF, EnumBlockHalf.TOP), + wallMaterial, + Blocks.GLASS_PANE.getDefaultState(), + Blocks.OAK_DOOR.getDefaultState(), + WizardryBlocks.arcane_workbench.getDefaultState(), + Blocks.TORCH.getDefaultState(), + evilWizard ? Blocks.CHEST.getDefaultState() : Blocks.BOOKSHELF.getDefaultState() + }; + + Set blocksPlaced = new HashSet(); + + // == Foundations == + + // Fills in foundations. This is done first so the door always has something to be placed on. + boolean flag = true; + + // BlockPos is immutable, so I'm not sure if simply saying pos1 = pos will be sufficient. + BlockPos layerCentre = new BlockPos(origin); + + while(flag){ + + flag = false; + + for(BlockPos offset : foundationLayer){ + if(!world.isBlockNormalCube(layerCentre.add(offset), false)){ + world.setBlockState(layerCentre.add(offset), wallMaterial); + blocksPlaced.add(layerCentre.add(offset)); + // Keeps going as long as something was filled in. + flag = true; + } + } + + layerCentre = layerCentre.down(); + } + + // == Main Structure == + + // It is assumed that the width of the blueprint is the same all the way up, and that the layers are square. + int width = towerBlueprint[0].length-1; + + // x, y and z are the position the block is being put in. + // x1, y and z1 are the position in the blueprint which determines which block is being placed. + + int x1 = 0, z1 = 0; + + for(int y=0; y 3 || world.getBlockState(pos1).getBlock() instanceof BlockLiquid)){ + return false; + } + } + } + } + + return true; + } + + /** Array of relative positions of each block in a layer of foundations. */ + private static final BlockPos[] foundationLayer = new BlockPos[]{ + new BlockPos(-2, 0, -1), + new BlockPos(-2, 0, 0), + new BlockPos(-2, 0, 1), + new BlockPos(2, 0, -1), + new BlockPos(2, 0, 0), + new BlockPos(2, 0, 1), + new BlockPos(-1, 0, -2), + new BlockPos(0, 0, -2), + new BlockPos(1, 0, -2), + new BlockPos(-1, 0, 2), + new BlockPos(0, 0, 2), + new BlockPos(1, 0, 2), + }; + + /** + * 3D matrix of integers representing the different blocks which make up the wizard tower. The blocks corresponding + * to each integer are as follows (note that some blocks change depending on the biome): + *

    + * 0 Nothing (keep existing block)
    + * 1 Air (remove existing block)
    + * 2 Floor (planks)
    + * 3 Bookshelf
    + * 4 Roof (stained clay)
    + * 5 Floor slab (lower half)
    + * 6 Floor slab (upper half)
    + * 7 Wall (cobblestone by default)
    + * 8 Glass pane
    + * 9 Door (metadata is handled by the built-in vanilla method)
    + * 10 Arcane workbench
    + * 11 Torch (metadata is handled separately depending on adjacent blocks)
    + * 12 Chest (only generates if the wizard is evil, otherwise places a bookshelf instead) + */ + private static final int[][][] towerBlueprintSmall = { + // x is horizontal, z is vertical, y is layers + { + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 2, 2, 2, 0, 0, 0}, + {0, 0, 0, 2, 2, 2, 0, 0, 0}, + {0, 0, 0, 2, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 6, 5, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 9, 7, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 5, 1 ,1, 7, 0, 0}, + {0, 0, 7, 6, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 0, 7, 0, 0, 0}, + {0, 0, 0, 11,1, 11,0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 11,7, 0, 0}, + {0, 0, 7, 5, 6, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 6, 7, 0, 0}, + {0, 0, 7, 1, 1, 5, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 6, 5, 7, 0, 0}, + {0, 0, 7, 11,1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 5, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 2, 2, 2, 7, 0, 0}, + {0, 7, 1, 1, 1, 1, 2, 7, 0}, + {0, 7, 5, 2, 2, 6, 2, 7, 0}, + {0, 7, 2, 2, 2, 2, 2, 7, 0}, + {0, 0, 7, 2, 2, 2, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 3, 3, 3, 7, 0, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 7, 1, 1, 10,1, 3, 7, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 7, 11,1, 11,7, 0, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 8, 1, 1, 1, 1, 3, 7, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 0, 7, 11,1, 11,7, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 4, 7, 7, 7, 4, 0, 0}, + {0, 4, 7, 1, 1, 1, 7, 4, 0}, + {4, 7, 1, 1, 1, 1, 3, 7, 4}, + {4, 7, 1, 1, 1, 1, 3, 7, 4}, + {4, 7, 1, 1, 1, 1, 12,7, 4}, + {0, 4, 7, 1, 1, 1, 7, 4, 0}, + {0, 0, 4, 7, 7, 7, 4, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 4, 1, 1, 1, 1, 1, 4, 0}, + {0, 4, 1, 1, 1, 1, 1, 4, 0}, + {0, 4, 1, 1, 1, 1, 1, 4, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + } + }; + + /** + * 3D matrix of integers representing the different blocks which make up the wizard tower. The blocks corresponding + * to each integer are as follows (note that some blocks change depending on the biome): + *

    + * 0 Nothing (keep existing block)
    + * 1 Air (remove existing block)
    + * 2 Floor (planks)
    + * 3 Bookshelf
    + * 4 Roof (stained clay)
    + * 5 Floor slab (lower half)
    + * 6 Floor slab (upper half)
    + * 7 Wall (cobblestone by default)
    + * 8 Glass pane
    + * 9 Door (metadata is handled by the built-in vanilla method)
    + * 10 Arcane workbench
    + * 11 Torch (metadata is handled separately depending on adjacent blocks)
    + * 12 Chest (only generates if the wizard is evil, otherwise places a bookshelf instead) + */ + private static final int[][][] towerBlueprintMedium = { + // x is horizontal, z is vertical, y is layers + { + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 2, 2, 2, 0, 0, 0}, + {0, 0, 0, 2, 2, 2, 0, 0, 0}, + {0, 0, 0, 2, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 6, 5, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 9, 7, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 5, 1 ,1, 7, 0, 0}, + {0, 0, 7, 6, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 0, 7, 0, 0, 0}, + {0, 0, 0, 11,1, 11,0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 11,7, 0, 0}, + {0, 0, 7, 5, 6, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 6, 7, 0, 0}, + {0, 0, 7, 1, 1, 5, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 6, 5, 7, 0, 0}, + {0, 0, 7, 11,1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 5, 1 ,1, 7, 0, 0}, + {0, 0, 7, 6, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 11,7, 0, 0}, + {0, 0, 7, 5, 6, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 6, 7, 0, 0}, + {0, 0, 7, 1, 1, 5, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 6, 5, 7, 0, 0}, + {0, 0, 7, 11,1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 5, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 2, 2, 2, 7, 0, 0}, + {0, 7, 1, 1, 1, 1, 2, 7, 0}, + {0, 7, 5, 2, 2, 6, 2, 7, 0}, + {0, 7, 2, 2, 2, 2, 2, 7, 0}, + {0, 0, 7, 2, 2, 2, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 3, 3, 3, 7, 0, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 7, 1, 1, 10,1, 3, 7, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 7, 11,1, 11,7, 0, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 8, 1, 1, 1, 1, 3, 7, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 0, 7, 11,1, 11,7, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 4, 7, 7, 7, 4, 0, 0}, + {0, 4, 7, 1, 1, 1, 7, 4, 0}, + {4, 7, 1, 1, 1, 1, 3, 7, 4}, + {4, 7, 1, 1, 1, 1, 3, 7, 4}, + {4, 7, 1, 1, 1, 1, 12,7, 4}, + {0, 4, 7, 1, 1, 1, 7, 4, 0}, + {0, 0, 4, 7, 7, 7, 4, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 4, 1, 1, 1, 1, 1, 4, 0}, + {0, 4, 1, 1, 1, 1, 1, 4, 0}, + {0, 4, 1, 1, 1, 1, 1, 4, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + } + }; + + /** + * 3D matrix of integers representing the different blocks which make up the wizard tower. The blocks corresponding + * to each integer are as follows (note that some blocks change depending on the biome): + *

    + * 0 Nothing (keep existing block)
    + * 1 Air (remove existing block)
    + * 2 Floor (planks)
    + * 3 Bookshelf
    + * 4 Roof (stained clay)
    + * 5 Floor slab (lower half)
    + * 6 Floor slab (upper half)
    + * 7 Wall (cobblestone by default)
    + * 8 Glass pane
    + * 9 Door (metadata is handled by the built-in vanilla method)
    + * 10 Arcane workbench
    + * 11 Torch (metadata is handled separately depending on adjacent blocks)
    + * 12 Chest (only generates if the wizard is evil, otherwise places a bookshelf instead) + */ + private static final int[][][] towerBlueprintTall = { + // x is horizontal, z is vertical, y is layers + { + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 2, 2, 2, 0, 0, 0}, + {0, 0, 0, 2, 2, 2, 0, 0, 0}, + {0, 0, 0, 2, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 6, 5, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 9, 7, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 5, 1 ,1, 7, 0, 0}, + {0, 0, 7, 6, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 0, 7, 0, 0, 0}, + {0, 0, 0, 11,1, 11,0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 11,7, 0, 0}, + {0, 0, 7, 5, 6, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 6, 7, 0, 0}, + {0, 0, 7, 1, 1, 5, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 6, 5, 7, 0, 0}, + {0, 0, 7, 11,1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 5, 1 ,1, 7, 0, 0}, + {0, 0, 7, 6, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 11,7, 0, 0}, + {0, 0, 7, 5, 6, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 6, 7, 0, 0}, + {0, 0, 7, 1, 1, 5, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 6, 5, 7, 0, 0}, + {0, 0, 7, 11,1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 5, 1 ,1, 7, 0, 0}, + {0, 0, 7, 6, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 11,7, 0, 0}, + {0, 0, 7, 5, 6, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 6, 7, 0, 0}, + {0, 0, 7, 1, 1, 5, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 1, 6, 5, 7, 0, 0}, + {0, 0, 7, 11,1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 5, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 2, 2, 2, 7, 0, 0}, + {0, 7, 1, 1, 1, 1, 2, 7, 0}, + {0, 7, 5, 2, 2, 6, 2, 7, 0}, + {0, 7, 2, 2, 2, 2, 2, 7, 0}, + {0, 0, 7, 2, 2, 2, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 7, 3, 3, 3, 7, 0, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 7, 1, 1, 10,1, 3, 7, 0}, + {0, 0, 7, 1, 1, 1, 7, 0, 0}, + {0, 0, 0, 7, 7, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 7, 11,1, 11,7, 0, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 8, 1, 1, 1, 1, 3, 7, 0}, + {0, 7, 1, 1, 1, 1, 3, 7, 0}, + {0, 0, 7, 11,1, 11,7, 0, 0}, + {0, 0, 0, 7, 8, 7, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 4, 7, 7, 7, 4, 0, 0}, + {0, 4, 7, 1, 1, 1, 7, 4, 0}, + {4, 7, 1, 1, 1, 1, 3, 7, 4}, + {4, 7, 1, 1, 1, 1, 3, 7, 4}, + {4, 7, 1, 1, 1, 1, 12,7, 4}, + {0, 4, 7, 1, 1, 1, 7, 4, 0}, + {0, 0, 4, 7, 7, 7, 4, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 4, 1, 1, 1, 1, 1, 4, 0}, + {0, 4, 1, 1, 1, 1, 1, 4, 0}, + {0, 4, 1, 1, 1, 1, 1, 4, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 4, 1, 1, 1, 4, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 0, 4, 4, 4, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 4, 1, 4, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + } + }; + + /** + * 3D matrix of integers representing the different blocks which make up the wizard tower. The blocks corresponding + * to each integer are as follows (note that some blocks change depending on the biome): + *

    + * 0 Nothing (keep existing block)
    + * 1 Air (remove existing block)
    + * 2 Floor (planks)
    + * 3 Bookshelf
    + * 4 Roof (stained clay)
    + * 5 Floor slab (lower half)
    + * 6 Floor slab (upper half)
    + * 7 Wall (cobblestone by default)
    + * 8 Glass pane
    + * 9 Door (metadata is handled by the built-in vanilla method)
    + * 10 Arcane workbench
    + * 11 Torch (metadata is handled separately depending on adjacent blocks)
    + * 12 Chest (only generates if the wizard is evil, otherwise places a bookshelf instead) + */ + private static final int[][][] towerBlueprintDouble = { + // x is horizontal, z is vertical, y is layers + { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 6, 5, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 9, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 5, 1 ,1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 6, 1, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 11,1, 11,0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 11,7, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 5, 6, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 6, 7, 7, 7, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 5, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 6, 5, 7, 7, 7, 0, 0}, + {0, 0, 0, 0, 7, 11,1, 1, 1, 1, 1, 7, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 7, 7, 0, 0}, + {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 5, 1 ,1, 7, 7, 8, 7, 0}, + {0, 0, 0, 0, 7, 6, 1, 1, 1, 1, 1, 8, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 7, 8, 7, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 8, 7, 0, 4, 4, 4, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 7, 7, 7, 4}, + {0, 0, 0, 0, 7, 1, 1, 11,7, 1, 1, 7, 4}, + {0, 0, 0, 0, 7, 5, 6, 1, 7, 7, 7, 7, 4}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 4, 4, 4, 0}, + {0, 0, 0, 0, 7, 1, 1, 6, 7, 4, 1, 4, 0}, + {0, 0, 0, 0, 7, 1, 1, 5, 7, 4, 4, 4, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 6, 5, 7, 0, 4, 0, 0}, + {0, 0, 0, 0, 7, 11,1, 1, 7, 4, 1, 4, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 4, 0, 0}, + {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 5, 1, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 4, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 2, 2, 2, 7, 0, 0, 0, 0}, + {0, 0, 0, 7, 1, 1, 1, 1, 2, 7, 0, 0, 0}, + {0, 0, 0, 7, 5, 2, 2, 6, 2, 7, 4, 0, 0}, + {0, 0, 0, 7, 2, 2, 2, 2, 2, 7, 0, 0, 0}, + {0, 0, 0, 0, 7, 2, 2, 2, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 3, 3, 3, 7, 0, 0, 0, 0}, + {0, 0, 0, 7, 1, 1, 1, 1, 3, 7, 0, 0, 0}, + {0, 0, 0, 7, 1, 1, 1, 1, 3, 7, 0, 0, 0}, + {0, 0, 0, 7, 1, 1, 10,1, 3, 7, 0, 0, 0}, + {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 7, 11,1, 11,7, 0, 0, 0, 0}, + {0, 0, 0, 7, 1, 1, 1, 1, 3, 7, 0, 0, 0}, + {0, 0, 0, 8, 1, 1, 1, 1, 3, 7, 0, 0, 0}, + {0, 0, 0, 7, 1, 1, 1, 1, 3, 7, 0, 0, 0}, + {0, 0, 0, 0, 7, 11,1, 11,7, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 7, 7, 7, 4, 0, 0, 0, 0}, + {0, 0, 0, 4, 7, 1, 1, 1, 7, 4, 0, 0, 0}, + {0, 0, 4, 7, 1, 1, 1, 1, 3, 7, 4, 0, 0}, + {0, 0, 4, 7, 1, 1, 1, 1, 3, 7, 4, 0, 0}, + {0, 0, 4, 7, 1, 1, 1, 1, 12,7, 4, 0, 0}, + {0, 0, 0, 4, 7, 1, 1, 1, 7, 4, 0, 0, 0}, + {0, 0, 0, 0, 4, 7, 7, 7, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, + {0, 0, 0, 4, 1, 1, 1, 1, 1, 4, 0, 0, 0}, + {0, 0, 0, 4, 1, 1, 1, 1, 1, 4, 0, 0, 0}, + {0, 0, 0, 4, 1, 1, 1, 1, 1, 4, 0, 0, 0}, + {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 1, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 1, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 1, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 4, 1, 4, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + },{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + } + }; + + +} diff --git a/src/main/java/electroblob/wizardry/block/BlockArcaneWorkbench.java b/src/main/java/electroblob/wizardry/block/BlockArcaneWorkbench.java new file mode 100644 index 00000000..4a0c3f8f --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockArcaneWorkbench.java @@ -0,0 +1,120 @@ +package electroblob.wizardry.block; + +import java.util.Random; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.WizardryGuiHandler; +import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumBlockRenderType; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +public class BlockArcaneWorkbench extends BlockContainer { + + private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.75D, 1.0D); + + public BlockArcaneWorkbench(){ + super(Material.ROCK); + this.setLightLevel(0.8f); + } + + @Override + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){ + return AABB; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + return new TileEntityArcaneWorkbench(); + } + + @Override + public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { + return false; + } + + @Override + public EnumBlockRenderType getRenderType(IBlockState state) { + return EnumBlockRenderType.MODEL; + } + + @Override + public boolean isOpaqueCube(IBlockState state) { + return false; + } + + @Override + public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, + EnumHand hand, ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ){ + + TileEntity tileEntity = world.getTileEntity(pos); + + if(tileEntity == null || player.isSneaking()){ + return false; + } + + player.openGui(Wizardry.instance, WizardryGuiHandler.ARCANE_WORKBENCH, world, pos.getX(), pos.getY(), pos.getZ()); + return true; + } + + @Override + public void breakBlock(World world, BlockPos pos, IBlockState block) + { + Random random = new Random(); + TileEntityArcaneWorkbench tileentityarcaneworkbench = (TileEntityArcaneWorkbench)world.getTileEntity(pos); + + if (tileentityarcaneworkbench != null) + { + for (int j1 = 0; j1 < tileentityarcaneworkbench.getSizeInventory(); ++j1) + { + ItemStack itemstack = tileentityarcaneworkbench.getStackInSlot(j1); + + if (itemstack != null) + { + float f = random.nextFloat() * 0.8F + 0.1F; + float f1 = random.nextFloat() * 0.8F + 0.1F; + EntityItem entityitem; + + for (float f2 = random.nextFloat() * 0.8F + 0.1F; itemstack.stackSize > 0; world.spawnEntityInWorld(entityitem)) + { + int k1 = random.nextInt(21) + 10; + + if (k1 > itemstack.stackSize) + { + k1 = itemstack.stackSize; + } + + itemstack.stackSize -= k1; + entityitem = new EntityItem(world, (double)((float)pos.getX() + f), (double)((float)pos.getY() + f1), (double)((float)pos.getZ() + f2), new ItemStack(itemstack.getItem(), k1, itemstack.getItemDamage())); + float f3 = 0.05F; + entityitem.motionX = (double)((float)random.nextGaussian() * f3); + entityitem.motionY = (double)((float)random.nextGaussian() * f3 + 0.2F); + entityitem.motionZ = (double)((float)random.nextGaussian() * f3); + + if (itemstack.hasTagCompound()) + { + entityitem.getEntityItem().setTagCompound(((NBTTagCompound)itemstack.getTagCompound().copy())); + } + } + } + } + + //par1World.func_96440_m(par2, par3, par4, block); + } + + super.breakBlock(world, pos, block); + } + +} diff --git a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java new file mode 100644 index 00000000..13daca12 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java @@ -0,0 +1,46 @@ +package electroblob.wizardry.block; + +import java.util.Random; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.block.BlockBush; +import net.minecraft.block.SoundType; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.EnumPlantType; + +// Extending BlockBush allows me to remove nearly everything from this class. +public class BlockCrystalFlower extends BlockBush { + + private static final AxisAlignedBB AABB = new AxisAlignedBB(0.5F - 0.2f, 0.0F, 0.5F - 0.2f, 0.5F + 0.2f, 0.2f * 3.0F, 0.5F + 0.2f); + + public BlockCrystalFlower(Material par2Material) { + super(par2Material); + this.setLightLevel(0.5f); + this.setTickRandomly(true); + this.setSoundType(SoundType.PLANT); + } + + @Override + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) + { + return AABB; + } + + @Override + public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){ + if(world.isRemote && random.nextBoolean()){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, pos.getX()+random.nextDouble(), pos.getY()+random.nextDouble()/2+0.5, pos.getZ()+random.nextDouble(), 0d, 0.01, 0d, 20 + random.nextInt(10), 0.5f + (random.nextFloat()/2), 0.5f + (random.nextFloat()/2), 0.5f + (random.nextFloat()/2)); + } + } + + @Override + public EnumPlantType getPlantType(IBlockAccess world, BlockPos pos) { + return EnumPlantType.Plains; + } +} diff --git a/src/main/java/electroblob/wizardry/block/BlockCrystalOre.java b/src/main/java/electroblob/wizardry/block/BlockCrystalOre.java new file mode 100644 index 00000000..dc594dc0 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockCrystalOre.java @@ -0,0 +1,35 @@ +package electroblob.wizardry.block; + +import java.util.Random; + +import electroblob.wizardry.registry.WizardryItems; +import net.minecraft.block.Block; +import net.minecraft.block.SoundType; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.item.Item; + +public class BlockCrystalOre extends Block { + + public BlockCrystalOre(Material material) { + super(material); + this.setSoundType(SoundType.STONE); + setResistance(5.0F); + setHarvestLevel("pickaxe", 2); + } + + @Override + public int quantityDropped(IBlockState state, int fortune, Random random) + { + if(fortune > 0){ + return random.nextInt(2) + 1 + random.nextInt(fortune); + }else{ + return random.nextInt(2) + 1; + } + } + + @Override + public Item getItemDropped(IBlockState state, Random random, int fortune){ + return WizardryItems.magic_crystal; + } +} diff --git a/src/main/java/electroblob/wizardry/block/BlockMagicLight.java b/src/main/java/electroblob/wizardry/block/BlockMagicLight.java new file mode 100644 index 00000000..c3ef8499 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockMagicLight.java @@ -0,0 +1,58 @@ +package electroblob.wizardry.block; + +import electroblob.wizardry.tileentity.TileEntityMagicLight; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumBlockRenderType; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +public class BlockMagicLight extends BlockContainer { + + private static final AxisAlignedBB AABB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + + public BlockMagicLight(Material par2Material) { + super(par2Material); + this.setLightLevel(1.0f); + } + + @Override + public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos){ + // The other two bounding box methods in Block aren't nullable, so this is the only one that can return NULL_AABB. + return NULL_AABB; + } + + @Override + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){ + return AABB; + } + + @Override + public boolean isCollidable(){ + return false; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + return new TileEntityMagicLight(600); + } + + @Override + public boolean isOpaqueCube(IBlockState state) { + return false; + } + + @Override + public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { + return false; + } + + @Override + public EnumBlockRenderType getRenderType(IBlockState state) { + return EnumBlockRenderType.ENTITYBLOCK_ANIMATED; + } +} diff --git a/src/main/java/electroblob/wizardry/block/BlockSnare.java b/src/main/java/electroblob/wizardry/block/BlockSnare.java new file mode 100644 index 00000000..d020a580 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockSnare.java @@ -0,0 +1,110 @@ +package electroblob.wizardry.block; + +import java.util.Random; + +import electroblob.wizardry.tileentity.TileEntityPlayerSave; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.SoundType; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.MobEffects; +import net.minecraft.item.Item; +import net.minecraft.potion.PotionEffect; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumBlockRenderType; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +// TODO: Apparently you shouldn't extend BlockContainer. I feel like BlockArcaneWorkbench should, but what about the rest? +public class BlockSnare extends BlockContainer { + + private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0f, 0.0f, 0.0f, 1.0f, 0.0625f, 1.0f); + + public BlockSnare(Material par2Material){ + super(par2Material); + this.setSoundType(SoundType.PLANT); + } + + @Override + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){ + return AABB; + } + + @Override + public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos){ + return NULL_AABB; + } + + @Override + public boolean hasTileEntity(IBlockState state){ + return true; + } + + @Override + public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) { + + if(!world.isRemote && entity instanceof EntityLivingBase){ + if(world.getTileEntity(pos) instanceof TileEntityPlayerSave){ + + TileEntityPlayerSave tileentity = (TileEntityPlayerSave)world.getTileEntity(pos); + + if(WizardryUtilities.isValidTarget(tileentity.getCaster(), entity)){ + ((EntityLivingBase)entity).attackEntityFrom(MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC), 6); + ((EntityLivingBase)entity).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 100, 2)); + + world.destroyBlock(pos, false); + } + } + } + } + + // The similarly named onNeighborChange method does NOT do the same thing. + @SuppressWarnings("deprecation") + @Override + public void neighborChanged(IBlockState state, World world, BlockPos pos, Block blockIn){ + super.neighborChanged(state, world, pos, blockIn); + if(!world.isSideSolid(pos.down(), EnumFacing.UP, false)){ + world.setBlockToAir(pos); + } + } + + @Override + public BlockRenderLayer getBlockLayer(){ + return BlockRenderLayer.CUTOUT; + } + + @Override + public EnumBlockRenderType getRenderType(IBlockState state){ + return EnumBlockRenderType.MODEL; + } + + @Override + public boolean isOpaqueCube(IBlockState state){ + return false; + } + + @Override + public boolean isFullCube(IBlockState state){ + return false; + } + + @Override + public Item getItemDropped(IBlockState state, Random rand, int fortune){ + return null; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + return new TileEntityPlayerSave(); + } + +} diff --git a/src/main/java/electroblob/wizardry/block/BlockSpectral.java b/src/main/java/electroblob/wizardry/block/BlockSpectral.java new file mode 100644 index 00000000..e151e845 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockSpectral.java @@ -0,0 +1,94 @@ +package electroblob.wizardry.block; + +import java.util.Random; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.tileentity.TileEntityTimer; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.SoundType; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumBlockRenderType; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on +// block break. +public class BlockSpectral extends BlockContainer { + + public BlockSpectral(Material material) { + super(material); + this.setSoundType(SoundType.GLASS); + } + + // Replaces getRenderBlockPass + @Override + public BlockRenderLayer getBlockLayer(){ + return BlockRenderLayer.TRANSLUCENT; + } + + @Override + public EnumBlockRenderType getRenderType(IBlockState state) { + return EnumBlockRenderType.MODEL; + } + + // Apparently it's OK to override this, despite it being deprecated. More importantly, it being deprecated is not + // Forge's doing, rather it is Mojang themselves misusing the @Deprecated annotation to mean 'internal, don't call'. + @Override + public boolean isOpaqueCube(IBlockState state){ + return false; + } + + @Override + public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { + return false; + } + + @Override + public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random) { + // Middle of block + Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX()+random.nextDouble(), pos.getY()+random.nextDouble(), pos.getZ()+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)), + 0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f); + // Top surface + Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX()+random.nextDouble(), pos.getY()+1, pos.getZ()+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)), + 0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f); + Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX()+random.nextDouble(), pos.getY()+1, pos.getZ()+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)), + 0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f); + } + + // Overriden to make the block always look full brightness despite not emitting full light. + @Override + public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos) { + return 15; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + return new TileEntityTimer(1200); + } + + @Override + public int quantityDropped(Random par1Random){ + return 0; + } + + @SuppressWarnings("deprecation") + @SideOnly(Side.CLIENT) + @Override + public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side){ + + IBlockState iblockstate = blockAccess.getBlockState(pos.offset(side)); + Block block = iblockstate.getBlock(); + + return block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side); + } + +} diff --git a/src/main/java/electroblob/wizardry/block/BlockStatue.java b/src/main/java/electroblob/wizardry/block/BlockStatue.java new file mode 100644 index 00000000..3b3e9b5e --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockStatue.java @@ -0,0 +1,146 @@ +package electroblob.wizardry.block; + +import java.util.Random; + +import electroblob.wizardry.spell.Petrify; +import electroblob.wizardry.tileentity.TileEntityStatue; +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.SoundType; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumBlockRenderType; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class BlockStatue extends BlockContainer { + + private boolean isIce; + + public BlockStatue(Material material) { + super(material); + this.isIce = material == Material.ICE; + if(this.isIce){ + this.slipperiness = 0.98F; + this.setSoundType(SoundType.GLASS); + } + } + + @Override + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){ + // Not a good idea to call getBlockBoundsMinX() or whatever from in here, since this method changes those! + if(!this.isIce){ + + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + + TileEntityStatue statue = (TileEntityStatue)world.getTileEntity(pos); + + if(statue.creature != null){ + + // Block bounds are set to match the width and height of the entity, clamped to within 1 block. + return new AxisAlignedBB((float)Math.max(0.5 - statue.creature.width/2, 0), 0, + (float)Math.max(0.5 - statue.creature.width/2, 0), + (float)Math.min(0.5 + statue.creature.width/2, 1), + // This checks if the block is the top one and if so reduces its height so the top lines up with + // the top of the entity model. + statue.position == statue.parts ? (float)Math.min(statue.creature.height - statue.parts + 1, 1) : 1, + (float)Math.min(0.5 + statue.creature.width/2, 1)); + } + } + } + + return FULL_BLOCK_AABB; + } + + // getCollisionBoundingBox eventually calls getBoundingBox anyway, and since I want the collision box and the block + // outline to be the same here, I've removed that getCollisionBoundingBox entirely. + + // The number of these methods is quite simply ridiculous. This one seems to be for placement logic and block + // connections (fences, glass panes, etc.)... + @Override public boolean isFullCube(IBlockState state) { return false; } + // ...this one isn't used much but has something to do with redstone... + @Override public boolean isBlockNormalCube(IBlockState state) { return false; } + // ... this one is for most other game logic... + @Override public boolean isNormalCube(IBlockState state) { return false; } + // Forge version of the above method. I still need to override both though because vanilla uses the other one. + @Override public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { return false; } + // ... and this one is for rendering. + @Override public boolean isOpaqueCube(IBlockState state){ return false; } + + @Override + public BlockRenderLayer getBlockLayer(){ + return this.isIce ? BlockRenderLayer.TRANSLUCENT : BlockRenderLayer.SOLID; + } + + @Override + public EnumBlockRenderType getRenderType(IBlockState state){ + return this.isIce ? EnumBlockRenderType.MODEL : EnumBlockRenderType.ENTITYBLOCK_ANIMATED; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + return new TileEntityStatue(this.isIce); + } + + @Override + public int quantityDropped(Random random){ + return 0; + } + + @Override + public void breakBlock(World world, BlockPos pos, IBlockState state){ + + if(!world.isRemote){ + + TileEntityStatue tileentity = (TileEntityStatue)world.getTileEntity(pos); + + if(tileentity != null){ + if(tileentity.parts == 2){ + if(tileentity.position == 2){ + world.destroyBlock(pos.down(), false); + }else{ + world.destroyBlock(pos.up(), false); + } + }else if(tileentity.parts == 3){ + if(tileentity.position == 3){ + world.destroyBlock(pos.down(), false); + world.destroyBlock(pos.down(2), false); + }else if(tileentity.position == 2){ + world.destroyBlock(pos.down(), false); + world.destroyBlock(pos.up(), false); + }else{ + world.destroyBlock(pos.up(), false); + world.destroyBlock(pos.up(2), false); + } + } + } + + // This is only when position == 1 because world.destroyBlock calls this function for the other blocks. + if(tileentity != null && tileentity.position == 1 && tileentity.creature != null){ + tileentity.creature.getEntityData().removeTag(Petrify.NBT_KEY); + tileentity.creature.isDead = false; + world.spawnEntityInWorld(tileentity.creature); + } + } + + super.breakBlock(world, pos, state); + } + + @SuppressWarnings("deprecation") + @SideOnly(Side.CLIENT) + @Override + public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side){ + + IBlockState iblockstate = blockAccess.getBlockState(pos.offset(side)); + Block block = iblockstate.getBlock(); + + return this.isIce && block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side); + } +} diff --git a/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java b/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java new file mode 100644 index 00000000..681d5266 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java @@ -0,0 +1,115 @@ +package electroblob.wizardry.block; + +import java.util.Random; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryBlocks; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +public class BlockTransportationStone extends Block { + + private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0625f*5, 0, 0.0625f*5, 0.0625f*11, 0.0625f*6, 0.0625f*11); + + public BlockTransportationStone(Material material){ + super(material); + this.setTickRandomly(true); + } + + @Override + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){ + return AABB; + } + + // The number of these methods is quite simply ridiculous. This one seems to be for placement logic and block + // connections (fences, glass panes, etc.)... + @Override public boolean isFullCube(IBlockState state) { return false; } + // ...this one isn't used much but has something to do with redstone... + @Override public boolean isBlockNormalCube(IBlockState state) { return false; } + // ... this one is for most other game logic... + @Override public boolean isNormalCube(IBlockState state) { return false; } + // Forge version of the above method. I still need to override both though because vanilla uses the other one. + @Override public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { return false; } + // ... and this one is for rendering. + @Override public boolean isOpaqueCube(IBlockState state){ return false; } + + @Override + public void onNeighborChange(IBlockAccess world, BlockPos pos, BlockPos neighbor){ + + super.onNeighborChange(world, pos, neighbor); + + if(!world.isSideSolid(pos.down(), EnumFacing.UP, false) && world instanceof World){ + this.dropBlockAsItem((World) world, pos, world.getBlockState(pos), 0); + ((World)world).setBlockToAir(pos); + } + } + + @Override + public void updateTick(World world, BlockPos pos, IBlockState state, Random random) { + + if(!world.isSideSolid(pos.down(), EnumFacing.UP)){ + this.dropBlockAsItem(world, pos, world.getBlockState(pos), 0); + world.setBlockToAir(pos); + } + } + + @Override + public boolean canPlaceBlockAt(World world, BlockPos pos){ + return super.canPlaceBlockAt(world, pos) && world.isSideSolid(pos.down(), EnumFacing.UP); + } + + @Override + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, + EnumHand hand, ItemStack stack, EnumFacing side, float hitX, float hitY, float hitZ) { + + if(stack != null && stack.getItem() instanceof ItemWand){ + if(WizardData.get(player) != null){ + + WizardData data = WizardData.get(player); + + for(int x=-1; x<=1; x++){ + for(int z=-1; z<=1; z++){ + BlockPos pos1 = pos.add(x, 0, z); + if(testForCircle(world, pos1)){ + data.setStoneCircleLocation(pos1, world.provider.getDimension()); + if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("tile.wizardry:transportation_stone.confirm", Spells.transportation.getNameForTranslationFormatted())); + return true; + } + } + } + + if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("tile.wizardry:transportation_stone.invalid")); + return true; + } + } + return false; + } + + /** Returns whether the specified location is surrounded by a complete cicle of 8 transportation stones. */ + public static boolean testForCircle(World world, BlockPos pos){ + + if(world.getBlockState(pos).getMaterial().blocksMovement()) return false; + + for(int x=-1; x<=1; x++){ + for(int z=-1; z<=1; z++){ + if(world.getBlockState(pos.add(x, 0, z)).getBlock() != WizardryBlocks.transportation_stone){ + if(x != 0 || z != 0) return false; + } + } + } + + return true; + } +} diff --git a/src/main/java/electroblob/wizardry/block/BlockVanishingCobweb.java b/src/main/java/electroblob/wizardry/block/BlockVanishingCobweb.java new file mode 100644 index 00000000..3dcc77cd --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockVanishingCobweb.java @@ -0,0 +1,70 @@ +package electroblob.wizardry.block; + +import java.util.Random; + +import electroblob.wizardry.tileentity.TileEntityTimer; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumBlockRenderType; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on block break. +public class BlockVanishingCobweb extends BlockContainer { + + public BlockVanishingCobweb(Material material) { + super(material); + } + + @SideOnly(Side.CLIENT) + public BlockRenderLayer getBlockLayer() + { + return BlockRenderLayer.CUTOUT; + } + + @Override + public EnumBlockRenderType getRenderType(IBlockState state){ + return EnumBlockRenderType.MODEL; + } + + @Override + public boolean isOpaqueCube(IBlockState state) + { + return false; + } + + @Override + public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos) + { + return NULL_AABB; + } + + @Override + public boolean isFullCube(IBlockState state) + { + return false; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + return new TileEntityTimer(400); + } + + @Override + public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity){ + entity.setInWeb(); + } + + @Override + public int quantityDropped(Random par1Random){ + return 0; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java new file mode 100644 index 00000000..dba2813d --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -0,0 +1,579 @@ +package electroblob.wizardry.client; + +import java.lang.ref.WeakReference; +import java.util.HashMap; + +import org.lwjgl.input.Keyboard; + +import electroblob.wizardry.CommonProxy; +import electroblob.wizardry.SpellGlyphData; +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.model.ModelWizardArmour; +import electroblob.wizardry.client.particle.ParticleBlizzard; +import electroblob.wizardry.client.particle.ParticleDarkMagic; +import electroblob.wizardry.client.particle.ParticleDust; +import electroblob.wizardry.client.particle.ParticleGiantBubble; +import electroblob.wizardry.client.particle.ParticleIce; +import electroblob.wizardry.client.particle.ParticleLeaf; +import electroblob.wizardry.client.particle.ParticleMagicFlame; +import electroblob.wizardry.client.particle.ParticlePath; +import electroblob.wizardry.client.particle.ParticleRotatingSparkle; +import electroblob.wizardry.client.particle.ParticleSnow; +import electroblob.wizardry.client.particle.ParticleSpark; +import electroblob.wizardry.client.particle.ParticleSparkle; +import electroblob.wizardry.client.particle.ParticleTornado; +import electroblob.wizardry.client.renderer.LayerStone; +import electroblob.wizardry.client.renderer.RenderArc; +import electroblob.wizardry.client.renderer.RenderArcaneWorkbench; +import electroblob.wizardry.client.renderer.RenderBlackHole; +import electroblob.wizardry.client.renderer.RenderBlank; +import electroblob.wizardry.client.renderer.RenderBubble; +import electroblob.wizardry.client.renderer.RenderDecay; +import electroblob.wizardry.client.renderer.RenderDecoy; +import electroblob.wizardry.client.renderer.RenderEvilWizard; +import electroblob.wizardry.client.renderer.RenderFireRing; +import electroblob.wizardry.client.renderer.RenderForceArrow; +import electroblob.wizardry.client.renderer.RenderHammer; +import electroblob.wizardry.client.renderer.RenderIceGiant; +import electroblob.wizardry.client.renderer.RenderIceSpike; +import electroblob.wizardry.client.renderer.RenderLightningDisc; +import electroblob.wizardry.client.renderer.RenderLightningPulse; +import electroblob.wizardry.client.renderer.RenderMagicArrow; +import electroblob.wizardry.client.renderer.RenderMagicLight; +import electroblob.wizardry.client.renderer.RenderPhoenix; +import electroblob.wizardry.client.renderer.RenderProjectile; +import electroblob.wizardry.client.renderer.RenderSigil; +import electroblob.wizardry.client.renderer.RenderSpiritHorse; +import electroblob.wizardry.client.renderer.RenderSpiritWolf; +import electroblob.wizardry.client.renderer.RenderStatue; +import electroblob.wizardry.client.renderer.RenderWizard; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.entity.EntityShield; +import electroblob.wizardry.entity.construct.EntityArrowRain; +import electroblob.wizardry.entity.construct.EntityBlackHole; +import electroblob.wizardry.entity.construct.EntityBlizzard; +import electroblob.wizardry.entity.construct.EntityBubble; +import electroblob.wizardry.entity.construct.EntityDecay; +import electroblob.wizardry.entity.construct.EntityEarthquake; +import electroblob.wizardry.entity.construct.EntityFireRing; +import electroblob.wizardry.entity.construct.EntityFireSigil; +import electroblob.wizardry.entity.construct.EntityForcefield; +import electroblob.wizardry.entity.construct.EntityFrostSigil; +import electroblob.wizardry.entity.construct.EntityHailstorm; +import electroblob.wizardry.entity.construct.EntityHammer; +import electroblob.wizardry.entity.construct.EntityHealAura; +import electroblob.wizardry.entity.construct.EntityIceSpike; +import electroblob.wizardry.entity.construct.EntityLightningPulse; +import electroblob.wizardry.entity.construct.EntityLightningSigil; +import electroblob.wizardry.entity.construct.EntityTornado; +import electroblob.wizardry.entity.living.EntityDecoy; +import electroblob.wizardry.entity.living.EntityEvilWizard; +import electroblob.wizardry.entity.living.EntityIceGiant; +import electroblob.wizardry.entity.living.EntityIceWraith; +import electroblob.wizardry.entity.living.EntityLightningWraith; +import electroblob.wizardry.entity.living.EntityPhoenix; +import electroblob.wizardry.entity.living.EntityShadowWraith; +import electroblob.wizardry.entity.living.EntitySpiritHorse; +import electroblob.wizardry.entity.living.EntitySpiritWolf; +import electroblob.wizardry.entity.living.EntityStormElemental; +import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.entity.living.ISpellCaster; +import electroblob.wizardry.entity.living.ISummonedCreature; +import electroblob.wizardry.entity.projectile.EntityDarknessOrb; +import electroblob.wizardry.entity.projectile.EntityDart; +import electroblob.wizardry.entity.projectile.EntityFirebolt; +import electroblob.wizardry.entity.projectile.EntityFirebomb; +import electroblob.wizardry.entity.projectile.EntityForceArrow; +import electroblob.wizardry.entity.projectile.EntityForceOrb; +import electroblob.wizardry.entity.projectile.EntityIceCharge; +import electroblob.wizardry.entity.projectile.EntityIceLance; +import electroblob.wizardry.entity.projectile.EntityIceShard; +import electroblob.wizardry.entity.projectile.EntityLightningArrow; +import electroblob.wizardry.entity.projectile.EntityLightningDisc; +import electroblob.wizardry.entity.projectile.EntityMagicMissile; +import electroblob.wizardry.entity.projectile.EntityPoisonBomb; +import electroblob.wizardry.entity.projectile.EntitySmokeBomb; +import electroblob.wizardry.entity.projectile.EntitySpark; +import electroblob.wizardry.entity.projectile.EntitySparkBomb; +import electroblob.wizardry.entity.projectile.EntityThunderbolt; +import electroblob.wizardry.item.ItemScroll; +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.packet.PacketCastContinuousSpell; +import electroblob.wizardry.packet.PacketCastSpell; +import electroblob.wizardry.packet.PacketNPCCastSpell; +import electroblob.wizardry.packet.PacketPlayerSync.Message; +import electroblob.wizardry.packet.PacketTransportation; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Clairvoyance; +import electroblob.wizardry.spell.None; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; +import electroblob.wizardry.tileentity.TileEntityMagicLight; +import electroblob.wizardry.tileentity.TileEntityStatue; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WandHelper; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.model.ModelBiped; +import net.minecraft.client.renderer.entity.RenderBlaze; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntityBlaze; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.config.Property; +import net.minecraftforge.fml.client.config.GuiConfigEntries.NumberSliderEntry; +import net.minecraftforge.fml.client.registry.ClientRegistry; +import net.minecraftforge.fml.client.registry.RenderingRegistry; + +/** + * The client proxy for wizardry. + * @author Electroblob + * @since Wizardry 1.0 + */ +public class ClientProxy extends CommonProxy { + + /** Static instance of the mixed font renderer */ + public static MixedFontRenderer mixedFontRenderer; + + // Key Bindings + public static final KeyBinding NEXT_SPELL = new KeyBinding("key.wizardry:next_spell", Keyboard.KEY_N, "key.categories.wizardry"); + public static final KeyBinding PREVIOUS_SPELL = new KeyBinding("key.wizardry:previous_spell", Keyboard.KEY_B, "key.categories.wizardry"); + + // Armour Model + public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f); + + // SECTION Registry + // =============================================================================================================== + + @Override + public ModelBiped getWizardArmourModel(){ + return WIZARD_ARMOUR_MODEL; + } + + @Override + public void registerKeyBindings(){ + ClientRegistry.registerKeyBinding(NEXT_SPELL); + ClientRegistry.registerKeyBinding(PREVIOUS_SPELL); + } + + @Override + public void registerSpellHUD(){ + MinecraftForge.EVENT_BUS.register(new GuiSpellDisplay(Minecraft.getMinecraft())); + } + + @Override + public void initMixedFontRenderer(){ + mixedFontRenderer = new MixedFontRenderer(Minecraft.getMinecraft().gameSettings, + new ResourceLocation("textures/font/ascii.png"), Minecraft.getMinecraft().renderEngine, false); + } + + // SECTION Misc + // =============================================================================================================== + + @Override + public void setToNumberSliderEntry(Property property) { + property.setConfigEntryClass(NumberSliderEntry.class); + } + + @Override + public World getTheWorld() { + return Minecraft.getMinecraft().theWorld; + } + + @Override + public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){ + Minecraft.getMinecraft().getSoundHandler().playSound(new MovingSoundEntity(entity, sound, volume, pitch, repeat)); + } + + // SECTION Items + // =============================================================================================================== + + @Override + public FontRenderer getFontRenderer(ItemStack stack){ + + Spell spell = Spells.none; + + if(stack.getItem() instanceof ItemWand){ + spell = WandHelper.getCurrentSpell(stack); + }else if(stack.getItem() instanceof ItemSpellBook || stack.getItem() instanceof ItemScroll){ + spell = Spell.get(stack.getItemDamage()); + } + + if(Minecraft.getMinecraft().thePlayer != null && Wizardry.settings.discoveryMode + && WizardData.get(Minecraft.getMinecraft().thePlayer) != null + && !Minecraft.getMinecraft().thePlayer.capabilities.isCreativeMode + && !WizardData.get(Minecraft.getMinecraft().thePlayer).hasSpellBeenDiscovered(spell)){ + return mixedFontRenderer; + } + + return null; + } + + @Override + public String getScrollDisplayName(ItemStack scroll){ + + // Displays [Empty slot] if spell is continuous. + Spell spell = Spell.get(scroll.getItemDamage()); + if(spell.isContinuous) spell = Spells.none; + + EntityPlayer player = Minecraft.getMinecraft().thePlayer; + + boolean discovered = true; + // It seems that this method is called when the world is loading, before thePlayer has been initialised. + // If the player is null, the spell is assumed to be discovered. + if(player != null && Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode + && WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){ + discovered = false; + } + + if(discovered){ + return I18n.format("item.wizardry:scroll.name", spell.getDisplayName()).trim(); + }else{ + return I18n.format("item.wizardry:scroll.undiscovered.name", "#" + SpellGlyphData.getGlyphName(spell, player.worldObj) + "#").trim(); + } + } + + @Override + public double getConjuredBowDurability(ItemStack stack){ + EntityPlayer player = Minecraft.getMinecraft().thePlayer; + if(player.getActiveItemStack() == stack){ + return (double)(stack.getItemDamage() + (player.getItemInUseMaxCount()) ) / (double)stack.getMaxDamage(); + } + return super.getConjuredBowDurability(stack); + } + + // SECTION Particles + // =============================================================================================================== + + @Override + public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b, boolean doGravity, double radius){ + + // Colour values are now automatically clamped to between 0 and 1, as values outside this range seem to + // cause strange effects in 1.10 (or more specifically, particles that are bright pink!) + // TODO: This is a terrible dirty fix, but it'll do for now. Find a nicer way in future. + if(type != WizardryParticleType.MAGIC_FIRE) r = MathHelper.clamp_float(r, 0, 1); + g = MathHelper.clamp_float(g, 0, 1); + b = MathHelper.clamp_float(b, 0, 1); + + switch(type){ + + case BLIZZARD: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleBlizzard(world, maxAge, x, z, radius, y)); + break; + case BRIGHT_DUST: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDust(world, x, y, z, velX, velY, velZ, r, g, b, false)); + break; + case DARK_MAGIC: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDarkMagic(world, x, y, z, velX, velY, velZ, r, g, b)); + break; + case DUST: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDust(world, x, y, z, velX, velY, velZ, r, g, b, true)); + break; + case ICE: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleIce(world, x, y, z, velX, velY, velZ, maxAge)); + break; + case LEAF: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleLeaf(world, x, y, z, velX, velY, velZ, maxAge)); + break; + case MAGIC_BUBBLE: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleGiantBubble(world, x, y, z, velX, velY, velZ)); + break; + case MAGIC_FIRE: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleMagicFlame(world, x, y, z, velX, velY, velZ, maxAge, r == 0 ? 1 + world.rand.nextFloat() : r)); + break; + case PATH: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticlePath(world, x, y, z, velX, velY, velZ, r, g, b, maxAge)); + break; + case SNOW: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSnow(world, x, y, z, velX, velY, velZ)); + break; + case SPARK: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSpark(world, x, y, z, velX, velY, velZ)); + break; + case SPARKLE: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSparkle(world, x, y, z, velX, velY, velZ, r, g, b, maxAge, doGravity)); + break; + case SPARKLE_ROTATING: + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleRotatingSparkle(world, maxAge, x, z, radius, y, r, g, b)); + break; + default: + break; + } + } + + @Override + public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){ + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTornado(world, maxAge, x, z, radius, y, velX, velZ, block).setBlockPos(pos));//, world.rand.nextInt(6))); + } + + // SECTION Packet Handlers + // =============================================================================================================== + + @Override + public void handleCastSpellPacket(PacketCastSpell.Message message){ + + World world = Minecraft.getMinecraft().theWorld; + Entity caster = world.getEntityByID(message.casterID); + Spell spell = Spell.get(message.spellID); + // Should always be true + if(caster instanceof EntityPlayer){ + + ((EntityPlayer)caster).setActiveHand(message.hand); + + // Duration isn't needed because it only ever affects things server-side, and anything that is + // seen client-side gets synced elsewhere. + spell.cast(world, (EntityPlayer)caster, message.hand, 0, new SpellModifiers()); + + // Updates the spell discovery data client-side. Could be done by calling sync(), but that means sending + // another packet unnecessarily. + if(WizardData.get((EntityPlayer)caster) != null){ + WizardData.get((EntityPlayer)caster).discoverSpell(spell); + } + + }else{ + Wizardry.logger.warn("Recieved a PacketCastSpell, but the caster ID was not the ID of a player"); + } + } + + @Override + public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){ + + World world = Minecraft.getMinecraft().theWorld; + Entity caster = world.getEntityByID(message.casterID); + Spell spell = Spell.get(message.spellID); + // Should always be true + if(caster instanceof EntityPlayer){ + + WizardData data = WizardData.get((EntityPlayer)caster); + + if(data != null){ + if(data.isCasting()){ + WizardData.get((EntityPlayer)caster).stopCastingContinuousSpell(); + }else{ + WizardData.get((EntityPlayer)caster).startCastingContinuousSpell(spell, message.modifiers); + } + } + }else{ + Wizardry.logger.warn("Recieved a PacketCastContinuousSpell, but the caster ID was not the ID of a player"); + } + } + + @Override + public void handleNPCCastSpellPacket(PacketNPCCastSpell.Message message){ + + World world = Minecraft.getMinecraft().theWorld; + Entity caster = world.getEntityByID(message.casterID); + Entity target = message.targetID == -1 ? null : world.getEntityByID(message.targetID); + Spell spell = Spell.get(message.spellID); + // Should always be true + if(caster instanceof EntityLiving){ + + if(target instanceof EntityLivingBase){ + spell.cast(world, (EntityLiving)caster, message.hand, 0, (EntityLivingBase)target, message.modifiers); + } + + if(caster instanceof ISpellCaster){ + if(spell.isContinuous || spell instanceof None){ + ((ISpellCaster)caster).setContinuousSpell(spell); + ((EntityLiving)caster).setAttackTarget((EntityLivingBase)target); + } + } + }else{ + Wizardry.logger.warn("Recieved a PacketNPCCastSpell, but the caster ID was not the ID of an EntityLiving"); + } + } + + @Override + public void handleTransportationPacket(PacketTransportation.Message message){ + + World world = Minecraft.getMinecraft().theWorld; + Entity caster = world.getEntityByID(message.casterID); + // Moved from when the packet is sent to when it is received; fixes the sound not playing in first person. + caster.playSound(SoundEvents.BLOCK_PORTAL_TRAVEL, 1, 1); + + for(int i=0; i<20; i++){ + double radius = 1; + double angle = world.rand.nextDouble()*Math.PI*2; + double x = caster.posX + radius*Math.cos(angle); + double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble()*2; + double z = caster.posZ + radius*Math.sin(angle); + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSparkle(world, x, y, z, 0, 0.02, 0, 0.6f, 1.0f, 0.6f, 80 + world.rand.nextInt(10))); + } + for(int i=0; i<20; i++){ + double radius = 1; + double angle = world.rand.nextDouble()*Math.PI*2; + double x = caster.posX + radius*Math.cos(angle); + double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble()*2; + double z = caster.posZ + radius*Math.sin(angle); + world.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, x, y, z, 0, 0.02, 0); + } + for(int i=0; i<20; i++){ + double radius = 1; + double angle = world.rand.nextDouble()*Math.PI*2; + double x = caster.posX + radius*Math.cos(angle); + double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble()*2; + double z = caster.posZ + radius*Math.sin(angle); + world.spawnParticle(EnumParticleTypes.ENCHANTMENT_TABLE, x, y, z, 0, 0.02, 0); + } + } + + @Override + public void handlePlayerSyncPacket(Message message){ + + WizardData properties = WizardData.get(Minecraft.getMinecraft().thePlayer); + + if(properties != null){ + + properties.spellsDiscovered = message.spellsDiscovered; + + if(message.selectedMinionID == -1){ + properties.selectedMinion = null; + }else{ + Entity entity = Minecraft.getMinecraft().theWorld.getEntityByID(message.selectedMinionID); + + if(entity instanceof ISummonedCreature){ + properties.selectedMinion = new WeakReference((ISummonedCreature)entity); + }else{ + properties.selectedMinion = null; + } + } + } + } + + @Override + public void handleGlyphDataPacket(electroblob.wizardry.packet.PacketGlyphData.Message message){ + + SpellGlyphData data = SpellGlyphData.get(Minecraft.getMinecraft().theWorld); + + data.randomNames = new HashMap(); + data.randomDescriptions = new HashMap(); + + for(Spell spell : Spell.getSpells(Spell.allSpells)){ + // -1 because the none spell isn't included + data.randomNames.put(spell, message.names.get(spell.id() - 1)); + data.randomDescriptions.put(spell, message.descriptions.get(spell.id() - 1)); + } + } + + @Override + public void handleClairvoyancePacket(electroblob.wizardry.packet.PacketClairvoyance.Message message) { + Clairvoyance.spawnPathPaticles(Minecraft.getMinecraft().theWorld, message.path, message.durationMultiplier); + } + + // SECTION Rendering + // =============================================================================================================== + + private static final ResourceLocation ICE_WRAITH_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_wraith.png"); + private static final ResourceLocation LIGHTNING_WRAITH_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_wraith.png"); + /** Static instance of the statue renderer, used to access the block breaking texture. */ + public static RenderStatue renderStatue; + + @Override + public void initialiseLayers(){ + LayerStone.initialiseLayers(); + } + + @Override + public void registerRenderers(){ + + // Minions + // Yet another advantage to the new system: turns out you don't even need to register the renderer if you + // just want the vanilla one for the mob you're extending. + + // An anonymous class in a lambda expression! No point writing a separate class really, is there? + RenderingRegistry.registerEntityRenderingHandler(EntityLightningWraith.class, manager -> new RenderBlaze(manager){ + @Override + protected ResourceLocation getEntityTexture(EntityBlaze entity){ + return LIGHTNING_WRAITH_TEXTURE; + } + }); + + RenderingRegistry.registerEntityRenderingHandler(EntityIceWraith.class, manager -> new RenderBlaze(manager){ + @Override + protected ResourceLocation getEntityTexture(EntityBlaze entity){ + return ICE_WRAITH_TEXTURE; + } + }); + + RenderingRegistry.registerEntityRenderingHandler(EntityIceGiant.class, RenderIceGiant::new); + RenderingRegistry.registerEntityRenderingHandler(EntityPhoenix.class, RenderPhoenix::new); + + // Projectiles + RenderingRegistry.registerEntityRenderingHandler(EntityMagicMissile.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/magic_missile.png"), false, 8.0, 4.0, 16, 9, false)); + RenderingRegistry.registerEntityRenderingHandler(EntityIceShard.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ice_shard.png"), false, 8.0, 2.0, 16, 5, false)); + RenderingRegistry.registerEntityRenderingHandler(EntityLightningArrow.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_arrow.png"), true, 8.0, 2.0, 16, 5, false)); + RenderingRegistry.registerEntityRenderingHandler(EntityDart.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/dart.png"), false, 8.0, 2.0, 16, 5, true)); + RenderingRegistry.registerEntityRenderingHandler(EntityIceLance.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ice_lance.png"), false, 16.0, 3.0, 22, 5, true)); + + RenderingRegistry.registerEntityRenderingHandler(EntityForceArrow.class, RenderForceArrow::new); + + // Creatures + RenderingRegistry.registerEntityRenderingHandler(EntitySpiritWolf.class, manager -> new RenderSpiritWolf(manager, 0.5f)); + RenderingRegistry.registerEntityRenderingHandler(EntitySpiritHorse.class, manager -> new RenderSpiritHorse(manager, 0.5f)); + RenderingRegistry.registerEntityRenderingHandler(EntityWizard.class, RenderWizard::new); + RenderingRegistry.registerEntityRenderingHandler(EntityEvilWizard.class, RenderEvilWizard::new); + RenderingRegistry.registerEntityRenderingHandler(EntityDecoy.class, RenderDecoy::new); + + // Throwables + RenderingRegistry.registerEntityRenderingHandler(EntitySparkBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/spark_bomb.png"), false)); + RenderingRegistry.registerEntityRenderingHandler(EntityFirebomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/firebomb.png"), false)); + RenderingRegistry.registerEntityRenderingHandler(EntityPoisonBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/poison_bomb.png"), false)); + RenderingRegistry.registerEntityRenderingHandler(EntityIceCharge.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/ice_charge.png"), false)); + RenderingRegistry.registerEntityRenderingHandler(EntityForceOrb.class, manager -> new RenderProjectile(manager, 0.7f, new ResourceLocation(Wizardry.MODID, "textures/entity/force_orb.png"), true)); + RenderingRegistry.registerEntityRenderingHandler(EntitySpark.class, manager -> new RenderProjectile(manager, 0.4f, new ResourceLocation(Wizardry.MODID, "textures/entity/spark.png"), true)); + RenderingRegistry.registerEntityRenderingHandler(EntityDarknessOrb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/darkness_orb.png"), true)); + RenderingRegistry.registerEntityRenderingHandler(EntityFirebolt.class, manager -> new RenderProjectile(manager, 0.2f, new ResourceLocation(Wizardry.MODID, "textures/entity/firebolt.png"), false)); + RenderingRegistry.registerEntityRenderingHandler(EntityLightningDisc.class, manager -> new RenderLightningDisc(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_sigil.png"), 2.0f)); + RenderingRegistry.registerEntityRenderingHandler(EntitySmokeBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/smoke_bomb.png"), false)); + + // Effects and constructs + RenderingRegistry.registerEntityRenderingHandler(EntityArc.class, RenderArc::new); + RenderingRegistry.registerEntityRenderingHandler(EntityBlackHole.class, RenderBlackHole::new); + RenderingRegistry.registerEntityRenderingHandler(EntityShield.class, RenderBlank::new); + RenderingRegistry.registerEntityRenderingHandler(EntityBubble.class, RenderBubble::new); + RenderingRegistry.registerEntityRenderingHandler(EntityHammer.class, RenderHammer::new); + RenderingRegistry.registerEntityRenderingHandler(EntityIceSpike.class, RenderIceSpike::new); + + // Stuff that doesn't render + RenderingRegistry.registerEntityRenderingHandler(EntityBlizzard.class, RenderBlank::new); + RenderingRegistry.registerEntityRenderingHandler(EntityTornado.class, RenderBlank::new); + RenderingRegistry.registerEntityRenderingHandler(EntityArrowRain.class, RenderBlank::new); + RenderingRegistry.registerEntityRenderingHandler(EntityShadowWraith.class, RenderBlank::new); + RenderingRegistry.registerEntityRenderingHandler(EntityForcefield.class, RenderBlank::new); + RenderingRegistry.registerEntityRenderingHandler(EntityThunderbolt.class, RenderBlank::new); + RenderingRegistry.registerEntityRenderingHandler(EntityStormElemental.class, RenderBlank::new); + RenderingRegistry.registerEntityRenderingHandler(EntityEarthquake.class, RenderBlank::new); + RenderingRegistry.registerEntityRenderingHandler(EntityHailstorm.class, RenderBlank::new); + + // Runes on ground + RenderingRegistry.registerEntityRenderingHandler(EntityHealAura.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/healing_aura.png"), 5.0f, false)); + RenderingRegistry.registerEntityRenderingHandler(EntityFireSigil.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/fire_sigil.png"), 2.0f, true)); + RenderingRegistry.registerEntityRenderingHandler(EntityFrostSigil.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/frost_sigil.png"), 2.0f, true)); + RenderingRegistry.registerEntityRenderingHandler(EntityLightningSigil.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_sigil.png"), 2.0f, true)); + RenderingRegistry.registerEntityRenderingHandler(EntityFireRing.class, manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png"), 5.0f)); + RenderingRegistry.registerEntityRenderingHandler(EntityDecay.class, RenderDecay::new); + RenderingRegistry.registerEntityRenderingHandler(EntityLightningPulse.class, manager -> new RenderLightningPulse(manager, 8.0f)); + + // TESRs + ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench()); + ClientRegistry.bindTileEntitySpecialRenderer(TileEntityStatue.class, renderStatue = new RenderStatue()); + ClientRegistry.bindTileEntitySpecialRenderer(TileEntityMagicLight.class, new RenderMagicLight()); + + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/EntityNameEntry.java b/src/main/java/electroblob/wizardry/client/EntityNameEntry.java new file mode 100644 index 00000000..3221e189 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/EntityNameEntry.java @@ -0,0 +1,76 @@ +package electroblob.wizardry.client; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.EntityList; +import net.minecraftforge.fml.client.config.GuiButtonExt; +import net.minecraftforge.fml.client.config.GuiEditArray; +import net.minecraftforge.fml.client.config.GuiEditArrayEntries; +import net.minecraftforge.fml.client.config.GuiEditArrayEntries.StringEntry; +import net.minecraftforge.fml.client.config.GuiSelectString; +import net.minecraftforge.fml.client.config.IConfigElement; + +/** [NYI] Intended as a way of choosing entities by name from all those currently registered, within the config file, so + * that users don't have to look up the entity IDs. I can't get this to work correctly at the moment. */ +public class EntityNameEntry extends StringEntry { + + protected final GuiButtonExt btnValue; + protected Object entityClass; + + public EntityNameEntry(GuiEditArray owningScreen, GuiEditArrayEntries owningEntryList, IConfigElement configElement, Object value) + { + super(owningScreen, owningEntryList, configElement, value); + this.btnValue = new GuiButtonExt(0, 0, 0, owningEntryList.controlWidth, 18, I18n.format(this.textFieldValue.getText())); + //this.btnValue.enabled = owningScreen.enabled; + } + + @Override + public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected) + { + //super.drawEntry(slotIndex, x, y, listWidth, slotHeight, tessellator, mouseX, mouseY, isSelected); + this.btnValue.xPosition = listWidth / 4; + this.btnValue.yPosition = y; + + String trans = I18n.format(this.textFieldValue.getText()); + if (!trans.equals(this.textFieldValue.getText())) + this.btnValue.displayString = trans; + else + this.btnValue.displayString = this.textFieldValue.getText(); + //btnValue.packedFGColour = value ? GuiUtils.getColorCode('2', true) : GuiUtils.getColorCode('4', true); + + this.btnValue.drawButton(owningEntryList.getMC(), mouseX, mouseY); + } + + @Override + public boolean mousePressed(int index, int x, int y, int mouseEvent, int relativeX, int relativeY) + { + if (this.btnValue.mousePressed(owningEntryList.getMC(), x, y)) + { + btnValue.playPressSound(owningEntryList.getMC().getSoundHandler()); + // Some sort of type incompatiblity meant that I had to do this first. + Map map = new HashMap(EntityList.CLASS_TO_NAME); + Minecraft.getMinecraft().displayGuiScreen(new GuiSelectString(this.owningScreen, configElement, index, map, this.getValue(), true)); + owningEntryList.recalculateState(); + return true; + } + + return super.mousePressed(index, x, y, mouseEvent, relativeX, relativeY); + } + + @Override + public void mouseReleased(int index, int x, int y, int mouseEvent, int relativeX, int relativeY) + { + this.btnValue.mouseReleased(x, y); + super.mouseReleased(index, x, y, mouseEvent, relativeX, relativeY); + } + + @Override + public Object getValue() + { + return this.textFieldValue.getText(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/GuiArcaneWorkbench.java b/src/main/java/electroblob/wizardry/client/GuiArcaneWorkbench.java new file mode 100644 index 00000000..43f0470a --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/GuiArcaneWorkbench.java @@ -0,0 +1,230 @@ +package electroblob.wizardry.client; + +import org.lwjgl.input.Keyboard; + +import electroblob.wizardry.SpellGlyphData; +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.packet.PacketControlInput; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.tileentity.ContainerArcaneWorkbench; +import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; +import electroblob.wizardry.util.WandHelper; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +public class GuiArcaneWorkbench extends GuiContainer { + + private GuiButton applyBtn; + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png"); + + private IInventory playerInventory; + private IInventory arcaneWorkbenchInventory; + + private final int tooltipWidth = 164; + + public GuiArcaneWorkbench(InventoryPlayer invPlayer, TileEntityArcaneWorkbench entity) { + super(new ContainerArcaneWorkbench(invPlayer, entity)); + this.playerInventory = invPlayer; + this.arcaneWorkbenchInventory = entity; + xSize = 176; + ySize = 220; + } + + @Override + public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_){ + + // Tests if there is a wand in the workbench and edits the positioning accordingly + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){ + guiLeft = (this.width - this.xSize - tooltipWidth)/2; + this.applyBtn.xPosition = (this.width - tooltipWidth)/2 + 48; + }else{ + guiLeft = (this.width - this.xSize)/2; + this.applyBtn.xPosition = this.width/2 + 48; + } + + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack()){ + this.applyBtn.enabled = true; + }else{ + this.applyBtn.enabled = false; + } + + super.drawScreen(p_73863_1_, p_73863_2_, p_73863_3_); + } + + @Override + public void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) { + + GlStateManager.pushAttrib(); + + GlStateManager.color(1F, 1F, 1F, 1F); + Minecraft.getMinecraft().renderEngine.bindTexture(texture); + + // Main inventory + drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); + + // Changing slots + for(int i=0; i=0 && slot.yDisplayPosition >= 0) + this.drawTexturedModalRect(guiLeft + slot.xDisplayPosition - 10, guiTop + slot.yDisplayPosition - 10, + 0, 220, 36, 36); + } + + // Tooltip only drawn if there is a wand + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){ + + // Tooltip box + drawTexturedModalRect(guiLeft + xSize, guiTop, xSize, 0, 256 - xSize - 4, ySize); + drawTexturedModalRect(guiLeft + 252, guiTop, xSize + 4, 0, tooltipWidth - 2*(256 - xSize - 4), ySize); + drawTexturedModalRect(guiLeft + xSize + tooltipWidth - (256 - xSize - 4), guiTop, xSize + 4, 0, 256 - xSize - 4, ySize); + + ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack(); + + Spell[] spells = WandHelper.getSpells(wand); + + int i=0; + + for(Spell spell : spells){ + + boolean discovered = true; + + if(!this.mc.thePlayer.capabilities.isCreativeMode && WizardData.get(this.mc.thePlayer) != null){ + discovered = WizardData.get(this.mc.thePlayer).hasSpellBeenDiscovered(spell); + } + // As of Wizardry 1.2, the icons have been split off into their own texture files to allow for add-on + // mods to add their own. + Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.element.getIcon() : Element.MAGIC.getIcon()); + + // Renders the little element icon + WizardryUtilities.drawTexturedRect(guiLeft + xSize + 5, guiTop + 34 + 10*i++, 8, 8); + } + + int x = 0; + int y = guiTop + 50 + spells.length*10; + + // Look how much shorter this is with the WandHelper class! + for(Item item : WandHelper.getSpecialUpgrades()){ + + int level = WandHelper.getUpgradeLevel(wand, item); + + if(level > 0){ + ItemStack stack = new ItemStack(item, level); + GlStateManager.enableDepth(); + this.itemRender.renderItemAndEffectIntoGUI(stack, guiLeft + xSize + 6 + x, y); + this.itemRender.renderItemOverlayIntoGUI(this.fontRendererObj, stack, guiLeft + xSize + 6 + x, y, null); + x += 18; + GlStateManager.disableDepth(); + } + } + } + + Minecraft.getMinecraft().renderEngine.bindTexture(texture); + + // Fixes the bug that caused the slot hightlight to render opaque. I don't know why it works, it just works! + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + + GlStateManager.popAttrib(); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){ + + this.fontRendererObj.drawString(this.arcaneWorkbenchInventory.hasCustomName() ? this.arcaneWorkbenchInventory.getName() : I18n.format(this.arcaneWorkbenchInventory.getName()), 8, 6, 4210752); + this.fontRendererObj.drawString(this.playerInventory.hasCustomName() ? this.playerInventory.getName() : I18n.format(this.playerInventory.getName()), 8, this.ySize - 96 + 2, 4210752); + + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){ + + ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack(); + + this.fontRendererObj.drawStringWithShadow("\u00A7f" + wand.getDisplayName(), xSize + 6, 6, 0); + this.fontRendererObj.drawStringWithShadow("\u00A77" + I18n.format("container.wizardry:arcane_workbench.mana") + " " + (wand.getMaxDamage() - wand.getItemDamage()) + "/" + wand.getMaxDamage(), xSize + 6, 20, 0); + + Spell[] spells = WandHelper.getSpells(wand); + + int y = 34; + + for(Spell spell : spells){ + + boolean discovered = true; + + if(!this.mc.thePlayer.capabilities.isCreativeMode && WizardData.get(this.mc.thePlayer) != null){ + discovered = WizardData.get(this.mc.thePlayer).hasSpellBeenDiscovered(spell); + } + + if(discovered){ + this.fontRendererObj.drawStringWithShadow(spell.getDisplayNameWithFormatting(), xSize + 16, y, 0); + }else{ + this.mc.standardGalacticFontRenderer.drawStringWithShadow("\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.theWorld), xSize + 16, y, 0); + } + y += 10; + } + + if(WandHelper.getTotalUpgrades(wand) > 0){ + + this.fontRendererObj.drawStringWithShadow("\u00A7f" + I18n.format("container.wizardry:arcane_workbench.upgrades"), xSize + 6, y + 6, 0); + + int x = 0; + y = 50 + spells.length*10; + // Wand upgrade tooltips + for(Item item : WandHelper.getSpecialUpgrades()){ + + int level = WandHelper.getUpgradeLevel(wand, item); + + if(level > 0){ + // The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is + // relative to the GUI but the POINT isn't. + if(isPointInRegion(xSize + 6 + x, y, 16, 16, mouseX, mouseY)){ + ItemStack stack = new ItemStack(item, level); + this.renderToolTip(stack, mouseX - guiLeft, mouseY - guiTop); + } + x += 18; + } + } + } + } + } + + @Override + public void initGui(){ + this.mc.thePlayer.openContainer = this.inventorySlots; + this.guiLeft = (this.width - this.xSize) / 2; + this.guiTop = (this.height - this.ySize) / 2; + Keyboard.enableRepeatEvents(true); + this.buttonList.clear(); + this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width/2 + 48, this.height/2 + 3)); + } + + @Override + public void onGuiClosed(){ + super.onGuiClosed(); + Keyboard.enableRepeatEvents(false); + } + + @Override + protected void actionPerformed(GuiButton button){ + if(button.enabled){ + if(button.id == 0){ + // Packet building + IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.APPLY_BUTTON); + WizardryPacketHandler.net.sendToServer(msg); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/GuiButtonApply.java b/src/main/java/electroblob/wizardry/client/GuiButtonApply.java new file mode 100644 index 00000000..fd54d344 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/GuiButtonApply.java @@ -0,0 +1,41 @@ +package electroblob.wizardry.client; + +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.resources.I18n; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +class GuiButtonApply extends GuiButton { + + public GuiButtonApply(int id, int x, int y){ + + super(id, x, y, 32, 16, I18n.format("container.wizardry:arcane_workbench.apply")); + } + + @Override + public void drawButton(Minecraft minecraft, int mouseX, int mouseY){ + + // Whether the button is highlighted + this.hovered = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height; + + int k = 36; + int l = 220; + int colour = 14737632; + + if(this.enabled){ + if(this.hovered){ + k += this.width*2; + colour = 16777120; + } + }else{ + k += this.width; + colour = 10526880; + } + + WizardryUtilities.drawTexturedRect(this.xPosition, this.yPosition, k, l, this.width, this.height, 256, 256); + this.drawCenteredString(minecraft.fontRendererObj, this.displayString, this.xPosition + this.width / 2, this.yPosition + (this.height - 8) / 2, colour); + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/GuiButtonInvisible.java b/src/main/java/electroblob/wizardry/client/GuiButtonInvisible.java new file mode 100644 index 00000000..3cc2f12e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/GuiButtonInvisible.java @@ -0,0 +1,23 @@ +package electroblob.wizardry.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +class GuiButtonInvisible extends GuiButton { + + public GuiButtonInvisible(int id, int x, int y, int width, int height){ + + super(id, x, y, width, height, ""); + } + + /** + * Draws this button to the screen. + */ + public void drawButton(Minecraft par1Minecraft, int par2, int par3){ + this.hovered = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/GuiButtonTurnPage.java b/src/main/java/electroblob/wizardry/client/GuiButtonTurnPage.java new file mode 100644 index 00000000..b4b7e68b --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/GuiButtonTurnPage.java @@ -0,0 +1,52 @@ +package electroblob.wizardry.client; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +class GuiButtonTurnPage extends GuiButton { + + /** True for pointing right (next page), false for pointing left (previous page). */ + private final boolean nextPage; + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png"); + + public GuiButtonTurnPage(int id, int x, int y, boolean isNextPage) + { + super(id, x, y, 23, 13, ""); + this.nextPage = isNextPage; + } + + /** + * Draws this button to the screen. + */ + public void drawButton(Minecraft par1Minecraft, int par2, int par3) + { + if (this.visible) + { + boolean flag = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height; + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + par1Minecraft.getTextureManager().bindTexture(texture); + int k = 0; + int l = 192; + + if (flag) + { + k += 23; + } + + if (!this.nextPage) + { + l += 13; + } + + WizardryUtilities.drawTexturedRect(this.xPosition, this.yPosition, k, l, 23, 13, 288, 256); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/GuiConfigWizardry.java b/src/main/java/electroblob/wizardry/client/GuiConfigWizardry.java new file mode 100644 index 00000000..587a8603 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/GuiConfigWizardry.java @@ -0,0 +1,80 @@ +package electroblob.wizardry.client; + +import java.util.ArrayList; +import java.util.List; + +import electroblob.wizardry.Settings; +import electroblob.wizardry.Wizardry; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import net.minecraftforge.common.config.ConfigElement; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.fml.client.config.DummyConfigElement.DummyCategoryElement; +import net.minecraftforge.fml.client.config.GuiConfig; +import net.minecraftforge.fml.client.config.GuiConfigEntries; +import net.minecraftforge.fml.client.config.GuiConfigEntries.CategoryEntry; +import net.minecraftforge.fml.client.config.IConfigElement; + +public class GuiConfigWizardry extends GuiConfig { + + public GuiConfigWizardry(GuiScreen parent){ + super(parent, getConfigEntries(), Wizardry.MODID, false, false, Wizardry.NAME + " - " + I18n.format("config.wizardry.title.general")); + //this.titleLine2 = "File location: " + Wizardry.config.getConfigFile().getAbsolutePath(); + } + + private static List getConfigEntries(){ + List configList = new ArrayList(1); + configList.add(new DummyCategoryElement("spellsConfig", "config.wizardry.category." + Settings.SPELLS_CATEGORY, SpellsCategory.class)); + configList.add(new DummyCategoryElement("resistancesConfig", "config.wizardry.category." + Settings.RESISTANCES_CATEGORY, ResistancesCategory.class)); + configList.addAll(new ConfigElement(Wizardry.settings.getConfigCategory(Configuration.CATEGORY_GENERAL)).getChildElements()); + return configList; + } + + /** Spells category of the config gui. This adds a button which opens up the spells category config. */ + public static class SpellsCategory extends CategoryEntry + { + public SpellsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop) + { + super(owningScreen, owningEntryList, prop); + } + + @Override + protected GuiScreen buildChildScreen() + { + // This GuiConfig object specifies the configID of the object and as such will force-save when it is closed. + // The parent GuiConfig object's entryList will also be refreshed to reflect the changes. + GuiConfig spellsMenu = new GuiConfig(this.owningScreen, + (new ConfigElement(Wizardry.settings.getConfigCategory(Settings.SPELLS_CATEGORY))).getChildElements(), + this.owningScreen.modID, Settings.SPELLS_CATEGORY, false, false, + Wizardry.NAME + " - " + I18n.format("config.wizardry.title." + Settings.SPELLS_CATEGORY)); + + spellsMenu.titleLine2 = I18n.format("config.wizardry.subtitle." + Settings.SPELLS_CATEGORY); + + return spellsMenu; + } + } + + /** Resistances category of the config gui. */ + public static class ResistancesCategory extends CategoryEntry + { + public ResistancesCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop) + { + super(owningScreen, owningEntryList, prop); + } + + @Override + protected GuiScreen buildChildScreen() + { + // This GuiConfig object specifies the configID of the object and as such will force-save when it is closed. + // The parent GuiConfig object's entryList will also be refreshed to reflect the changes. + GuiConfig idsMenu = new GuiConfig(this.owningScreen, + (new ConfigElement(Wizardry.settings.getConfigCategory(Settings.RESISTANCES_CATEGORY))).getChildElements(), + this.owningScreen.modID, Settings.RESISTANCES_CATEGORY, false, false, + Wizardry.NAME + " - " + I18n.format("config.wizardry.title." + Settings.RESISTANCES_CATEGORY)); + + idsMenu.titleLine2 = I18n.format("config.wizardry.subtitle." + Settings.RESISTANCES_CATEGORY); + + return idsMenu; + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/GuiPortableCrafting.java b/src/main/java/electroblob/wizardry/client/GuiPortableCrafting.java new file mode 100644 index 00000000..d4f8e225 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/GuiPortableCrafting.java @@ -0,0 +1,39 @@ +package electroblob.wizardry.client; + +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ContainerWorkbench; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +/** Crafting table GUI that doesn't require a crafting table container object. */ +public class GuiPortableCrafting extends GuiContainer { + + private static final ResourceLocation craftingTableGuiTextures = new ResourceLocation("textures/gui/container/crafting_table.png"); + + public GuiPortableCrafting(InventoryPlayer p_i1084_1_, World p_i1084_2_, BlockPos pos) + { + super(new ContainerWorkbench(p_i1084_1_, p_i1084_2_, pos)); + } + + /** + * Draw the foreground layer for the GuiContainer (everything in front of the items) + */ + protected void drawGuiContainerForegroundLayer(int p_146979_1_, int p_146979_2_) + { + this.fontRendererObj.drawString(I18n.format("container.crafting"), 28, 6, 4210752); + this.fontRendererObj.drawString(I18n.format("container.inventory"), 8, this.ySize - 96 + 2, 4210752); + } + + protected void drawGuiContainerBackgroundLayer(float p_146976_1_, int p_146976_2_, int p_146976_3_) + { + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + this.mc.getTextureManager().bindTexture(craftingTableGuiTextures); + int k = (this.width - this.xSize) / 2; + int l = (this.height - this.ySize) / 2; + this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.ySize); + } +} diff --git a/src/main/java/electroblob/wizardry/client/GuiSpellBook.java b/src/main/java/electroblob/wizardry/client/GuiSpellBook.java new file mode 100644 index 00000000..c7a90cb2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/GuiSpellBook.java @@ -0,0 +1,127 @@ +package electroblob.wizardry.client; + +import org.lwjgl.input.Keyboard; + +import electroblob.wizardry.SpellGlyphData; +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; + +public class GuiSpellBook extends GuiScreen { + + private int xSize, ySize; + private Spell spell; + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/spellbook.png"); + + public GuiSpellBook(Spell spell) { + super(); + xSize = 288; + ySize = 180; + this.spell = spell; + } + + /** + * Draws the screen and all the components in it. + */ + public void drawScreen(int par1, int par2, float par3) { + + int xPos = this.width/2 - xSize/2; + int yPos = this.height/2 - this.ySize/2; + + EntityPlayer player = Minecraft.getMinecraft().thePlayer; + + boolean discovered = true; + if(Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null + && !WizardData.get(player).hasSpellBeenDiscovered(spell)){ + discovered = false; + } + + // Draws spell illustration on opposite page, underneath the book so it shows through the hole. + Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon()); + WizardryUtilities.drawTexturedRect(xPos + 145, yPos + 20, 0, 0, 128, 128, 128, 128); + + Minecraft.getMinecraft().renderEngine.bindTexture(texture); + WizardryUtilities.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256); + + super.drawScreen(par1, par2, par3); + + if(discovered){ + this.fontRendererObj.drawString(spell.getDisplayName(), xPos+17, yPos+14, 0); + this.fontRendererObj.drawString(spell.type.getDisplayName(), xPos+17, yPos+25, 0x777777); + }else{ + this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(spell, player.worldObj), xPos+17, yPos+14, 0); + this.mc.standardGalacticFontRenderer.drawString(spell.type.getDisplayName(), xPos+17, yPos+25, 0x777777); + } + + this.fontRendererObj.drawString("-------------------", xPos+17, yPos+34, 0); + + if(spell.tier == Tier.BASIC){ + // Basic is usually white but this doesn't show up. + this.fontRendererObj.drawString("Tier: \u00A77" + Tier.BASIC.getDisplayName(), xPos+17, yPos+44, 0); + }else{ + this.fontRendererObj.drawString("Tier: " + spell.tier.getDisplayNameWithFormatting(), xPos+17, yPos+44, 0); + } + + String element = "Element: " + spell.element.getFormattingCode() + spell.element.getDisplayName(); + if(!discovered) element = "Element: ?"; + this.fontRendererObj.drawString(element, xPos+17, yPos+56, 0); + + String manaCost = "Mana Cost: " + spell.cost; + if(spell.isContinuous) manaCost = "Mana Cost: " + spell.cost + "/second"; + if(!discovered) manaCost = "Mana Cost: ?"; + this.fontRendererObj.drawString(manaCost, xPos+17, yPos+68, 0); + + if(discovered){ + this.fontRendererObj.drawSplitString(spell.getDescription(), xPos+17, yPos+82, 118, 0); + }else{ + this.mc.standardGalacticFontRenderer.drawSplitString(SpellGlyphData.getGlyphDescription(spell, player.worldObj), xPos+17, yPos+82, 118, 0); + } + + /* + // Word wrapping + int charNumber = 0; + int lineNumber = 0; + + while(charNumber < spell.desc.length()){ + int lineLength = 0; + String line; + if(spell.desc.length() - charNumber > 22){ + for(int i = charNumber; i < charNumber+23; i++){ + if(spell.desc.charAt(i) == ' '){ + lineLength = i - charNumber; + } + } + line = spell.desc.substring(charNumber, charNumber + lineLength); + }else{ + line = spell.desc.substring(charNumber, spell.desc.length()); + charNumber = spell.desc.length(); + } + this.fontRendererObj.drawString("\u00A7o" + line, xPos+17, yPos+82+10*lineNumber, 0); + charNumber+=(lineLength+1); + lineNumber++; + } + */ + } + + public void initGui() + { + super.initGui(); + Keyboard.enableRepeatEvents(true); + this.buttonList.clear(); + } + + public void onGuiClosed() + { + super.onGuiClosed(); + Keyboard.enableRepeatEvents(false); + } +} + diff --git a/src/main/java/electroblob/wizardry/client/GuiSpellDisplay.java b/src/main/java/electroblob/wizardry/client/GuiSpellDisplay.java new file mode 100644 index 00000000..dc27a3eb --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/GuiSpellDisplay.java @@ -0,0 +1,155 @@ +package electroblob.wizardry.client; + +import java.util.List; + +import electroblob.wizardry.Settings.GuiPosition; +import electroblob.wizardry.SpellGlyphData; +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.WandHelper; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +public class GuiSpellDisplay extends Gui { + + private Minecraft mc; + + private static final ResourceLocation hudTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_hud.png"); + + public GuiSpellDisplay(Minecraft par1Minecraft) { + super(); + this.mc = par1Minecraft; + } + + @SubscribeEvent + public void draw(RenderGameOverlayEvent event){ + + EntityPlayer player = this.mc.thePlayer; + + // If the player has a wand in each hand, only displays for the one in the main hand. + + ItemStack wand = player.getHeldItemMainhand(); + + if(wand == null || !(wand.getItem() instanceof ItemWand)){ + wand = player.getHeldItemOffhand(); + // If the player isn't holding a wand, then nothing else needs to be done. + if(wand == null || !(wand.getItem() instanceof ItemWand)) return; + } + + int width = event.getResolution().getScaledWidth(); + int height = event.getResolution().getScaledHeight(); + + Spell spell = WandHelper.getCurrentSpell(wand); + int cooldown = WandHelper.getCurrentCooldown(wand); + + float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(wand, WizardryItems.cooldown_upgrade)*Constants.COOLDOWN_REDUCTION_PER_LEVEL; + + if(player.isPotionActive(WizardryPotions.font_of_mana)){ + // Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously + cooldownMultiplier /= 2 + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier(); + } + + // Coordinates of the top left corner of the HUD. + int left = 0; + int top = 0; + boolean mirror = false; + + if(Wizardry.settings.spellHUDPosition == GuiPosition.BOTTOM_LEFT){ + left = 0; + top = height-36; + }else if(Wizardry.settings.spellHUDPosition == GuiPosition.TOP_LEFT){ + left = 0; + top = 0; + }else if(Wizardry.settings.spellHUDPosition == GuiPosition.TOP_RIGHT){ + left = width-128; + top = 0; + mirror = true; + }else if(Wizardry.settings.spellHUDPosition == GuiPosition.BOTTOM_RIGHT){ + left = width-128; + top = height-36; + mirror = true; + } + + boolean discovered = true; + + if(!player.capabilities.isCreativeMode && WizardData.get(player) != null){ + discovered = WizardData.get(player).hasSpellBeenDiscovered(spell); + } + + if(event.getType() == RenderGameOverlayEvent.ElementType.TEXT){ + + // Makes spells greyed out if they are in cooldown or if the player has the arcane jammer effect + String colour = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.element.getFormattingCode(); + if(!discovered) colour = "\u00A79"; + String spellName = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.worldObj); + FontRenderer font = discovered ? this.mc.fontRendererObj : this.mc.standardGalacticFontRenderer; + + int maxWidth = 90; + + if(font.getStringWidth(spellName) <= maxWidth){ + // Single line is rendered more centrally + font.drawStringWithShadow(colour + spellName, mirror ? left+5 : left+41, top+13, 0xffffffff); + + }else{ + + int lineNumber = 0; + + List lines = font.listFormattedStringToWidth(spellName, maxWidth); + + for(Object line : lines){ + if(line instanceof String){ + font.drawStringWithShadow(colour + (String)line, mirror ? left+5 : left+41, top+6 + 11*lineNumber, 0xffffffff); + } + lineNumber++; + } + } + + }else if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR){ + + GlStateManager.pushAttrib(); + + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.color(1, 1, 1); + + this.mc.renderEngine.bindTexture(hudTexture); + + // Background of spell hud + this.drawTexturedModalRect(left, top, 0, mirror ? 36 : 0, 128, 36); + + // Cooldown bar + if(cooldown > 0){ + this.drawTexturedModalRect(mirror ? left+5 : left+41, height-8, 128, 6, 82, 6); + + int l = (int)(((double)(spell.cooldown * cooldownMultiplier - cooldown) + / (double)(spell.cooldown * cooldownMultiplier)) * 82); + + this.drawTexturedModalRect(mirror ? left+5 : left+41, height-8, 128, 0, l, 6); + } + + // Spell illustration + this.mc.renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon()); + + WizardryUtilities.drawTexturedRect(mirror ? left+94 : left+2, top+2, 0, 0, 32, 32, 32, 32); + + GlStateManager.popAttrib(); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/client/GuiWizardHandbook.java b/src/main/java/electroblob/wizardry/client/GuiWizardHandbook.java new file mode 100644 index 00000000..5cb8ee9e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/GuiWizardHandbook.java @@ -0,0 +1,809 @@ +package electroblob.wizardry.client; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.Charsets; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +public class GuiWizardHandbook extends GuiScreen { + + private int xSize, ySize; + private int pageNumber = 0; + + private static final int PAGE_WIDTH = 120; + /** The integer colour for black passed into the font renderer methods. This used to be 0 but that's now white + * for some reason, so I've made a it a constant in case it changes again. */ + // I think this is actually ever-so-slightly lighter than pure black, but the difference is unnoticeable. + private static final int BLACK = 1; + + public static final ResourceLocation regularHandbook = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png"); + public static final ResourceLocation ore = new ResourceLocation(Wizardry.MODID, "textures/gui/ore_picture.png"); + public static final ResourceLocation crystal = new ResourceLocation(Wizardry.MODID, "textures/items/magic_crystal.png"); + public static final ResourceLocation workbenchGui = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png"); + public static final ResourceLocation craftingGrids = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook_recipes.png"); + + private ArrayList> text; + private ArrayList

    sections; + + private int guiPage, imagePage; + + public GuiWizardHandbook() { + super(); + xSize = 288; + ySize = 180; + } + + @Override + public void drawScreen(int mouseX, int mouseY, float par3){ + + int xPos = this.width/2 - xSize/2; + int yPos = this.height/2 - this.ySize/2; + + // Tests for crafting recipes section + if(pageNumber >= (sections.get(sections.size()-1).pageNumber-1)/2 && pageNumber < (sections.get(sections.size()-1).pageNumber-1)/2 + 4){ + Minecraft.getMinecraft().renderEngine.bindTexture(craftingGrids); + }else{ + Minecraft.getMinecraft().renderEngine.bindTexture(regularHandbook); + } + + WizardryUtilities.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256); + + // Arcane workbench gui picture + if(pageNumber == (this.guiPage-1)/2){ + Minecraft.getMinecraft().renderEngine.bindTexture(workbenchGui); + this.drawTexturedModalRect(this.guiPage % 2 == 1 ? xPos + 17 : this.width/2 + 7, yPos + 14, 28, 12, 120, 118); + } + + // Magic crystal and crystal ore images + if(pageNumber == (this.imagePage-1)/2){ + + Minecraft.getMinecraft().renderEngine.bindTexture(ore); + WizardryUtilities.drawTexturedRect(this.imagePage % 2 == 1 ? xPos + 17 : this.width/2 + 7, yPos + 80, 0, 0, 64, 64, 64, 64); + + Minecraft.getMinecraft().renderEngine.bindTexture(crystal); + drawTexturedStretchedRect(this.imagePage % 2 == 1 ? xPos + 17 + 64 : this.width/2 + 7 + 62, yPos + 80, 0, 0, 64, 64, 1, 1); + + } + + this.fontRendererObj.drawString("" + (pageNumber*2 + 1), xPos + xSize/4 - 3, yPos + ySize - 20, 0); + this.fontRendererObj.drawString("" + (pageNumber*2 + 2), xPos + 3*xSize/4 - 5, yPos + ySize - 20, 0); + + super.drawScreen(mouseX, mouseY, par3); + + int lineNumber = 0; + + if(pageNumber == 1){ + for(Section s : sections){ + s.drawContents(); + } + }else{ + for(Section s : sections){ + s.hideButton(); + } + } + + for(String paragraph : text.get(pageNumber*2)){ + + this.fontRendererObj.drawSplitString(paragraph, xPos + 17, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, PAGE_WIDTH, BLACK); + + List list = new ArrayList(this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH)); + + lineNumber += list.size(); + } + + lineNumber = 0; + + // Prevents crash when the last page is blank (and hence is not in the list of pages) + if(text.size() > pageNumber*2 + 1){ + for(String paragraph : text.get(pageNumber*2 + 1)){ + + // First page is centred + if(pageNumber == 0){ + int startX = this.width/2 + 7 + PAGE_WIDTH/2 - this.fontRendererObj.getStringWidth(paragraph)/2; + this.fontRendererObj.drawSplitString(paragraph, startX, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, PAGE_WIDTH, BLACK); + }else{ + this.fontRendererObj.drawSplitString(paragraph, this.width/2 + 7, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, PAGE_WIDTH, BLACK); + } + + List list = new ArrayList(this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH)); + + lineNumber += list.size(); + } + } + + ItemStack[][] craftingGrid; + ItemStack craftingResult; + + // Tooltips are rendered after recipes to prevent tooltips on the left appearing behind items on the right. + if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2){ + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.GOLD_NUGGET); + craftingGrid[1][0] = new ItemStack(Blocks.CARPET, 1, 10); + craftingGrid[2][0] = new ItemStack(Items.GOLD_NUGGET); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][1] = new ItemStack(Blocks.LAPIS_BLOCK); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[0][2] = new ItemStack(Blocks.STONE); + craftingGrid[1][2] = new ItemStack(Blocks.STONE); + craftingGrid[2][2] = new ItemStack(Blocks.STONE); + craftingResult = new ItemStack(WizardryBlocks.arcane_workbench); + this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][1] = new ItemStack(Items.STICK); + craftingGrid[0][2] = new ItemStack(Items.GOLD_NUGGET); + craftingResult = new ItemStack(WizardryItems.magic_wand); + this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][1] = new ItemStack(Items.BOOK); + craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal); + craftingResult = new ItemStack(WizardryItems.spell_book, 1, 1); + this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.BOOK); + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal); + craftingResult = new ItemStack(WizardryItems.wizard_handbook); + this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + }else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 1){ + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryBlocks.crystal_flower); + craftingResult = new ItemStack(WizardryItems.magic_crystal, 2); + this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][1] = new ItemStack(Items.GLASS_BOTTLE); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[0][2] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[2][2] = new ItemStack(WizardryItems.magic_crystal); + craftingResult = new ItemStack(WizardryItems.mana_flask); + this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[1][0] = new ItemStack(Blocks.STONE); + craftingGrid[0][1] = new ItemStack(Blocks.STONE); + craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][2] = new ItemStack(Blocks.STONE); + craftingGrid[2][1] = new ItemStack(Blocks.STONE); + craftingResult = new ItemStack(WizardryBlocks.transportation_stone, 2); + this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[1][0] = new ItemStack(Items.STRING); + craftingGrid[0][1] = new ItemStack(Items.STRING); + craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][2] = new ItemStack(Items.STRING); + craftingGrid[2][1] = new ItemStack(Items.STRING); + craftingResult = new ItemStack(WizardryItems.magic_silk, 2); + this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + }else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 2){ + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk); + craftingResult = new ItemStack(WizardryItems.wizard_hat); + this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[1][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[1][2] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk); + craftingResult = new ItemStack(WizardryItems.wizard_robe); + this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk); + craftingResult = new ItemStack(WizardryItems.wizard_leggings); + this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk); + craftingResult = new ItemStack(WizardryItems.wizard_boots); + this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + }else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 3){ + + if(Wizardry.settings.useAlternateScrollRecipe){ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.PAPER); + craftingGrid[1][0] = new ItemStack(Items.STRING); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal); + craftingResult = new ItemStack(WizardryItems.blank_scroll); + this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + }else{ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.PAPER); + craftingGrid[1][0] = new ItemStack(Items.STRING); + craftingResult = new ItemStack(WizardryItems.blank_scroll); + this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + } + + if(Wizardry.settings.firebombIsCraftable){ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.BLAZE_POWDER); + craftingGrid[1][0] = new ItemStack(Items.BLAZE_POWDER); + craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE); + craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER); + craftingResult = new ItemStack(WizardryItems.firebomb, 3); + this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + } + + if(Wizardry.settings.poisonBombIsCraftable){ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.SPIDER_EYE); + craftingGrid[1][0] = new ItemStack(Items.SPIDER_EYE); + craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE); + craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER); + craftingResult = new ItemStack(WizardryItems.poison_bomb, 3); + this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + } + + if(Wizardry.settings.smokeBombIsCraftable){ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.COAL); + craftingGrid[1][0] = new ItemStack(Items.COAL); + craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE); + craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER); + craftingResult = new ItemStack(WizardryItems.smoke_bomb, 3); + this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + } + + } + + if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2){ + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.GOLD_NUGGET); + craftingGrid[1][0] = new ItemStack(Blocks.CARPET, 1, 10); + craftingGrid[2][0] = new ItemStack(Items.GOLD_NUGGET); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][1] = new ItemStack(Blocks.LAPIS_BLOCK); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[0][2] = new ItemStack(Blocks.STONE); + craftingGrid[1][2] = new ItemStack(Blocks.STONE); + craftingGrid[2][2] = new ItemStack(Blocks.STONE); + craftingResult = new ItemStack(WizardryBlocks.arcane_workbench); + this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][1] = new ItemStack(Items.STICK); + craftingGrid[0][2] = new ItemStack(Items.GOLD_NUGGET); + craftingResult = new ItemStack(WizardryItems.magic_wand); + this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][1] = new ItemStack(Items.BOOK); + craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal); + craftingResult = new ItemStack(WizardryItems.spell_book, 1, 1); + this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.BOOK); + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal); + craftingResult = new ItemStack(WizardryItems.wizard_handbook); + this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + }else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 1){ + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryBlocks.crystal_flower); + craftingResult = new ItemStack(WizardryItems.magic_crystal, 2); + this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][1] = new ItemStack(Items.GLASS_BOTTLE); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[0][2] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[2][2] = new ItemStack(WizardryItems.magic_crystal); + craftingResult = new ItemStack(WizardryItems.mana_flask); + this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[1][0] = new ItemStack(Blocks.STONE); + craftingGrid[0][1] = new ItemStack(Blocks.STONE); + craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][2] = new ItemStack(Blocks.STONE); + craftingGrid[2][1] = new ItemStack(Blocks.STONE); + craftingResult = new ItemStack(WizardryBlocks.transportation_stone, 2); + this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[1][0] = new ItemStack(Items.STRING); + craftingGrid[0][1] = new ItemStack(Items.STRING); + craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal); + craftingGrid[1][2] = new ItemStack(Items.STRING); + craftingGrid[2][1] = new ItemStack(Items.STRING); + craftingResult = new ItemStack(WizardryItems.magic_silk, 2); + this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + }else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 2){ + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk); + craftingResult = new ItemStack(WizardryItems.wizard_hat); + this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[1][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[1][2] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk); + craftingResult = new ItemStack(WizardryItems.wizard_robe); + this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk); + craftingResult = new ItemStack(WizardryItems.wizard_leggings); + this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk); + craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk); + craftingResult = new ItemStack(WizardryItems.wizard_boots); + this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + + }else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 3){ + + if(Wizardry.settings.useAlternateScrollRecipe){ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.PAPER); + craftingGrid[1][0] = new ItemStack(Items.STRING); + craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal); + craftingResult = new ItemStack(WizardryItems.blank_scroll); + this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + }else{ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.PAPER); + craftingGrid[1][0] = new ItemStack(Items.STRING); + craftingResult = new ItemStack(WizardryItems.blank_scroll); + this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + } + + if(Wizardry.settings.firebombIsCraftable){ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.BLAZE_POWDER); + craftingGrid[1][0] = new ItemStack(Items.BLAZE_POWDER); + craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE); + craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER); + craftingResult = new ItemStack(WizardryItems.firebomb, 3); + this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + } + + if(Wizardry.settings.poisonBombIsCraftable){ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.SPIDER_EYE); + craftingGrid[1][0] = new ItemStack(Items.SPIDER_EYE); + craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE); + craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER); + craftingResult = new ItemStack(WizardryItems.poison_bomb, 3); + this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult); + } + + if(Wizardry.settings.smokeBombIsCraftable){ + craftingGrid = new ItemStack[3][3]; + craftingGrid[0][0] = new ItemStack(Items.COAL); + craftingGrid[1][0] = new ItemStack(Items.COAL); + craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE); + craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER); + craftingResult = new ItemStack(WizardryItems.smoke_bomb, 3); + this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult); + } + + } + } + + private void renderCraftingRecipe(int xPos, int yPos, int mouseX, int mouseY, ItemStack[][] craftingGrid, ItemStack craftingResult) { + + GlStateManager.pushMatrix(); + RenderHelper.enableGUIStandardItemLighting(); + GlStateManager.disableLighting(); + GlStateManager.enableRescaleNormal(); + GL11.glEnable(GL11.GL_COLOR_MATERIAL); + GlStateManager.enableLighting(); + itemRender.zLevel = 100.0F; + + for(int i=0; i>(1); + sections = new ArrayList
    (1); + + BufferedReader bufferedreader = null; + + String textFilepath = "wizardry:texts/handbook_" + Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".txt"; + + try { + + bufferedreader = new BufferedReader(new InputStreamReader(this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), Charsets.UTF_8)); + + } catch (IOException e){ + + Wizardry.logger.info("Wizard handbook text file missing for the current language. Using default (English - US) instead."); + + textFilepath = "wizardry:texts/handbook_en_US.txt"; + + try { + + bufferedreader = new BufferedReader(new InputStreamReader(this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), Charsets.UTF_8)); + + } catch (IOException x){ + Wizardry.logger.error("Couldn't find file: wizardry:assets/texts/handbook_en_US.txt. The file may be" + + "missing; please try re-downloading and reinstalling Wizardry.", x); + } + } + + if(bufferedreader != null){ + + try { + + String paragraph = bufferedreader.readLine(); + ArrayList page = new ArrayList(1); + + int linesPerPage = 16; + + int lineNumber = 0; + + while(paragraph != null){ + + //System.out.println(paragraph); + + if(paragraph.contains("PAGEBREAK") || lineNumber >= linesPerPage){ + + text.add(page); + + page = new ArrayList(1); + + lineNumber = 0; + + if(paragraph.contains("PAGEBREAK")) paragraph = bufferedreader.readLine(); + + }else if(paragraph.contains("LINEBREAK")){ + + lineNumber++; + + page.add(""); + + paragraph = bufferedreader.readLine(); + + }else if(paragraph.contains("SECTION")){ + + sections.add(new Section(paragraph.replace("SECTION ", ""), text.size() + 1, this.width/2 + 7, + this.height/2 - this.ySize/2 + 14 + (sections.size()+2)*this.fontRendererObj.FONT_HEIGHT, nextButtonId++)); + paragraph = bufferedreader.readLine(); + + }else if(paragraph.contains("IMAGE")){ + + if(paragraph.contains("WORKBENCH")){ + this.guiPage = text.size() + 1; + }else if(paragraph.contains("CRYSTAL")){ + this.imagePage = text.size() + 1; + } + + paragraph = bufferedreader.readLine(); + + }else{ + + paragraph = paragraph.replaceAll("NEXT_SPELL_KEY", Keyboard.getKeyName(ClientProxy.NEXT_SPELL.getKeyCode())); + paragraph = paragraph.replaceAll("PREVIOUS_SPELL_KEY", Keyboard.getKeyName(ClientProxy.PREVIOUS_SPELL.getKeyCode())); + paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL_MINUS_30", "" + (Constants.MANA_PER_CRYSTAL - 30)); + paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL", "" + Constants.MANA_PER_CRYSTAL); + paragraph = paragraph.replaceAll("BASIC_MAX_CHARGE", "" + Tier.BASIC.maxCharge); + paragraph = paragraph.replaceAll("APPRENTICE_MAX_CHARGE", "" + Tier.APPRENTICE.maxCharge); + paragraph = paragraph.replaceAll("ADVANCED_MAX_CHARGE", "" + Tier.ADVANCED.maxCharge); + paragraph = paragraph.replaceAll("MASTER_MAX_CHARGE", "" + Tier.MASTER.maxCharge); + paragraph = paragraph.replaceAll("BASIC_COLOUR", "\u00A77"); + paragraph = paragraph.replaceAll("APPRENTICE_COLOUR", Tier.APPRENTICE.getFormattingCode()); + paragraph = paragraph.replaceAll("ADVANCED_COLOUR", Tier.ADVANCED.getFormattingCode()); + paragraph = paragraph.replaceAll("MASTER_COLOUR", Tier.MASTER.getFormattingCode()); + paragraph = paragraph.replaceAll("FIRE_COLOUR", Element.FIRE.getFormattingCode()); + paragraph = paragraph.replaceAll("ICE_COLOUR", Element.ICE.getFormattingCode()); + paragraph = paragraph.replaceAll("LIGHTNING_COLOUR", Element.LIGHTNING.getFormattingCode()); + paragraph = paragraph.replaceAll("NECROMANCY_COLOUR", Element.NECROMANCY.getFormattingCode()); + paragraph = paragraph.replaceAll("EARTH_COLOUR", Element.EARTH.getFormattingCode()); + paragraph = paragraph.replaceAll("SORCERY_COLOUR", Element.SORCERY.getFormattingCode()); + paragraph = paragraph.replaceAll("HEALING_COLOUR", Element.HEALING.getFormattingCode()); + paragraph = paragraph.replaceAll("RESET_COLOUR", "\u00A70"); + paragraph = paragraph.replaceAll("VERSION", Wizardry.VERSION); + + int linesInParagraph = this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH).size(); + + // Ignores empty lines at the top of a page. + if(paragraph.isEmpty() && lineNumber == 0){ + + paragraph = bufferedreader.readLine(); + + // Normal paragraph, all on one page + }else if(lineNumber + linesInParagraph <= linesPerPage){ + + page.add(paragraph); + + lineNumber += linesInParagraph; + + paragraph = bufferedreader.readLine(); + + // Paragraphs split across two pages (or more?) + }else{ + + int linesInFirstPart = linesPerPage - lineNumber; + + String paragraphFirstPart = ""; + String paragraphLastPart = ""; + + int i = 0; + + List strings = this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH); + + for(Object s : strings){ + if(i < linesInFirstPart){ + paragraphFirstPart = paragraphFirstPart.concat((String)s + " "); + }else{ + paragraphLastPart = paragraphLastPart.concat((String)s + " "); + } + i++; + } + + //System.out.println("Paragraph crosses page boundary; string split into: \"" + paragraphFirstPart + "\" and \"" + paragraphLastPart + "\""); + + page.add(paragraphFirstPart); + + lineNumber += linesInFirstPart; + + paragraph = paragraphLastPart; + } + } + } + + text.add(page); + + } catch (IOException e){ + Wizardry.logger.error("Something went wrong reading file: " + textFilepath + ". The file may be damaged;" + + "please try re-downloading and reinstalling wizardry.", e); + } + } + } + + private class Section { + + /** The integer text colour used for the section when it is moused over. Currently orange. */ + private static final int HIGHLIGHT_COLOUR = 0xdd4c1d; + + String name; + int pageNumber; + int x, y; + int buttonId; + + Section(String name, int pageNumber, int x, int y, int id){ + this.name = name; + this.pageNumber = pageNumber; + this.x = x; + this.y = y; + this.buttonId = id; + GuiWizardHandbook.this.buttonList.add(new GuiButtonInvisible(id, x, y, GuiWizardHandbook.PAGE_WIDTH, GuiWizardHandbook.this.fontRendererObj.FONT_HEIGHT)); + } + + void hideButton(){ + GuiWizardHandbook.this.buttonList.get(buttonId).visible = false; + } + + void drawContents(){ + + GuiWizardHandbook.this.buttonList.get(buttonId).visible = true; + + GuiWizardHandbook.this.fontRendererObj.drawString(name, x, y, GuiWizardHandbook.this.buttonList.get(buttonId).isMouseOver() ? HIGHLIGHT_COLOUR : BLACK); + + int nameWidth = GuiWizardHandbook.this.fontRendererObj.getStringWidth(name); + + String dotsAndNumber = " " + this.pageNumber; + + while(GuiWizardHandbook.this.fontRendererObj.getStringWidth(dotsAndNumber) < GuiWizardHandbook.PAGE_WIDTH - nameWidth - 2){ + dotsAndNumber = "." + dotsAndNumber; + } + + GuiWizardHandbook.this.fontRendererObj.drawString(dotsAndNumber, x + GuiWizardHandbook.PAGE_WIDTH - GuiWizardHandbook.this.fontRendererObj.getStringWidth(dotsAndNumber), y, BLACK); + } + } + + @Override + public void onGuiClosed() + { + super.onGuiClosed(); + Keyboard.enableRepeatEvents(false); + } + + /** + * Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e). + */ + @Override + protected void actionPerformed(GuiButton par1GuiButton){ + + if(par1GuiButton.enabled){ + if(par1GuiButton.id == 0){ + if(pageNumber < (text.size()-1)/2) pageNumber++; + }else if(par1GuiButton.id == 1){ + if(pageNumber > 0) pageNumber--; + }else{ + if(pageNumber == 1) pageNumber = (sections.get(par1GuiButton.id - 2).pageNumber-1)/2; + } + } + } + + /** + * Args: left, top, width, height, pointX, pointY. Note: left, top are local to Gui, pointX, pointY are local to + * screen + */ + protected boolean isPointInRegion(int par1, int par2, int par3, int par4, int par5, int par6) + { + int k1 = this.width/2 - xSize/2; + int l1 = this.height/2 - this.ySize/2; + par5 -= k1; + par6 -= l1; + return par5 >= par1 - 1 && par5 < par1 + par3 + 1 && par6 >= par2 - 1 && par6 < par2 + par4 + 1; + } + + /** + * Draws a textured rectangle, stretching the section of the image to fit the size given. + * @param x The x position of the rectangle + * @param y The y position of the rectangle + * @param u The x position of the top left corner of the section of the image wanted, expressed as a fraction of the image width + * @param v The y position of the top left corner of the section of the image wanted, expressed as a fraction of the image width + * @param finalWidth The width as rendered + * @param finalHeight The height as rendered + * @param width The width of the section, expressed as a fraction of the image width + * @param height The height of the section, expressed as a fraction of the image width + */ + public static void drawTexturedStretchedRect(int x, int y, int u, int v, int finalWidth, int finalHeight, int width, int height){ + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos((x), y + finalHeight, 0).tex(u, v + height).endVertex(); + buffer.pos(x + finalWidth, y + finalHeight, 0).tex(u + width, v + height).endVertex(); + buffer.pos(x + finalWidth, (y), 0).tex(u + width, v).endVertex(); + buffer.pos((x), (y), 0).tex(u, v).endVertex(); + tessellator.draw(); + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/MixedFontRenderer.java b/src/main/java/electroblob/wizardry/client/MixedFontRenderer.java new file mode 100644 index 00000000..43b51f8b --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/MixedFontRenderer.java @@ -0,0 +1,94 @@ +package electroblob.wizardry.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** Font renderer that renders parts of strings surrounded by '#' (without quotes) in the SGA instead of normal text. + * @since Wizardry 1.1 */ +@SideOnly(Side.CLIENT) +public class MixedFontRenderer extends FontRenderer { + + public MixedFontRenderer(GameSettings p_i1035_1_, ResourceLocation p_i1035_2_, TextureManager p_i1035_3_, + boolean p_i1035_4_) { + super(p_i1035_1_, p_i1035_2_, p_i1035_3_, p_i1035_4_); + } + + @Override + public int drawString(String string, float x, float y, int colour, boolean shadow){ + + int l = 0; + + boolean sga = false; + + while(string.indexOf('#') > -1){ + + String section = string.substring(0, string.indexOf('#')); + + if(sga){ + l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(section, x, y, colour, shadow); + x += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(section); + }else{ + l += Minecraft.getMinecraft().fontRendererObj.drawString(section, x, y, colour, shadow); + x += Minecraft.getMinecraft().fontRendererObj.getStringWidth(section); + } + + string = string.substring(string.indexOf('#') + 1); + sga = !sga; + } + + if(sga){ + l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(string, x, y, colour, shadow); + }else{ + l += Minecraft.getMinecraft().fontRendererObj.drawString(string, x, y, colour, shadow); + } + + return l; + } + + @Override + public int getStringWidth(String string){ + + int l = 0; + + boolean sga = false; + + while(string.indexOf('#') > -1){ + + String section = string.substring(0, string.indexOf('#')); + + if(sga){ + l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(section); + }else{ + l += Minecraft.getMinecraft().fontRendererObj.getStringWidth(section); + } + + string = string.substring(string.indexOf('#') + 1); + sga = !sga; + } + + if(sga){ + l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(string); + }else{ + l += Minecraft.getMinecraft().fontRendererObj.getStringWidth(string); + } + + return l; + } + + // This doesn't work the same way yet + @Override + public void drawSplitString(String string, int x, int y, int width, int colour){ + + if(string.contains("#")){ + Minecraft.getMinecraft().standardGalacticFontRenderer.drawSplitString(string.substring(1), x, y, width, colour); + }else{ + Minecraft.getMinecraft().fontRendererObj.drawSplitString(string, x, y, width, colour); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/client/MovingSoundEntity.java b/src/main/java/electroblob/wizardry/client/MovingSoundEntity.java new file mode 100644 index 00000000..3696e866 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/MovingSoundEntity.java @@ -0,0 +1,59 @@ +package electroblob.wizardry.client; + +import net.minecraft.client.audio.MovingSound; +import net.minecraft.entity.Entity; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +// Copied from MovingSoundMinecart; if it ever breaks between updates take a look at that. +@SideOnly(Side.CLIENT) +public class MovingSoundEntity extends MovingSound +{ + private final Entity source; + private float distance = 0.0F; + + public MovingSoundEntity(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat) + { + // Uses BLOCKS because that's the closest thing to inanimate entities. Could use NEUTRAL like MovingSoundMinecart. + super(sound, SoundCategory.BLOCKS); + this.source = entity; + this.repeat = repeat; + this.volume = volume; + this.pitch = pitch; + this.repeatDelay = 0; + } + + /** + * Updates the JList with a new model. + */ + @Override + public void update() + { + if (this.source.isDead && repeat) + { + this.donePlaying = true; + } + else + { + this.xPosF = (float)this.source.posX; + this.yPosF = (float)this.source.posY; + this.zPosF = (float)this.source.posZ; + float f = MathHelper.sqrt_double(this.source.motionX * this.source.motionX + this.source.motionY * this.source.motionY + this.source.motionZ * this.source.motionZ); + + // Is this something to do with the Doppler effect? + if ((double)f >= 0.01D) + { + this.distance = MathHelper.clamp_float(this.distance + 0.0025F, 0.0F, 1.0F); + this.volume = 0.0F + MathHelper.clamp_float(f, 0.0F, 0.5F) * 0.7F; + } + else + { + //this.pitch = 0.0F; + //this.volume = 0.0F; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java new file mode 100644 index 00000000..84b0d552 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java @@ -0,0 +1,752 @@ +package electroblob.wizardry.client; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.item.ItemSpectralBow; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.packet.PacketControlInput; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.spell.Flight; +import electroblob.wizardry.spell.ShadowWard; +import electroblob.wizardry.spell.Shield; +import electroblob.wizardry.tileentity.ContainerArcaneWorkbench; +import electroblob.wizardry.util.WandHelper; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.RayTraceResult; +import net.minecraftforge.client.event.FOVUpdateEvent; +import net.minecraftforge.client.event.MouseEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.client.event.RenderLivingEvent; +import net.minecraftforge.client.event.RenderPlayerEvent; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.relauncher.Side; + +/** + * Event handler responsible for all client-side only events, mostly rendering. + * @author Electroblob + * @since Wizardry 1.0 + */ +@Mod.EventBusSubscriber(Side.CLIENT) +public final class WizardryClientEventHandler { + + private static final ResourceLocation shieldTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/shield.png"); + private static final ResourceLocation wingTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/wing.png"); + private static final ResourceLocation shadowWardTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/shadow_ward.png"); + private static final ResourceLocation sixthSenseTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/sixth_sense.png"); + private static final ResourceLocation sixthSenseOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/sixth_sense_overlay.png"); + private static final ResourceLocation frostOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/frost_overlay.png"); + private static final ResourceLocation pointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/pointer.png"); + private static final ResourceLocation targetPointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/target_pointer.png"); + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_CRYSTAL); + event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_UPGRADE); + } + + // Shift-scrolling to change spells + @SubscribeEvent + public static void onMouseEvent(MouseEvent event){ + + EntityPlayer player = Minecraft.getMinecraft().thePlayer; + ItemStack wand = player.getHeldItemMainhand(); + + if(wand == null || !(wand.getItem() instanceof ItemWand)){ + wand = player.getHeldItemOffhand(); + // If the player isn't holding a wand, then nothing else needs to be done. + if(wand == null || !(wand.getItem() instanceof ItemWand)) return; + } + + if(Minecraft.getMinecraft().inGameHasFocus && wand != null && event.getDwheel() != 0 && player.isSneaking() + && Wizardry.settings.enableShiftScrolling){ + + event.setCanceled(true); + + if(event.getDwheel() > 0){ + // Packet building + IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY); + WizardryPacketHandler.net.sendToServer(msg); + + }else if(event.getDwheel() < 0){ + // Packet building + IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY); + WizardryPacketHandler.net.sendToServer(msg); + } + } + } + + @SubscribeEvent + public static void onFOVUpdateEvent(FOVUpdateEvent event){ + + // Bow zoom. Taken directly from AbstractClientPlayer so it works exactly like vanilla. + if(event.getEntity().isHandActive() && event.getEntity().getActiveItemStack() != null + && event.getEntity().getActiveItemStack().getItem() instanceof ItemSpectralBow){ + + int maxUseTicks = event.getEntity().getItemInUseMaxCount(); + + float maxUseSeconds = (float)maxUseTicks / 20.0F; + + if(maxUseSeconds > 1.0F){ + maxUseSeconds = 1.0F; + }else{ + maxUseSeconds = maxUseSeconds * maxUseSeconds; + } + + event.setNewfov(event.getFov() * 1.0F - maxUseSeconds * 0.15F); + } + } + + // Third person + @SubscribeEvent + public static void onRenderPlayerEvent(RenderPlayerEvent.Post event){ + renderShieldIfActive(event.getEntityPlayer()); + renderWingsIfActive(event.getEntityPlayer(), event.getPartialRenderTick()); + renderShadowWardIfActive(event.getEntityPlayer()); + } + + // First person + @SubscribeEvent + public static void onRenderWorldLastEvent(RenderWorldLastEvent event){ + // Now only fires in first person. + if(Minecraft.getMinecraft().gameSettings.thirdPersonView == 0){ + renderShieldFirstPerson(Minecraft.getMinecraft().thePlayer); + renderShadowWardFirstPerson(Minecraft.getMinecraft().thePlayer); + } + } + + @SubscribeEvent + public static void onRenderLivingEvent(RenderLivingEvent.Post event){ + /* + // Frost effect + if(event.entity.isPotionActive(Wizardry.frost)){ + + GlStateManager.pushMatrix(); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + float someScalingFactor = 0.0625f; + + float yaw = event.entity.prevRotationYaw; + + //int brightness = event.entity.getBrightnessForRender(0); + + //int j = brightness % 65536; + //int k = brightness / 65536; + //OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F); + //GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + + GlStateManager.translate(event.x, event.y, event.z); + + GlStateManager.rotate(-yaw + 180, 0F, 1F, 0F); + + Render render = renderManager.getEntityRenderObject(event.entity); + + RenderLiving renderliving = event.renderer; + + // Reflection + + try { + + Timer timer = ReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "timer"); + + // Chooses the appropriate zombie model, normal or villager + // Fixed by moving before the model fields are accessed + if(render instanceof RenderZombie && event.entity instanceof EntityZombie){ + // The second argument is never used... + ReflectionHelper.findMethod(RenderZombie.class, (RenderZombie)render, new String[]{"func_82427_a"}, EntityZombie.class) + .invoke(renderliving, (EntityZombie)event.entity); + } + + // Turns out that java automatically infers the type parameter T in this method from the type + // I am assigning the returned value to. Neat! + ModelBase mainModel = ReflectionHelper.getPrivateValue(RenderLiving.class, renderliving, "mainModel"); + + mainModel.isRiding = event.entity.isRiding(); + mainModel.isChild = event.entity.isChild(); + + GlStateManager.enableRescaleNormal(); + GlStateManager.scale(-1.0F, -1.0F, 1.0F); + + // The second argument is never used... + ReflectionHelper.findMethod(RenderLiving.class, renderliving, new String[]{"preRenderCallback"}, EntityLivingBase.class, float.class) + .invoke(renderliving, event.entity, someScalingFactor); + + // Why is this -1.5f? No idea! + GlStateManager.translate(0, -1.5f, 0); + + float f6 = event.entity.prevLimbSwingAmount + (event.entity.limbSwingAmount - event.entity.prevLimbSwingAmount) * timer.renderPartialTicks; + float f7 = event.entity.limbSwing - event.entity.limbSwingAmount * (1.0F - timer.renderPartialTicks); + + if (event.entity.isChild()) + { + f7 *= 3.0F; + } + + if (f6 > 1.0F) + { + f6 = 1.0F; + } + + mainModel.setLivingAnimations(event.entity, f7, f6, timer.renderPartialTicks); + + GlStateManager.enableAlpha(); + GlStateManager.color(0.5f, 0.7f, 1, 0.5f); + + mainModel.render(event.entity, f7, f6, 0, 0, 0, someScalingFactor); + + GL11.glDepthMask(true); + + // 'Pokemon' exception handling... Because why not?! + } catch (Exception e) { + System.err.println("Something went very wrong! Error while rendering frost effect:"); + e.printStackTrace(); + } + + GlStateManager.disableAlpha(); + GlStateManager.disableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.disableRescaleNormal(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GlStateManager.popMatrix(); + } + */ + + Minecraft mc = Minecraft.getMinecraft(); + WizardData properties = WizardData.get(mc.thePlayer); + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.theWorld, mc.thePlayer, 16); + RenderManager renderManager = event.getRenderer().getRenderManager(); + + ItemStack wand = mc.thePlayer.getHeldItemMainhand(); + + if(wand == null || !(wand.getItem() instanceof ItemWand)){ + wand = mc.thePlayer.getHeldItemOffhand(); + } + + // Target selection pointer + if(mc.thePlayer.isSneaking() && wand != null && wand.getItem() instanceof ItemWand && rayTrace != null + && rayTrace.entityHit instanceof EntityLivingBase && rayTrace.entityHit == event.getEntity() + && properties != null && properties.selectedMinion != null){ + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + GlStateManager.pushMatrix(); + + GlStateManager.disableCull(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + // Disabling depth test allows it to be seen through everything. + GL11.glDisable(GL11.GL_DEPTH_TEST); + GlStateManager.color(1, 1, 1, 1); + + GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ()); + + // This counteracts the reverse rotation behaviour when in front f5 view. + // Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example. + float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX; + GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + mc.renderEngine.bindTexture(targetPointerTexture); + + buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex(); + buffer.pos(0.2, 0.24, 0).tex(9f/16f, 0).endVertex(); + buffer.pos(0.2, -0.24, 0).tex(9f/16f, 11f/16f).endVertex(); + buffer.pos(-0.2, -0.24, 0).tex(0, 11f/16f).endVertex(); + + tessellator.draw(); + + GlStateManager.enableCull(); + GlStateManager.enableLighting(); + GL11.glEnable(GL11.GL_DEPTH_TEST); + + GlStateManager.popMatrix(); + } + + // Summoned creature selection pointer + if(properties != null && properties.selectedMinion != null && properties.selectedMinion.get() == event.getEntity()){ + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + GlStateManager.pushMatrix(); + + GlStateManager.disableCull(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + // Disabling depth test allows it to be seen through everything. + GL11.glDisable(GL11.GL_DEPTH_TEST); + GlStateManager.color(1, 1, 1, 1); + + GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ()); + + // This counteracts the reverse rotation behaviour when in front f5 view. + // Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example. + float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX; + GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + mc.renderEngine.bindTexture(pointerTexture); + + buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex(); + buffer.pos(0.2, 0.24, 0).tex(9f/16f, 0).endVertex(); + buffer.pos(0.2, -0.24, 0).tex(9f/16f, 11f/16f).endVertex(); + buffer.pos(-0.2, -0.24, 0).tex(0, 11f/16f).endVertex(); + + tessellator.draw(); + + GlStateManager.enableCull(); + GlStateManager.enableLighting(); + GL11.glEnable(GL11.GL_DEPTH_TEST); + + GlStateManager.popMatrix(); + } + + // Sixth sense + if(mc.thePlayer.isPotionActive(WizardryPotions.sixth_sense) && event.getEntity() != mc.thePlayer + && mc.thePlayer.getActivePotionEffect(WizardryPotions.sixth_sense) != null + && event.getEntity().getDistanceToEntity(mc.thePlayer) < 20*(1+mc.thePlayer.getActivePotionEffect(WizardryPotions.sixth_sense).getAmplifier()*Constants.RANGE_INCREASE_PER_LEVEL)){ + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + GlStateManager.pushMatrix(); + + GlStateManager.disableCull(); + GlStateManager.enableBlend(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + // Disabling depth test allows it to be seen through everything. + GL11.glDisable(GL11.GL_DEPTH_TEST); + + GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height * 0.6, event.getZ()); + + // This counteracts the reverse rotation behaviour when in front f5 view. + // Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example. + float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX; + GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + mc.renderEngine.bindTexture(sixthSenseTexture); + + buffer.pos(-0.6, 0.6, 0).tex(0, 0).endVertex(); + buffer.pos(0.6, 0.6, 0).tex(1, 0).endVertex(); + buffer.pos(0.6, -0.6, 0).tex(1, 1).endVertex(); + buffer.pos(-0.6, -0.6, 0).tex(0, 1).endVertex(); + + tessellator.draw(); + + GlStateManager.enableCull(); + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + GL11.glEnable(GL11.GL_DEPTH_TEST); + + GlStateManager.popMatrix(); + } + } + + @SubscribeEvent + public static void onRenderGameOverlayEvent(RenderGameOverlayEvent.Post event){ + + if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET + && Minecraft.getMinecraft().thePlayer.isPotionActive(WizardryPotions.sixth_sense)){ + + GlStateManager.pushMatrix(); + + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glDepthMask(false); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.disableAlpha(); + Minecraft.getMinecraft().renderEngine.bindTexture(sixthSenseOverlayTexture); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex(); + buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D).endVertex(); + buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex(); + buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex(); + tessellator.draw(); + + GL11.glDepthMask(true); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GlStateManager.enableAlpha(); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + GlStateManager.popMatrix(); + } + + if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET + && Minecraft.getMinecraft().thePlayer.isPotionActive(WizardryPotions.frost)){ + + GlStateManager.pushMatrix(); + + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glDepthMask(false); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.disableAlpha(); + Minecraft.getMinecraft().renderEngine.bindTexture(frostOverlayTexture); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex(); + buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D).endVertex(); + buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex(); + buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex(); + + tessellator.draw(); + GL11.glDepthMask(true); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GlStateManager.enableAlpha(); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + GlStateManager.popMatrix(); + } + } + + // FIXME: Something in here is making the first person shadow ward rather translucent. + private static void renderShadowWardFirstPerson(EntityPlayer entityplayer){ + ItemStack wand = entityplayer.getActiveItemStack(); + if(WizardData.get(entityplayer) != null && WizardData.get(entityplayer).currentlyCasting() instanceof ShadowWard || (entityplayer.isHandActive() && wand != null && wand.getItemDamage() < wand.getMaxDamage() + && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){ + + GlStateManager.pushMatrix(); + + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + GlStateManager.disableLighting(); + GlStateManager.disableAlpha(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.translate(0, 1.2, 0); + GlStateManager.rotate(-entityplayer.rotationYaw, 0, 1, 0); + GlStateManager.rotate(entityplayer.rotationPitch, 1, 0, 0); + + Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture); + + GlStateManager.pushMatrix(); + + GlStateManager.translate(0, 0, 1.2); + GlStateManager.rotate(entityplayer.worldObj.getWorldTime()*-2, 0, 0, 1); + GlStateManager.scale(1.1, 1.1, 1.1); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); + buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); + buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); + buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); + buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); + buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); + buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + + GlStateManager.popMatrix(); + + } + } + + private static void renderShadowWardIfActive(EntityPlayer entityplayer){ + ItemStack wand = entityplayer.getActiveItemStack(); + if(WizardData.get(entityplayer).currentlyCasting() instanceof ShadowWard || (entityplayer.isHandActive() && wand != null + && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){ + + GlStateManager.pushMatrix(); + + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.rotate(180, 0, 1, 0); + GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0); + + Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + GlStateManager.translate(0, 1.2, 0); + GlStateManager.rotate(entityplayer.worldObj.getWorldTime()*-2, 0, 0, 1); + GlStateManager.scale(1.1, 1.1, 1.1); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); + buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); + buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); + buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); + buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); + buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); + buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + + GlStateManager.popMatrix(); + + } + } + + private static void renderWingsIfActive(EntityPlayer entityplayer, float partialTickTime){ + ItemStack wand = entityplayer.getActiveItemStack(); + if(WizardData.get(entityplayer).currentlyCasting() instanceof Flight || (entityplayer.isHandActive() && wand != null + && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Flight)){ + + GlStateManager.pushMatrix(); + + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + //GlStateManager.rotate(-entityplayer.rotationYawHead, 0, 1, 0); + GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0); + //GlStateManager.rotate(180, 1, 0, 0); + + Minecraft.getMinecraft().renderEngine.bindTexture(wingTexture); + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + GlStateManager.pushMatrix(); + + GlStateManager.translate(0.1, 0.4, -0.15); + GlStateManager.rotate(20 + 20*(float)Math.sin(entityplayer.worldObj.getWorldTime()*0.3), 0, 1, 0); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(0, 2, 0).tex(0, 0).endVertex(); + buffer.pos(2, 2, 0).tex(1, 0).endVertex(); + buffer.pos(2, 0, 0).tex(1, 1).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(0, 2, 0).tex(0, 0).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).endVertex(); + buffer.pos(2, 0, 0).tex(1, 1).endVertex(); + buffer.pos(2, 2, 0).tex(1, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + + GlStateManager.pushMatrix(); + + GlStateManager.translate(-0.1, 0.4, -0.15); + GlStateManager.rotate(-200 - 20*(float)Math.sin(entityplayer.worldObj.getWorldTime()*0.3), 0, 1, 0); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(0, 2, 0).tex(0, 0).endVertex(); + buffer.pos(2, 2, 0).tex(1, 0).endVertex(); + buffer.pos(2, 0, 0).tex(1, 1).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(0, 2, 0).tex(0, 0).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).endVertex(); + buffer.pos(2, 0, 0).tex(1, 1).endVertex(); + buffer.pos(2, 2, 0).tex(1, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + + GlStateManager.popMatrix(); + } + } + + private static void renderShieldFirstPerson(EntityPlayer entityplayer){ + ItemStack wand = entityplayer.getActiveItemStack(); + if(WizardData.get(entityplayer) != null && WizardData.get(entityplayer).shield != null && (WizardData.get(entityplayer).currentlyCasting() instanceof Shield || (entityplayer.isHandActive() && wand != null + && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Shield))){ + + GlStateManager.pushMatrix(); + + GlStateManager.disableCull(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.translate(0, 1.4, 0); + + GlStateManager.rotate(-entityplayer.rotationYaw, 0, 1, 0); + GlStateManager.rotate(entityplayer.rotationPitch, 1, 0, 0); + + GlStateManager.translate(0, 0, 0.8); + + Tessellator tessellator = Tessellator.getInstance(); + + Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture); + + renderShield(tessellator); + + GlStateManager.enableLighting(); + + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableCull(); + GlStateManager.disableBlend(); + //RenderHelper.enableStandardItemLighting(); + + GlStateManager.popMatrix(); + } + } + + private static void renderShieldIfActive(EntityPlayer entityplayer){ + ItemStack wand = entityplayer.getActiveItemStack(); + if(WizardData.get(entityplayer).shield != null && (WizardData.get(entityplayer).currentlyCasting() instanceof Shield || (entityplayer.isHandActive() && wand != null + && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Shield))){ + + GlStateManager.pushMatrix(); + + GlStateManager.disableCull(); + GlStateManager.enableBlend(); + // For some reason, the old blend function (GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA) caused the inner + // edges to appear black, so I have changed it to this, which looks very slightly different. + GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.translate(0, 1.3, 0); + + //GlStateManager.rotate(180, 0, 1, 0); + GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0); + //GlStateManager.rotate(-entityplayer.rotationPitch, 1, 0, 0); + + GlStateManager.translate(0, 0, 0.8); + + Tessellator tessellator = Tessellator.getInstance(); + + Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture); + + renderShield(tessellator); + + GlStateManager.enableLighting(); + + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableCull(); + GlStateManager.disableBlend(); + //RenderHelper.enableStandardItemLighting(); + + GlStateManager.popMatrix(); + } + } + + private static void renderShield(Tessellator tessellator){ + + VertexBuffer buffer = tessellator.getBuffer(); + + double widthOuter = 0.6d; + double heightOuter = 0.7d; + double widthInner = 0.3d; + double heightInner = 0.4d; + double depth = 0.2d; + + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); + + buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); + buffer.pos(-widthInner, heightOuter, -depth).tex(0.2, 0).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); + + buffer.pos(widthInner, heightOuter, -depth).tex(0.8, 0).color(0, 0, 0, 255).endVertex(); + buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex(); + buffer.pos(widthOuter, heightInner, -depth).tex(1, 0.2).color(0, 0, 0, 255).endVertex(); + buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex(); + + buffer.pos(widthOuter, -heightInner, -depth).tex(1, 0.8).color(0, 0, 0, 255).endVertex(); + buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex(); + buffer.pos(widthInner, -heightOuter, -depth).tex(0.8, 1).color(0, 0, 0, 255).endVertex(); + buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex(); + + buffer.pos(-widthInner, -heightOuter, -depth).tex(0.2, 1).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex(); + buffer.pos(-widthOuter, -heightInner, -depth).tex(0, 0.8).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex(); + + buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); + + buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); + buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex(); + buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex(); + buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex(); + + tessellator.draw(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/model/ModelHammer.java b/src/main/java/electroblob/wizardry/client/model/ModelHammer.java new file mode 100644 index 00000000..e1445f05 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/model/ModelHammer.java @@ -0,0 +1,83 @@ +package electroblob.wizardry.client.model; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; + +public class ModelHammer extends ModelBase +{ + ModelRenderer Shape1; + ModelRenderer Shape2; + ModelRenderer Shape3; + ModelRenderer Shape4; + ModelRenderer Shape5; + ModelRenderer Shape6; + + public ModelHammer() + { + textureWidth = 64; + textureHeight = 64; + + Shape1 = new ModelRenderer(this, 0, 0); + Shape1.addBox(0F, 0F, 0F, 20, 12, 12); + Shape1.setRotationPoint(-10F, 12F, -6F); + Shape1.setTextureSize(64, 64); + Shape1.mirror = true; + setRotation(Shape1, 0F, 0F, 0F); + Shape2 = new ModelRenderer(this, 0, 24); + Shape2.addBox(0F, 0F, 0F, 4, 14, 4); + Shape2.setRotationPoint(-2F, -2F, -2F); + Shape2.setTextureSize(64, 64); + Shape2.mirror = true; + setRotation(Shape2, 0F, 0F, 0F); + Shape3 = new ModelRenderer(this, 0, 49); + Shape3.addBox(0F, 0F, 0F, 5, 5, 5); + Shape3.setRotationPoint(-2.5F, -7F, -2.5F); + Shape3.setTextureSize(64, 64); + Shape3.mirror = true; + setRotation(Shape3, 0F, 0F, 0F); + Shape4 = new ModelRenderer(this, 0, 42); + Shape4.addBox(0F, 0F, 0F, 5, 2, 5); + Shape4.setRotationPoint(-2.5F, 10F, -2.5F); + Shape4.setTextureSize(64, 64); + Shape4.mirror = true; + setRotation(Shape4, 0F, 0F, 0F); + Shape5 = new ModelRenderer(this, 20, 24); + Shape5.addBox(0F, 0F, 0F, 2, 14, 14); + Shape5.setRotationPoint(-8F, 11F, -7F); + Shape5.setTextureSize(64, 64); + Shape5.mirror = true; + setRotation(Shape5, 0F, 0F, 0F); + Shape6 = new ModelRenderer(this, 20, 24); + Shape6.addBox(0F, 0F, 0F, 2, 14, 14); + Shape6.setRotationPoint(6F, 11F, -7F); + Shape6.setTextureSize(64, 64); + Shape6.mirror = true; + setRotation(Shape6, 0F, 0F, 0F); + } + + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) + { + super.render(entity, f, f1, f2, f3, f4, f5); + setRotationAngles(f, f1, f2, f3, f4, f5, entity); + Shape1.render(f5); + Shape2.render(f5); + Shape3.render(f5); + Shape4.render(f5); + Shape5.render(f5); + Shape6.render(f5); + } + + private void setRotation(ModelRenderer model, float x, float y, float z) + { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } + + public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity) + { + super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/model/ModelIceGiant.java b/src/main/java/electroblob/wizardry/client/model/ModelIceGiant.java new file mode 100644 index 00000000..4a8591d7 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/model/ModelIceGiant.java @@ -0,0 +1,321 @@ +package electroblob.wizardry.client.model; + +import javax.vecmath.Matrix4f; +import javax.vecmath.Vector3f; + +import electroblob.wizardry.entity.living.EntityIceGiant; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ModelIceGiant extends ModelBase +{ + /** The head model for the iron golem. */ + public ModelRenderer iceGiantHead; + + /** The body model for the iron golem. */ + public ModelRenderer iceGiantBody; + + /** The right arm model for the iron golem. */ + public ModelRenderer iceGiantRightArm; + + /** The left arm model for the iron golem. */ + public ModelRenderer iceGiantLeftArm; + + /** The left leg model for the Iron Golem. */ + public ModelRenderer iceGiantLeftLeg; + + /** The right leg model for the Iron Golem. */ + public ModelRenderer iceGiantRightLeg; + + ModelRenderer headSpike1; + ModelRenderer headSpike2; + ModelRenderer headSpike3; + ModelRenderer headSpike4; + ModelRenderer headSpike5; + ModelRenderer headSpike6; + ModelRenderer headSpike7; + ModelRenderer rightArmSpike1; + ModelRenderer rightArmSpike2; + ModelRenderer leftArmSpike1; + ModelRenderer leftArmSpike2; + ModelRenderer bodySpike1; + ModelRenderer bodySpike2; + ModelRenderer bodySpike3; + ModelRenderer bodySpike4; + ModelRenderer bodySpike5; + + public ModelIceGiant() + { + this(0.0F); + } + + public ModelIceGiant(float par1) + { + this(par1, -7.0F); + } + + public ModelIceGiant(float par1, float par2) + { + short short1 = 128; + short short2 = 128; + + this.iceGiantHead = (new ModelRenderer(this)).setTextureSize(short1, short2); + this.iceGiantHead.setRotationPoint(0.0F, 0.0F + par2, -1.0F); + this.iceGiantHead.setTextureOffset(0, 10).addBox(-6.0F, -14.0F, -6.5F, 12, 12, 12, par1); + + this.iceGiantBody = (new ModelRenderer(this)).setTextureSize(short1, short2); + this.iceGiantBody.setRotationPoint(0.0F, 0.0F + par2, 0.0F); + this.iceGiantBody.setTextureOffset(0, 40).addBox(-9.0F, -2.0F, -6.0F, 18, 12, 11, par1); + this.iceGiantBody.setTextureOffset(0, 70).addBox(-4.5F, 10.0F, -3.0F, 9, 5, 6, par1 + 0.5F); + + this.iceGiantRightArm = (new ModelRenderer(this)).setTextureSize(short1, short2); + this.iceGiantRightArm.setRotationPoint(0.0F, -7.0F, 0.0F); + this.iceGiantRightArm.setTextureOffset(60, 21).addBox(-13.0F, -2.5F, -3.0F, 4, 30, 6, par1); + + this.iceGiantLeftArm = (new ModelRenderer(this)).setTextureSize(short1, short2); + this.iceGiantLeftArm.setRotationPoint(0.0F, -7.0F, 0.0F); + this.iceGiantLeftArm.setTextureOffset(60, 58).addBox(9.0F, -2.5F, -3.0F, 4, 30, 6, par1); + + this.iceGiantLeftLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2); + this.iceGiantLeftLeg.setRotationPoint(-4.0F, 18.0F + par2, 0.0F); + this.iceGiantLeftLeg.setTextureOffset(37, 0).addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1); + + this.iceGiantRightLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2); + this.iceGiantRightLeg.mirror = true; + this.iceGiantRightLeg.setTextureOffset(60, 0).setRotationPoint(5.0F, 18.0F + par2, 0.0F); + this.iceGiantRightLeg.addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1); + + headSpike1 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + headSpike1.addBox(-4F, -4F, 0F, 4, 4, 4); + headSpike1.setRotationPoint(-4F, -10F, -5F); + headSpike1.mirror = true; + setRotationWithEulerYzx(headSpike1, -0.1047198F, -0.5235988F, 0.9599311F); + + headSpike2 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + headSpike2.addBox(0F, -4F, 0F, 4, 4, 4); + headSpike2.setRotationPoint(4F, -16F, 0F); + headSpike2.mirror = true; + setRotationWithEulerYzx(headSpike2, 0.5585054F, 0.9250245F, -0.5235988F); + + headSpike3 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + headSpike3.addBox(-2F, -2F, -2F, 4, 4, 4); + headSpike3.setRotationPoint(4F, -13F, 4F); + headSpike3.mirror = true; + setRotationWithEulerYzx(headSpike3, 0.7853982F, -1.396263F, 0.7853982F); + + headSpike4 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + headSpike4.addBox(-4F, -4F, 0F, 4, 4, 4); + headSpike4.setRotationPoint(-4F, -16F, 0F); + headSpike4.mirror = true; + setRotationWithEulerYzx(headSpike4, 0.5585054F, -0.9250245F, 0.5235988F); + + headSpike5 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + headSpike5.addBox(0F, -4F, 0F, 4, 4, 4); + headSpike5.setRotationPoint(4F, -10F, -5F); + headSpike5.mirror = true; + setRotationWithEulerYzx(headSpike5, 0.5235988F, -0.9599311F, 0.1047198F); + + rightArmSpike1 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + rightArmSpike1.addBox(-2F, -2F, -2F, 4, 4, 4); + rightArmSpike1.setRotationPoint(-11F, -8F, 0F); + rightArmSpike1.mirror = true; + setRotationWithEulerYzx(rightArmSpike1, 0.7853982F, 1.134464F, 0.9599311F); + + headSpike6 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + headSpike6.addBox(-2F, -2F, -2F, 4, 4, 4); + headSpike6.setRotationPoint(-4F, -13F, 4F); + headSpike6.mirror = true; + setRotationWithEulerYzx(headSpike6, 0.7853982F, -1.745329F, 0.7853982F); + + leftArmSpike1 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + leftArmSpike1.addBox(-2F, -2F, -2F, 4, 4, 4); + leftArmSpike1.setRotationPoint(11F, -8F, 0F); + leftArmSpike1.mirror = true; + setRotationWithEulerYzx(leftArmSpike1, 0.7853982F, -1.134464F, -0.9599311F); + + leftArmSpike2 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + leftArmSpike2.addBox(-2F, -2F, -2F, 4, 4, 4); + leftArmSpike2.setRotationPoint(12F, -4F, 0F); + leftArmSpike2.mirror = true; + setRotationWithEulerYzx(leftArmSpike2, 0.7853982F, 0F, -0.9599311F); + + bodySpike1 = new ModelRenderer(this, 32, 69).setTextureSize(short1, short2); + bodySpike1.addBox(-3F, -3F, -3F, 6, 6, 6); + bodySpike1.setRotationPoint(-4F, -4F, 3F); + bodySpike1.mirror = true; + setRotationWithEulerYzx(bodySpike1, 0.2808018F, 0.8096675F, 0.8339369F); + + rightArmSpike2 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + rightArmSpike2.addBox(-2F, -2F, -2F, 4, 4, 4); + rightArmSpike2.setRotationPoint(-12F, -4F, 0F); + rightArmSpike2.mirror = true; + setRotationWithEulerYzx(rightArmSpike2, 0.7853982F, 0F, 0.9599311F); + + bodySpike2 = new ModelRenderer(this, 32, 69).setTextureSize(short1, short2); + bodySpike2.addBox(-3F, -3F, -3F, 6, 6, 6); + bodySpike2.setRotationPoint(4F, -4F, 3F); + bodySpike2.mirror = true; + setRotationWithEulerYzx(bodySpike2, 0.2808018F, -0.8096757F, -0.8339358F); + + bodySpike3 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + bodySpike3.addBox(-2F, -2F, -2F, 4, 4, 4); + bodySpike3.setRotationPoint(6F, -2F, -5F); + bodySpike3.mirror = true; + setRotationWithEulerYzx(bodySpike3, 1.120006F, -1.347726F, -0.8969422F); + + bodySpike4 = new ModelRenderer(this, 32, 69).setTextureSize(short1, short2); + bodySpike4.addBox(-3F, -3F, -3F, 6, 6, 6); + bodySpike4.setRotationPoint(0F, -4F, -4F); + bodySpike4.mirror = true; + setRotationWithEulerYzx(bodySpike4, 0.7853982F, -1.570796F, 0.9599311F); + + headSpike7 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + headSpike7.addBox(-2F, -2F, -2F, 4, 4, 4); + headSpike7.setRotationPoint(0F, -20F, 4F); + headSpike7.mirror = true; + setRotationWithEulerYzx(headSpike7, 0.7853982F, 1.570796F, 0.7853982F); + + bodySpike5 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2); + bodySpike5.addBox(-2F, -2F, -2F, 4, 4, 4); + bodySpike5.setRotationPoint(-6F, -2F, -5F); + bodySpike5.mirror = true; + setRotationWithEulerYzx(bodySpike5, 1.120006F, 1.347725F, 0.896934F); + + this.convertToChild(this.iceGiantHead, headSpike1); + this.convertToChild(this.iceGiantHead, headSpike2); + this.convertToChild(this.iceGiantHead, headSpike3); + this.convertToChild(this.iceGiantHead, headSpike4); + this.convertToChild(this.iceGiantHead, headSpike5); + this.convertToChild(this.iceGiantHead, headSpike6); + this.convertToChild(this.iceGiantHead, headSpike7); + this.convertToChild(this.iceGiantRightArm, rightArmSpike1); + this.convertToChild(this.iceGiantRightArm, rightArmSpike2); + this.convertToChild(this.iceGiantLeftArm, leftArmSpike1); + this.convertToChild(this.iceGiantLeftArm, leftArmSpike2); + this.convertToChild(this.iceGiantBody, bodySpike1); + this.convertToChild(this.iceGiantBody, bodySpike2); + this.convertToChild(this.iceGiantBody, bodySpike3); + this.convertToChild(this.iceGiantBody, bodySpike4); + this.convertToChild(this.iceGiantBody, bodySpike5); + + } + + /** + * Sets the models various rotation angles then renders the model. + */ + public void render(Entity par1Entity, float par2, float par3, float par4, float par5, float par6, float par7) + { + this.setRotationAngles(par2, par3, par4, par5, par6, par7, par1Entity); + this.iceGiantHead.render(par7); + this.iceGiantBody.render(par7); + this.iceGiantLeftLeg.render(par7); + this.iceGiantRightLeg.render(par7); + this.iceGiantRightArm.render(par7); + this.iceGiantLeftArm.render(par7); + } + + /** + * Sets the model's various rotation angles. For bipeds, par1 and par2 are used for animating the movement of arms + * and legs, where par1 represents the time(so that arms and legs swing back and forth) and par2 represents how + * "far" arms and legs can swing at most. + */ + public void setRotationAngles(float par1, float par2, float par3, float par4, float par5, float par6, Entity par7Entity) + { + this.iceGiantHead.rotateAngleY = par4 / (180F / (float)Math.PI); + this.iceGiantHead.rotateAngleX = par5 / (180F / (float)Math.PI); + this.iceGiantLeftLeg.rotateAngleX = -1.5F * this.func_78172_a(par1, 13.0F) * par2; + this.iceGiantRightLeg.rotateAngleX = 1.5F * this.func_78172_a(par1, 13.0F) * par2; + this.iceGiantLeftLeg.rotateAngleY = 0.0F; + this.iceGiantRightLeg.rotateAngleY = 0.0F; + } + + /** + * Used for easily adding entity-dependent animations. The second and third float params here are the same second + * and third as in the setRotationAngles method. + */ + public void setLivingAnimations(EntityLivingBase par1EntityLivingBase, float par2, float par3, float par4) + { + EntityIceGiant entityicegiant = (EntityIceGiant)par1EntityLivingBase; + int i = entityicegiant.getAttackTimer(); + + if (i > 0) + { + this.iceGiantRightArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F); + this.iceGiantLeftArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F); + } + else + { + this.iceGiantRightArm.rotateAngleX = (-0.2F + 1.5F * this.func_78172_a(par2, 13.0F)) * par3; + this.iceGiantLeftArm.rotateAngleX = (-0.2F - 1.5F * this.func_78172_a(par2, 13.0F)) * par3; + } + } + + private float func_78172_a(float par1, float par2) + { + return (Math.abs(par1 % par2 - par2 * 0.5F) - par2 * 0.25F) / (par2 * 0.25F); + } + + /** This is really useful for converting the source from a Techne model export + * which will have absolute rotation points that need to be converted before + * creating the addChild() relationship. [Courtesy of jabelar] */ + protected void convertToChild(ModelRenderer parent, ModelRenderer child) + { + // move child rotation point to be relative to parent + child.rotationPointX -= parent.rotationPointX; + child.rotationPointY -= parent.rotationPointY; + child.rotationPointZ -= parent.rotationPointZ; + // make rotations relative to parent + child.rotateAngleX -= parent.rotateAngleX; + child.rotateAngleY -= parent.rotateAngleY; + child.rotateAngleZ -= parent.rotateAngleZ; + // create relationship + parent.addChild(child); + } + + /** Fixes the Techne rotation order bug. [Courtesy of tprk77] */ + private Vector3f ConvertEulerYzxToZyx(Vector3f eulerYzx) { + // Create a matrix from YZX ordered Euler angles + float a = MathHelper.cos(eulerYzx.x); + float b = MathHelper.sin(eulerYzx.x); + float c = MathHelper.cos(eulerYzx.y); + float d = MathHelper.sin(eulerYzx.y); + float e = MathHelper.cos(eulerYzx.z); + float f = MathHelper.sin(eulerYzx.z); + Matrix4f matrix = new Matrix4f(); + matrix.m00 = c * e; + matrix.m01 = b * d - a * c * f; + matrix.m02 = b * c * f + a * d; + matrix.m10 = f; + matrix.m11 = a * e; + matrix.m12 = -b * e; + matrix.m20 = -d * e; + matrix.m21 = a * d * f + b * c; + matrix.m22 = a * c - b * d * f; + matrix.m33 = 1.0F; + // Create ZYX ordered Euler angles from the matrix + Vector3f eulerZyx = new Vector3f(); + eulerZyx.y = (float) Math.asin(MathHelper.clamp_float(-matrix.m20, -1, 1)); + if (MathHelper.abs(matrix.m20) < 0.99999) { + eulerZyx.x = (float) Math.atan2(matrix.m21, matrix.m22); + eulerZyx.z = (float) Math.atan2(matrix.m10, matrix.m00); + } else { + eulerZyx.x = 0.0F; + eulerZyx.z = (float) Math.atan2(-matrix.m01, matrix.m11); + } + return eulerZyx; + } + + private void setRotationWithEulerYzx(ModelRenderer model, float x, float y, float z) { + Vector3f eulerYzx = new Vector3f(x, y, z); + Vector3f eulerZyx = ConvertEulerYzxToZyx(eulerYzx); + model.rotateAngleX = eulerZyx.x; + model.rotateAngleY = eulerZyx.y; + model.rotateAngleZ = eulerZyx.z; + } +} diff --git a/src/main/java/electroblob/wizardry/client/model/ModelPhoenix.java b/src/main/java/electroblob/wizardry/client/model/ModelPhoenix.java new file mode 100644 index 00000000..568b580c --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/model/ModelPhoenix.java @@ -0,0 +1,139 @@ +package electroblob.wizardry.client.model; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; + +public class ModelPhoenix extends ModelBase { + + ModelRenderer body; + ModelRenderer rightWing; + ModelRenderer leftWing; + ModelRenderer tailFeathers; + ModelRenderer tail; + ModelRenderer head; + ModelRenderer neck; + ModelRenderer beak; + ModelRenderer plume; + + public ModelPhoenix() + { + textureWidth = 64; + textureHeight = 64; + + /* For future reference: + * - setRotationPoint sets the origin of a part relative to that of its parent. + * - The first 3 arguments of addBox set the position of a part relative to its rotation point, and the last + * 3 arguments are the size of the part. + * (This means that rotation point and position seem to be the wrong way round, since changing the rotation point + * will move the component without changing which point on the component it rotates about.) + * - The two integer arguments in the ModelRenderer constructor are the texture offset. + * - Mirror does nothing unless you set it before addBox. + * - Rotation is the usual pitch, yaw, roll. + */ + + body = new ModelRenderer(this, 0, 34); + body.addBox(0F, 0F, -3F, 6, 15, 6); + body.setRotationPoint(-3F, 0F, -5F); + body.setTextureSize(64, 64); + body.mirror = true; + setRotation(body, 0.296706F, 0F, 0F); + + rightWing = new ModelRenderer(this, 0, 0); + rightWing.mirror = true; + rightWing.addBox(-27F, -27F, 0F, 27, 34, 0); + rightWing.setRotationPoint(0F, 5F, 0F); + rightWing.setTextureSize(64, 64); + setRotation(rightWing, 0.1745329F, 0F, 0F); + + leftWing = new ModelRenderer(this, 0, 0); + leftWing.addBox(0F, -27F, 0F, 27, 34, 0); + leftWing.setRotationPoint(6F, 5F, 0F); + leftWing.setTextureSize(64, 64); + setRotation(leftWing, 0.1745329F, 0F, 0F); + + tailFeathers = new ModelRenderer(this, 0, 57); + tailFeathers.addBox(-5F, 0F, 0F, 10, 7, 0); + tailFeathers.setRotationPoint(0F, 7F, 1F); + tailFeathers.setTextureSize(64, 64); + tailFeathers.mirror = true; + setRotation(tailFeathers, 0.5235988F, 0F, 0F); + + tail = new ModelRenderer(this, 20, 55); + tail.addBox(-1F, 0F, -1F, 2, 7, 2); + tail.setRotationPoint(3F, 15F, 2F); + tail.setTextureSize(64, 64); + tail.mirror = true; + setRotation(tail, 0.4014257F, 0F, 0F); + + head = new ModelRenderer(this, 24, 34); + head.addBox(-2F, -4F, -5F, 4, 4, 6); + head.setRotationPoint(0F, -4F, 0F); + head.setTextureSize(64, 64); + head.mirror = true; + setRotation(head, 0F, 0F, 0F); + + neck = new ModelRenderer(this, 24, 44); + neck.addBox(-1F, -4F, -1F, 2, 4, 2); + neck.setRotationPoint(0F, 0F, -4F); + neck.setTextureSize(64, 64); + neck.mirror = true; + setRotation(neck, 0.2443461F, 0F, 0F); + + beak = new ModelRenderer(this, 32, 44); + beak.addBox(-0.5F, 4F, -1F, 1, 2, 3); + beak.setRotationPoint(0F, -5F, -8F); + beak.setTextureSize(64, 64); + beak.mirror = true; + setRotation(beak, 0.2792527F, 0F, 0F); + + plume = new ModelRenderer(this, 28, 50); + plume.addBox(-0.03333334F, 1F, 0F, 0, 5, 5); + plume.setRotationPoint(0F, -7F, 0F); + plume.setTextureSize(64, 64); + plume.mirror = true; + setRotation(plume, 0F, 0F, 0F); + + neck.addChild(head); + head.addChild(plume); + head.addChild(beak); + tail.addChild(tailFeathers); + body.addChild(tail); + body.addChild(rightWing); + body.addChild(leftWing); + } + + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) + { + super.render(entity, f, f1, f2, f3, f4, f5); + setRotationAngles(f, f1, f2, f3, f4, f5, entity); + + //float f6 = (180F / (float)Math.PI); + this.neck.rotateAngleX = f4 / (180F / (float)Math.PI); + this.neck.rotateAngleY = f3 / (180F / (float)Math.PI); + this.neck.rotateAngleZ = 0.0F; + this.body.rotateAngleX = 0.3f + MathHelper.cos(f2 * 0.1F) * 0.15F; + this.body.rotateAngleY = 0.0F; + this.tail.rotateAngleX = this.body.rotateAngleX * 1.1f; + this.tailFeathers.rotateAngleX = this.body.rotateAngleX * 1.2f; + this.rightWing.rotateAngleY = MathHelper.cos(f2 * 0.3F) * (float)Math.PI * 0.15F; + this.leftWing.rotateAngleY = -this.rightWing.rotateAngleY; + + body.render(f5); + neck.render(f5); + } + + private void setRotation(ModelRenderer model, float x, float y, float z) + { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } + + public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity) + { + super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/model/ModelWizard.java b/src/main/java/electroblob/wizardry/client/model/ModelWizard.java new file mode 100644 index 00000000..e10cf45e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/model/ModelWizard.java @@ -0,0 +1,174 @@ +package electroblob.wizardry.client.model; + +import net.minecraft.client.model.ModelBiped; +import net.minecraft.client.model.ModelRenderer; + +public class ModelWizard extends ModelBiped +{ + //fields + ModelRenderer Shape5; + ModelRenderer Shape8; + ModelRenderer Shape9; + ModelRenderer Shape10; + ModelRenderer Shape7; + ModelRenderer Shape11; + ModelRenderer Shape12; + ModelRenderer beard; + ModelRenderer Shape13; + + public ModelWizard() + { + //super(0, 0, 64, 32); + /* + bipedRightLeg = new ModelRenderer(this, 32, 0); // 32 and 0 are the x and y texture offsets respectively. + bipedRightLeg.addBox(-2F, 0F, -2F, 4, 12, 4); // x, y, z, u, v, w. + bipedRightLeg.setRotationPoint(-2F, 12F, 0F); // Rotation point xyz (absolute, not relative) + bipedRightLeg.setTextureSize(64, 64); + bipedRightLeg.mirror = true; + setRotation(bipedRightLeg, 0F, 0F, 0F); + + bipedLeftLeg.mirror = true; + bipedLeftLeg = new ModelRenderer(this, 32, 0); + bipedLeftLeg.addBox(-2F, 0F, -2F, 4, 12, 4); + bipedLeftLeg.setRotationPoint(2F, 12F, 0F); + bipedLeftLeg.setTextureSize(64, 64); + bipedLeftLeg.mirror = true; + setRotation(bipedLeftLeg, 0F, 0F, 0F); + bipedLeftLeg.mirror = false; + + bipedBody = new ModelRenderer(this, 0, 16); + bipedBody.addBox(0F, 0F, 0F, 8, 12, 4); + bipedBody.setRotationPoint(-4F, 0F, -2F); + bipedBody.setTextureSize(64, 64); + bipedBody.mirror = true; + setRotation(bipedBody, 0F, 0F, 0F); + + bipedLeftArm.mirror = true; + bipedLeftArm = new ModelRenderer(this, 48, 0); + bipedLeftArm.addBox(-1F, 0F, -2F, 4, 12, 4); + bipedLeftArm.setRotationPoint(4F, 0F, 0F); + bipedLeftArm.setTextureSize(64, 64); + bipedLeftArm.mirror = true; + setRotation(bipedLeftArm, 0F, 0F, 0F); + bipedLeftArm.mirror = false; + + bipedRightArm = new ModelRenderer(this, 48, 0); + bipedRightArm.addBox(-3F, 0F, -2F, 4, 12, 4); + bipedRightArm.setRotationPoint(-4F, 0F, 0F); + bipedRightArm.setTextureSize(64, 64); + bipedRightArm.mirror = true; + setRotation(bipedRightArm, 0F, 0F, 0F); + + bipedHead = new ModelRenderer(this, 0, 0); + bipedHead.addBox(-4F, -8F, -4F, 8, 8, 8); + bipedHead.setRotationPoint(0F, 0F, 0F); + bipedHead.setTextureSize(64, 64); + bipedHead.mirror = true; + setRotation(bipedHead, 0F, 0F, 0F); + */ + Shape5 = new ModelRenderer(this, 0, 51); + Shape5.addBox(0F, 0F, 0F, 12, 1, 12); + Shape5.setRotationPoint(-6F, -7F, -6F); + Shape5.setTextureSize(64, 64); + Shape5.mirror = true; + setRotation(Shape5, 0F, 0F, 0F); + Shape8 = new ModelRenderer(this, 0, 32); + Shape8.addBox(0F, 0F, 0F, 6, 1, 6); + Shape8.setRotationPoint(-3F, -9F, -3F); + Shape8.setTextureSize(64, 64); + Shape8.mirror = true; + setRotation(Shape8, -0.0349066F, 0F, 0F); + Shape9 = new ModelRenderer(this, 24, 32); + Shape9.addBox(0F, 0F, 0F, 3, 3, 3); + Shape9.setRotationPoint(-1.5F, -13F, -0.5F); + Shape9.setTextureSize(64, 64); + Shape9.mirror = true; + setRotation(Shape9, -0.2511622F, 0F, 0F); + Shape10 = new ModelRenderer(this, 0, 39); + Shape10.addBox(0F, 0F, 0F, 5, 1, 5); + Shape10.setRotationPoint(-2.5F, -10F, -2.5F); + Shape10.setTextureSize(64, 64); + Shape10.mirror = true; + setRotation(Shape10, -0.0698132F, 0F, 0F); + Shape7 = new ModelRenderer(this, 0, 45); + Shape7.addBox(0F, 0F, 0F, 4, 2, 4); + Shape7.setRotationPoint(-2F, -11F, -1.5F); + Shape7.setTextureSize(64, 64); + Shape7.mirror = true; + setRotation(Shape7, -0.1396263F, 0F, 0F); + Shape11 = new ModelRenderer(this, 20, 39); + Shape11.addBox(0F, 0F, 0F, 2, 3, 2); + Shape11.setRotationPoint(-1F, -15F, 1F); + Shape11.setTextureSize(64, 64); + Shape11.mirror = true; + setRotation(Shape11, -0.4363323F, 0F, 0F); + Shape12 = new ModelRenderer(this, 28, 39); + Shape12.addBox(0F, 0F, 0F, 1, 2, 1); + Shape12.setRotationPoint(-0.5F, -16F, 2.5F); + Shape12.setTextureSize(64, 64); + Shape12.mirror = true; + setRotation(Shape12, -0.715585F, 0F, 0F); + beard = new ModelRenderer(this, 32, 0); + beard.addBox(0F, 0F, 0F, 8, 5, 0); + beard.setRotationPoint(-4F, 0F, -4F); + beard.setTextureSize(64, 64); + beard.mirror = true; + setRotation(beard, 0F, 0F, 0F); + Shape13 = new ModelRenderer(this, 36, 16); + Shape13.addBox(4F, 0F, 2F, 8, 20, 6); + Shape13.setRotationPoint(-4F, 0F, -3F); + Shape13.setTextureSize(64, 64); + Shape13.mirror = true; + setRotation(Shape13, 0F, 0F, 0F); + + // Makes head bits move with head + //bipedHead.addChild(Shape5); + bipedHead.addChild(beard); + //bipedHead.addChild(Shape7); + //bipedHead.addChild(Shape8); + //bipedHead.addChild(Shape9); + //bipedHead.addChild(Shape10); + //bipedHead.addChild(Shape11); + //bipedHead.addChild(Shape12); + + // Makes cloak attached to body + //bipedBody.addChild(Shape13); + + // No outer head layer + this.bipedHeadwear.isHidden = true; + } + /* + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) + { + super.render(entity, f, f1, f2, f3, f4, f5); + setRotationAngles(f, f1, f2, f3, f4, f5, entity); + bipedRightLeg.render(f5); + bipedLeftLeg.render(f5); + bipedBody.render(f5); + bipedLeftArm.render(f5); + bipedRightArm.render(f5); + bipedHead.render(f5); + Shape5.render(f5); + Shape8.render(f5); + Shape9.render(f5); + Shape10.render(f5); + Shape7.render(f5); + Shape11.render(f5); + Shape12.render(f5); + Shape6.render(f5); + Shape13.render(f5); + } + */ + private void setRotation(ModelRenderer model, float x, float y, float z) + { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } + /* + public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity) + { + super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); + } +*/ +} diff --git a/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java b/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java new file mode 100644 index 00000000..3829f103 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java @@ -0,0 +1,111 @@ +package electroblob.wizardry.client.model; + +import net.minecraft.client.model.ModelBiped; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; + +public class ModelWizardArmour extends ModelBiped +{ + ModelRenderer Shape1; + ModelRenderer Shape2; + ModelRenderer Shape3; + ModelRenderer Shape4; + ModelRenderer Shape5; + ModelRenderer Shape6; + ModelRenderer Shape7; + ModelRenderer robe; + + public ModelWizardArmour(float scale){ + + super(scale, 0, 64, 64); + + // This is necessary to stop the head from scaling. + this.bipedHead = new ModelRenderer(this, 0, 0); + this.bipedHead.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, 0.1f); + this.bipedHead.setRotationPoint(0.0F, 0.0F + 0, 0.0F); + + Shape1 = new ModelRenderer(this, -16, 32); + Shape1.addBox(-8F, -7F, -8F, 16, 0, 16); + Shape1.setRotationPoint(0F, 0F, 0F); + Shape1.setTextureSize(64, 64); + Shape1.mirror = true; + setRotation(Shape1, 0F, 0F, 0F); + + Shape2 = new ModelRenderer(this, 0, 48); + Shape2.addBox(0F, 0F, 0F, 6, 2, 6); + Shape2.setRotationPoint(-3F, -10F, -3F); + Shape2.setTextureSize(64, 64); + Shape2.mirror = true; + setRotation(Shape2, -0.1396263F, 0F, 0F); + + Shape3 = new ModelRenderer(this, 0, 56); + Shape3.addBox(0F, 0F, 0F, 5, 2, 5); + Shape3.setRotationPoint(-2.5F, -11.53333F, -2F); + Shape3.setTextureSize(64, 64); + Shape3.mirror = true; + setRotation(Shape3, -0.2443461F, 0F, 0F); + + Shape4 = new ModelRenderer(this, 24, 48); + Shape4.addBox(0F, 0F, 0F, 4, 2, 4); + Shape4.setRotationPoint(-2F, -13F, -1F); + Shape4.setTextureSize(64, 64); + Shape4.mirror = true; + setRotation(Shape4, -0.4014257F, 0F, 0F); + + Shape5 = new ModelRenderer(this, 24, 54); + Shape5.addBox(0F, 0F, 0F, 3, 2, 3); + Shape5.setRotationPoint(-1.5F, -14F, 0F); + Shape5.setTextureSize(64, 64); + Shape5.mirror = true; + setRotation(Shape5, -0.5759587F, 0F, 0F); + + Shape6 = new ModelRenderer(this, 20, 59); + Shape6.addBox(0F, 0F, 0F, 2, 2, 2); + Shape6.setRotationPoint(-1F, -14F, 0F); + Shape6.setTextureSize(64, 64); + Shape6.mirror = true; + setRotation(Shape6, 0.3316126F, 0F, 0F); + + Shape7 = new ModelRenderer(this, 28, 59); + Shape7.addBox(0F, 0F, 0F, 1, 1, 3); + Shape7.setRotationPoint(-0.5F, -14.5F, 2F); + Shape7.setTextureSize(64, 64); + Shape7.mirror = true; + setRotation(Shape7, -0.5585054F, 0F, 0F); + + // The robe is now the body + bipedBody = new ModelRenderer(this, 40, 42); + bipedBody.addBox(-4F, 0F, -2F, 8, 18, 4, scale); + bipedBody.setRotationPoint(0F, 0F, 0F); + bipedBody.setTextureSize(64, 64); + bipedBody.mirror = true; + setRotation(bipedBody, 0F, 0F, 0F); + + // Makes the hat rotate with the head. + bipedHead.addChild(Shape1); + bipedHead.addChild(Shape2); + bipedHead.addChild(Shape3); + bipedHead.addChild(Shape4); + bipedHead.addChild(Shape5); + bipedHead.addChild(Shape6); + bipedHead.addChild(Shape7); + // Makes the robe move with the body + //bipedBody.addChild(robe); + } + + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){ + super.render(entity, f, f1, f2, f3, f4, f5); + setRotationAngles(f, f1, f2, f3, f4, f5, entity); + } + + private void setRotation(ModelRenderer model, float x, float y, float z){ + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } + + public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity){ + super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java b/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java new file mode 100644 index 00000000..a1d678ab --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java @@ -0,0 +1,192 @@ +package electroblob.wizardry.client.model; + +import java.util.ArrayList; +import java.util.List; + +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.client.model.ModelLoader; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.oredict.OreDictionary; + +/** + * Class responsible for registering all of wizardry's item (and itemblock) models. + * @author Electroblob + * @since Wizardry 2.1 + */ +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(Side.CLIENT) +public final class WizardryItemModels { + + @SubscribeEvent + public static void register(ModelRegistryEvent event){ + + // ItemBlocks + + registerItemModel(Item.getItemFromBlock(WizardryBlocks.arcane_workbench)); + registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_ore)); + registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_flower)); + registerItemModel(Item.getItemFromBlock(WizardryBlocks.transportation_stone)); + registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_block)); + + // Items + + registerItemModel(WizardryItems.magic_crystal); + + registerItemModel(WizardryItems.magic_wand); + registerItemModel(WizardryItems.apprentice_wand); + registerItemModel(WizardryItems.advanced_wand); + registerItemModel(WizardryItems.master_wand); + + registerItemModel(WizardryItems.spell_book); + // Wildcard registered for wizard trades. + registerItemModel(WizardryItems.spell_book, OreDictionary.WILDCARD_VALUE, "normal"); + registerItemModel(WizardryItems.arcane_tome); + registerItemModel(WizardryItems.wizard_handbook); + + registerItemModel(WizardryItems.basic_fire_wand); + registerItemModel(WizardryItems.basic_ice_wand); + registerItemModel(WizardryItems.basic_lightning_wand); + registerItemModel(WizardryItems.basic_necromancy_wand); + registerItemModel(WizardryItems.basic_earth_wand); + registerItemModel(WizardryItems.basic_sorcery_wand); + registerItemModel(WizardryItems.basic_healing_wand); + + registerItemModel(WizardryItems.apprentice_fire_wand); + registerItemModel(WizardryItems.apprentice_ice_wand); + registerItemModel(WizardryItems.apprentice_lightning_wand); + registerItemModel(WizardryItems.apprentice_necromancy_wand); + registerItemModel(WizardryItems.apprentice_earth_wand); + registerItemModel(WizardryItems.apprentice_sorcery_wand); + registerItemModel(WizardryItems.apprentice_healing_wand); + + registerItemModel(WizardryItems.advanced_fire_wand); + registerItemModel(WizardryItems.advanced_ice_wand); + registerItemModel(WizardryItems.advanced_lightning_wand); + registerItemModel(WizardryItems.advanced_necromancy_wand); + registerItemModel(WizardryItems.advanced_earth_wand); + registerItemModel(WizardryItems.advanced_sorcery_wand); + registerItemModel(WizardryItems.advanced_healing_wand); + + registerItemModel(WizardryItems.master_fire_wand); + registerItemModel(WizardryItems.master_ice_wand); + registerItemModel(WizardryItems.master_lightning_wand); + registerItemModel(WizardryItems.master_necromancy_wand); + registerItemModel(WizardryItems.master_earth_wand); + registerItemModel(WizardryItems.master_sorcery_wand); + registerItemModel(WizardryItems.master_healing_wand); + + registerItemModel(WizardryItems.spectral_sword); + registerItemModel(WizardryItems.spectral_pickaxe); + registerItemModel(WizardryItems.spectral_bow); + + registerItemModel(WizardryItems.mana_flask); + + registerItemModel(WizardryItems.storage_upgrade); + registerItemModel(WizardryItems.siphon_upgrade); + registerItemModel(WizardryItems.condenser_upgrade); + registerItemModel(WizardryItems.range_upgrade); + registerItemModel(WizardryItems.duration_upgrade); + registerItemModel(WizardryItems.cooldown_upgrade); + registerItemModel(WizardryItems.blast_upgrade); + registerItemModel(WizardryItems.attunement_upgrade); + + registerItemModel(WizardryItems.flaming_axe); + registerItemModel(WizardryItems.frost_axe); + + registerItemModel(WizardryItems.firebomb); + registerItemModel(WizardryItems.poison_bomb); + + registerItemModel(WizardryItems.blank_scroll); + registerItemModel(WizardryItems.scroll); + + registerItemModel(WizardryItems.armour_upgrade); + + registerItemModel(WizardryItems.magic_silk); + + registerItemModel(WizardryItems.wizard_hat); + registerItemModel(WizardryItems.wizard_robe); + registerItemModel(WizardryItems.wizard_leggings); + registerItemModel(WizardryItems.wizard_boots); + + registerItemModel(WizardryItems.wizard_hat_fire); + registerItemModel(WizardryItems.wizard_robe_fire); + registerItemModel(WizardryItems.wizard_leggings_fire); + registerItemModel(WizardryItems.wizard_boots_fire); + + registerItemModel(WizardryItems.wizard_hat_ice); + registerItemModel(WizardryItems.wizard_robe_ice); + registerItemModel(WizardryItems.wizard_leggings_ice); + registerItemModel(WizardryItems.wizard_boots_ice); + + registerItemModel(WizardryItems.wizard_hat_lightning); + registerItemModel(WizardryItems.wizard_robe_lightning); + registerItemModel(WizardryItems.wizard_leggings_lightning); + registerItemModel(WizardryItems.wizard_boots_lightning); + + registerItemModel(WizardryItems.wizard_hat_necromancy); + registerItemModel(WizardryItems.wizard_robe_necromancy); + registerItemModel(WizardryItems.wizard_leggings_necromancy); + registerItemModel(WizardryItems.wizard_boots_necromancy); + + registerItemModel(WizardryItems.wizard_hat_earth); + registerItemModel(WizardryItems.wizard_robe_earth); + registerItemModel(WizardryItems.wizard_leggings_earth); + registerItemModel(WizardryItems.wizard_boots_earth); + + registerItemModel(WizardryItems.wizard_hat_sorcery); + registerItemModel(WizardryItems.wizard_robe_sorcery); + registerItemModel(WizardryItems.wizard_leggings_sorcery); + registerItemModel(WizardryItems.wizard_boots_sorcery); + + registerItemModel(WizardryItems.wizard_hat_healing); + registerItemModel(WizardryItems.wizard_robe_healing); + registerItemModel(WizardryItems.wizard_leggings_healing); + registerItemModel(WizardryItems.wizard_boots_healing); + + registerItemModel(WizardryItems.spectral_helmet); + registerItemModel(WizardryItems.spectral_chestplate); + registerItemModel(WizardryItems.spectral_leggings); + registerItemModel(WizardryItems.spectral_boots); + + registerItemModel(WizardryItems.smoke_bomb); + + registerItemModel(WizardryItems.identification_scroll); + } + + // Moved from the proxies + + /** Registers an item model, using the item's registry name as the model name (this + * convention makes it easier to keep track of everything). Variant defaults to "normal". Registers the model + * for metadata 0 automatically, plus all the other metadata values that the item can take, as defined in + * {@link Item#getSubItems(Item, net.minecraft.creativetab.CreativeTabs, java.util.List)}. The passed in item + * must allow null to be passed in for the creative tab parameter in the aforementioned method, or a + * {@link NullPointerException} will result. */ + private static void registerItemModel(Item item){ + + if(item.getHasSubtypes()){ + List items = new ArrayList(); + item.getSubItems(item, null, items); // Client-only method, but we're client-side so this is OK. + for(ItemStack stack : items){ + ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(), new ModelResourceLocation(item.getRegistryName(), "inventory")); + } + } + // Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why! + ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(item.getRegistryName(), "inventory")); + } + + /** Registers an item model for the given metadata, using the item's registry name as the model name (this + * convention makes it easier to keep track of everything). This is intended for registering additional metadata + * values which aren't displayed in the creative menu, for example the wildcard spell book used in wizard trades. */ + private static void registerItemModel(Item item, int metadata, String variant) { + ModelLoader.setCustomModelResourceLocation(item, metadata, new ModelResourceLocation(item.getRegistryName(), variant)); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java new file mode 100644 index 00000000..4ea3114b --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java @@ -0,0 +1,72 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleBlizzard extends ParticleSnow { + + private double angle; + private double radius; + private double speed; + + public ParticleBlizzard(World world, int maxAge, double originX, double originZ, double radius, double yPos){ + super(world, 0, 0, 0, 0, 0, 0, maxAge); + this.angle = this.rand.nextDouble() * Math.PI * 2; + double x = originX - Math.cos(angle)*radius; + double z = originZ + radius*Math.sin(angle); + this.radius = radius; + this.setPosition(x, yPos, z); + this.prevPosX = x; + this.prevPosY = yPos; + this.prevPosZ = z; + if(rand.nextBoolean()){ + speed = rand.nextDouble()*2 + 1; + }else{ + speed = rand.nextDouble()*-2 - 1; + } + this.multipleParticleScaleBy(1.5f); + } + + @Override + public void init(){ + super.init(); + this.fullBrightness = true; + } + +// @Override +// public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ +// if(this.particleAge < this.particleMaxAge / 3 || (this.particleAge + this.particleMaxAge) / 3 % 2 == 0){ +// super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); +// } +// } + + @Override + public void onUpdate(){ + + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + + if(this.particleAge++ >= this.particleMaxAge){ + this.setExpired(); + } + + // This is in radians per tick... + double omega = Math.signum(speed) * ((Math.PI*2)/20 - speed/(20*radius)); + + // v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi. + this.angle += omega; + + this.motionY -= 0.04D * (double)this.particleGravity; + this.motionZ = radius * omega * Math.cos(angle); + this.motionX = radius * omega * Math.sin(angle); + this.moveEntity(motionX, motionY, motionZ); + + if(this.particleAge > this.particleMaxAge / 2){ + this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + } + + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java b/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java new file mode 100644 index 00000000..3d5fa986 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java @@ -0,0 +1,195 @@ +package electroblob.wizardry.client.particle; + +import java.util.List; + +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** + * Abstract superclass for all particles that use custom textures. This is intended to centralise as much code as + * possible; all subclasses need to do is to define the texture to use, how the frames are arranged (and which to + * choose), and any properties like gravity and collisions. + * @author Electroblob + * @since Wizardry 1.2 + */ +@SideOnly(Side.CLIENT) +public abstract class ParticleCustomTexture extends Particle { + + /** True if the particle always renders at full brightness. Defaults to false. */ + protected boolean fullBrightness = false; + + public ParticleCustomTexture(World world, double x, double y, double z, double vx, double vy, double vz){ + super(world, x, y, z, vx, vy, vz); + this.motionX = vx; + this.motionY = vy; + this.motionZ = vz; + this.init(); + } + + public ParticleCustomTexture(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){ + this(world, x, y, z, vx, vy, vz); + this.particleMaxAge = maxAge; + } + + /** Called from both constructors to set constants, avoiding duplicate code. Common fields to set here + * include: particleScale, particleGravity, canCollide, fullBrightness and setting the texture index. */ + public abstract void init(); + /** Returns a ResourceLocation for the particle's texture sheet. Do not create a new ResourceLocation in this + * method, only return a constant. */ + public abstract ResourceLocation getTexture(); + /** Returns how many 'frames' there are in the x direction on the texture. */ + protected abstract int getXFrames(); + /** Returns how many 'frames' there are in the y direction on the texture. */ + protected abstract int getYFrames(); + + /* There are 4 layers of particles, specified as 0-3 by the method below. + * - Layer 0 causes the normal particles.png to be bound to the render engine for normal particles. + * - Layer 1 causes the block textures to be bound to the render engine for digging fx and falling fx. + * - Layer 2 causes the item textures to be bound to the render engine for tool breaking fx, snowballpoofs, slime particles, etc. + * - Layer 3 is not used in vanilla minecraft and was presumably added by forge for exactly this reason. + * This means no texture is bound by vanilla minecraft, meaning you are free to do as you wish without possibly + * overwriting vanilla particles. Mod particles won't be overwritten anyway since they bind their own textures. + * It is of course important to bind the texture every time you render a custom particle, but I don't see how + * you could do it any other way, since you don't have access to EffectRenderer. */ + @Override + public int getFXLayer() { + // This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer. + return 3; + } + + @Override + public void setParticleTextureIndex(int index){ + this.particleTextureIndexX = index % getXFrames(); + this.particleTextureIndexY = index / getYFrames(); + } + + // Overridden to fix the bug with vanilla that makes particles frictionless. (y != y... seriously, Mojang?) + @Override + public void moveEntity(double x, double y, double z){ + + double d0 = y; + + if (this.canCollide) + { + List list = this.worldObj.getCollisionBoxes((Entity)null, this.getEntityBoundingBox().addCoord(x, y, z)); + + for (AxisAlignedBB axisalignedbb : list) + { + y = axisalignedbb.calculateYOffset(this.getEntityBoundingBox(), y); + } + + this.setEntityBoundingBox(this.getEntityBoundingBox().offset(0.0D, y, 0.0D)); + + for (AxisAlignedBB axisalignedbb1 : list) + { + x = axisalignedbb1.calculateXOffset(this.getEntityBoundingBox(), x); + } + + this.setEntityBoundingBox(this.getEntityBoundingBox().offset(x, 0.0D, 0.0D)); + + for (AxisAlignedBB axisalignedbb2 : list) + { + z = axisalignedbb2.calculateZOffset(this.getEntityBoundingBox(), z); + } + + this.setEntityBoundingBox(this.getEntityBoundingBox().offset(0.0D, 0.0D, z)); + } + else + { + this.setEntityBoundingBox(this.getEntityBoundingBox().offset(x, y, z)); + } + + this.resetPositionToBB(); + this.isCollided = d0 != y && d0 < 0.0D; + + /* Can never be true! - But this doesn't seem to make any difference anyway. + if (x != x) + { + this.motionX = 0.0D; + } + + if (z != z) + { + this.motionZ = 0.0D; + } + */ + } + + // Overridden to bind the new texture. I think this can be done with TextureAtlasSprite, but this works as it is + // so I'm not changing it for the time being. + @Override + public void renderParticle(VertexBuffer buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ + + GlStateManager.pushMatrix(); + GlStateManager.pushAttrib(); + + this.applyGLStateChanges(); + + // This stuff does the shading. It vanilla does this later on for each point, but this also seems to work. + int brightness = this.getBrightnessForRender(partialTicks); + int lightmapX = brightness % 65536; + int lightmapY = brightness / 65536; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)lightmapX / 1.0F, (float)lightmapY / 1.0F); + + RenderHelper.disableStandardItemLighting(); + + Minecraft.getMinecraft().getTextureManager().bindTexture(getTexture()); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); + + float u1 = (float)this.particleTextureIndexX / (float)getXFrames(); + float u2 = u1 + 1.0f/getXFrames(); + float v1 = (float)this.particleTextureIndexY / (float)getYFrames(); + float v2 = v1 + 1.0f/getYFrames(); + float scale = 0.1F * this.particleScale; + + // I'm pretty sure these were always static. + Particle.interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks; + Particle.interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks; + Particle.interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks; + + float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); + float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); + float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); + + buffer.pos((double)(x - rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), (double)(z - rotationYZ * scale - rotationXZ * scale)).tex(u2, v2).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos((double)(x - rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), (double)(z - rotationYZ * scale + rotationXZ * scale)).tex(u2, v1).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos((double)(x + rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), (double)(z + rotationYZ * scale + rotationXZ * scale)).tex(u1, v1).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos((double)(x + rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), (double)(z + rotationYZ * scale - rotationXZ * scale)).tex(u1, v2).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();; + + Tessellator.getInstance().draw(); + + this.undoGLStateChanges(); + + GlStateManager.popAttrib(); + GlStateManager.popMatrix(); + + } + + /** Override to add any GL state changes, like blending. Does nothing by default. State changes should be + * done using GLStateManager, not using GL11 directly (as is the case with all rendering code now). */ + public void applyGLStateChanges(){} + + /** Override to undo any GL state changes, like blending. Does nothing by default. State changes should be + * done using GLStateManager, not using GL11 directly (as is the case with all rendering code now). */ + public void undoGLStateChanges(){} + + @Override + public int getBrightnessForRender(float partialTick){ + return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTick); + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java b/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java new file mode 100644 index 00000000..986e3c7c --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java @@ -0,0 +1,90 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleDarkMagic extends Particle { + + /** Base spell texture index */ + private int baseSpellTextureIndex = 128; + + public ParticleDarkMagic(World par1World, double par2, double par4, double par6, double par8, double par10, double par12, float r, float g, float b) + { + super(par1World, par2, par4, par6, par8, par10, par12); + this.motionY *= 0.20000000298023224D; + + this.particleRed = r; + this.particleGreen = g; + this.particleBlue = b; + + this.particleScale *= 0.75F; + this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D)); + this.canCollide = true; + } + + @Override + public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) + { + float f6 = ((float)this.particleAge + partialTicks) / (float)this.particleMaxAge * 32.0F; + + if (f6 < 0.0F) + { + f6 = 0.0F; + } + + if (f6 > 1.0F) + { + f6 = 1.0F; + } + + super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + } + + /** + * Called to update the entity's position/logic. + */ + public void onUpdate() + { + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + + if (this.particleAge++ >= this.particleMaxAge) + { + this.setExpired(); + } + + this.setParticleTextureIndex(this.baseSpellTextureIndex + (7 - this.particleAge * 8 / this.particleMaxAge)); + this.motionY += 0.004D; + this.moveEntity(this.motionX, this.motionY, this.motionZ); + /* + if (this.posY == this.prevPosY) + { + this.motionX *= 1.1D; + this.motionZ *= 1.1D; + } + */ + this.motionX *= 0.9599999785423279D; + this.motionY *= 0.9599999785423279D; + this.motionZ *= 0.9599999785423279D; + + if (this.isCollided) + { + this.motionX *= 0.699999988079071D; + this.motionZ *= 0.699999988079071D; + } + } + + /** + * Sets the base spell texture index + */ + public void setBaseSpellTextureIndex(int par1) + { + this.baseSpellTextureIndex = par1; + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java b/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java new file mode 100644 index 00000000..6a121fa3 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java @@ -0,0 +1,57 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.client.particle.Particle; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleDust extends Particle { + + private final boolean shaded; + + public ParticleDust(World par1World, double x, double y, double z, double par8, double par10, double par12, float r, float g, float b, boolean shaded) + { + super(par1World, x, y, z, par8, par10, par12); + this.particleRed = r; + this.particleGreen = g; + this.particleBlue = b; + this.setParticleTextureIndex(0); + this.setSize(0.01F, 0.01F); + this.particleScale *= this.rand.nextFloat() + 0.2F; + this.motionX = par8; + this.motionY = par10; + this.motionZ = par12; + this.particleMaxAge = (int)(16.0D / (Math.random() * 0.8D + 0.2D)); + this.shaded = shaded; + } + + /** + * Called to update the entity's position/logic. + */ + public void onUpdate() + { + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + //this.moveEntity(this.motionX, this.motionY, this.motionZ); + + if (this.particleMaxAge-- <= 0) + { + this.setExpired(); + } + } + + @Override + public int getBrightnessForRender(float par1) + { + return shaded ? super.getBrightnessForRender(par1) : 15728880; + } + /* + @Override + public float getBrightness(float par1) + { + return shaded ? super.getBrightness(par1) : 1.0F; + } + */ +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleGiantBubble.java b/src/main/java/electroblob/wizardry/client/particle/ParticleGiantBubble.java new file mode 100644 index 00000000..b469bcb2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleGiantBubble.java @@ -0,0 +1,50 @@ +package electroblob.wizardry.client.particle; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.particle.Particle; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleGiantBubble extends Particle +{ + /** The name used to identify this particle. Uses the mod id to avoid any possible conflicts (Not that there would + * be any, but I may as well.) */ + public static final String NAME = Wizardry.MODID + "magicbubble"; + + public ParticleGiantBubble(World par1World, double par2, double par4, double par6, double par8, double par10, double par12) + { + super(par1World, par2, par4, par6, par8, par10, par12); + this.particleRed = 1.0F; + this.particleGreen = 1.0F; + this.particleBlue = 1.0F; + this.setParticleTextureIndex(32); + this.setSize(0.02F, 0.02F); + this.particleScale *= this.rand.nextFloat() * 0.6F + 0.2F; + this.motionX = par8 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F); + this.motionY = par10 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F); + this.motionZ = par12 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F); + this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D)); + } + + /** + * Called to update the entity's position/logic. + */ + public void onUpdate() + { + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + this.motionY += 0.002D; + this.moveEntity(this.motionX, this.motionY, this.motionZ); + this.motionX *= 0.8500000238418579D; + this.motionY *= 0.8500000238418579D; + this.motionZ *= 0.8500000238418579D; + + if (this.particleMaxAge-- <= 0) + { + this.setExpired(); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java new file mode 100644 index 00000000..3332db15 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java @@ -0,0 +1,34 @@ +package electroblob.wizardry.client.particle; + +import electroblob.wizardry.Wizardry; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleIce extends ParticleCustomTexture { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/ice_particles.png"); + + public ParticleIce(World world, double x, double y, double z, double vx, double vy, double vz){ + super(world, x, y, z, vx, vy, vz); + } + + public ParticleIce(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){ + super(world, x, y, z, vx, vy, vz, maxAge); + } + + @Override + public void init(){ + this.setParticleTextureIndex(rand.nextInt(8)); + this.particleScale *= 0.75f; + this.particleGravity = 1; + this.canCollide = true; + this.fullBrightness = true; + } + + @Override public ResourceLocation getTexture(){ return TEXTURE; } + @Override protected int getXFrames(){ return 4; } + @Override protected int getYFrames(){ return 4; } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java new file mode 100644 index 00000000..0292dddf --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java @@ -0,0 +1,33 @@ +package electroblob.wizardry.client.particle; + +import electroblob.wizardry.Wizardry; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleLeaf extends ParticleCustomTexture { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/leaf_particles.png"); + + public ParticleLeaf(World world, double x, double y, double z, double vx, double vy, double vz){ + super(world, x, y, z, vx, vy, vz); + } + + public ParticleLeaf(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){ + super(world, x, y, z, vx, vy, vz, maxAge); + } + + @Override + public void init() { + this.setParticleTextureIndex(rand.nextInt(16)); + this.particleScale *= 1.4f; + this.particleGravity = 0; + this.canCollide = true; + } + + @Override public ResourceLocation getTexture(){ return TEXTURE; } + @Override protected int getXFrames(){ return 4; } + @Override protected int getYFrames(){ return 4; } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleMagicFlame.java b/src/main/java/electroblob/wizardry/client/particle/ParticleMagicFlame.java new file mode 100644 index 00000000..755fa4db --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleMagicFlame.java @@ -0,0 +1,47 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleMagicFlame extends Particle { + + /** The scale of the flame particle */ + private float flameScale; + + public ParticleMagicFlame(World par1World, double par2, double par4, double par6, double par8, double par10, double par12, int maxAge, float scale) + { + super(par1World, par2, par4, par6, par8, par10, par12); + this.motionX = this.motionX * 0.009999999776482582D + par8; + this.motionY = this.motionY * 0.009999999776482582D + par10; + this.motionZ = this.motionZ * 0.009999999776482582D + par12; + this.flameScale = scale; + this.particleRed = this.particleGreen = this.particleBlue = 1.0F; + if(maxAge == 0){ + this.particleMaxAge = (int)(2.0D / (Math.random() * 0.8D + 0.2D)); + }else{ + this.particleMaxAge = maxAge; + } + // IDEA: Make the particles for ray spells collide properly and not spawn on the other side of stuff. + this.canCollide = false; + this.setParticleTextureIndex(48); + } + + @Override + public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) + { + float f6 = ((float)this.particleAge + partialTicks) / (float)this.particleMaxAge; + this.particleScale = this.flameScale * (1.0F - f6 * f6 * 0.5F); + super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + } + + @Override + public int getBrightnessForRender(float par1) + { + return 256; + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticlePath.java b/src/main/java/electroblob/wizardry/client/particle/ParticlePath.java new file mode 100644 index 00000000..cf7b2c6e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticlePath.java @@ -0,0 +1,93 @@ +package electroblob.wizardry.client.particle; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.spell.Clairvoyance; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticlePath extends ParticleCustomTexture { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/path_particles.png"); + + private final double originX, originY, originZ; + + public ParticlePath(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b){ + super(world, x, y, z, vx, vy, vz); + this.setRBGColorF(r, g, b); + this.originX = x; + this.originY = y; + this.originZ = z; + } + + public ParticlePath(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, int maxAge){ + super(world, x, y, z, vx, vy, vz, maxAge); + this.setRBGColorF(r, g, b); + this.originX = x; + this.originY = y; + this.originZ = z; + } + + @Override + public void init(){ + this.setParticleTextureIndex(0); + // Set to a constant to remove the randomness from Particle. + this.particleScale = 1.25f; + this.particleGravity = 0; + this.fullBrightness = true; + this.canCollide = false; + } + + @Override public ResourceLocation getTexture(){ return TEXTURE; } + @Override protected int getXFrames(){ return 1; } + @Override protected int getYFrames(){ return 1; } + + @Override + public void onUpdate(){ + + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + + if (this.particleAge++ >= this.particleMaxAge) + { + this.setExpired(); + } + + this.moveEntity(this.motionX, this.motionY, this.motionZ); + + // Fading + if(this.particleAge > this.particleMaxAge / 2){ + this.setAlphaF(1.0F - 2 * (((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge)); + } + + if(this.particleAge % Clairvoyance.PARTICLE_MOVEMENT_INTERVAL == 0){ + this.setPosition(this.originX, this.originY, this.originZ); + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + } + + } + + @Override + public void applyGLStateChanges(){ + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + // TESTME: Are these two actually necessary? + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + } + + @Override + public void undoGLStateChanges(){ + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleRotatingSparkle.java b/src/main/java/electroblob/wizardry/client/particle/ParticleRotatingSparkle.java new file mode 100644 index 00000000..eadc09bb --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleRotatingSparkle.java @@ -0,0 +1,59 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleRotatingSparkle extends ParticleSparkle { + + private double angle; + private double radius; + private double speed; + + public ParticleRotatingSparkle(World world, int maxAge, double originX, double originZ, double radius, double yPos, float r, float g , float b){ + super(world, 0, 0, 0, 0, 0, 0, r, g, b, maxAge); + this.angle = this.rand.nextDouble() * Math.PI * 2; + double x = originX - Math.cos(angle)*radius; + double z = originZ + radius*Math.sin(angle); + this.radius = radius; + this.setPosition(x, yPos, z); + this.prevPosX = x; + this.prevPosY = yPos; + this.prevPosZ = z; + if(rand.nextBoolean()){ + speed = rand.nextDouble()*2 + 1; + }else{ + speed = rand.nextDouble()*-2 - 1; + } + this.multipleParticleScaleBy(1.5f); + } + + @Override + public void onUpdate(){ + + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + + if(this.particleAge++ >= this.particleMaxAge){ + this.setExpired(); + } + + // This is in radians per tick... + double omega = Math.signum(speed) * ((Math.PI*2)/20 - speed/(20*radius)); + + // v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi. + this.angle += omega; + + this.motionY -= 0.04D * (double)this.particleGravity; + this.motionZ = radius * omega * Math.cos(angle); + this.motionX = radius * omega * Math.sin(angle); + this.moveEntity(motionX, motionY, motionZ); + + if(this.particleAge > this.particleMaxAge / 2){ + this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + } + + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java new file mode 100644 index 00000000..a1455c22 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java @@ -0,0 +1,33 @@ +package electroblob.wizardry.client.particle; + +import electroblob.wizardry.Wizardry; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleSnow extends ParticleCustomTexture { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/snow_particles.png"); + + public ParticleSnow(World world, double x, double y, double z, double vx, double vy, double vz){ + super(world, x, y, z, vx, vy, vz); + } + + public ParticleSnow(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){ + super(world, x, y, z, vx, vy, vz, maxAge); + } + + @Override + public void init(){ + this.setParticleTextureIndex(rand.nextInt(8)); + this.particleScale *= 0.6f; + this.particleGravity = 0; + this.canCollide = true; + } + + @Override public ResourceLocation getTexture(){ return TEXTURE; } + @Override protected int getXFrames(){ return 4; } + @Override protected int getYFrames(){ return 4; } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java new file mode 100644 index 00000000..57965ed2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java @@ -0,0 +1,58 @@ +package electroblob.wizardry.client.particle; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleSpark extends ParticleCustomTexture { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/lightning_particles.png"); + + public ParticleSpark(World world, double x, double y, double z, double vx, double vy, double vz){ + // Max age is always 3. + super(world, x, y, z, vx, vy, vz, 3); + } + + @Override + public void init(){ + // Multiplied by 4 because the index works slightly differently for spark particles. + this.setParticleTextureIndex(rand.nextInt(8)*4); + this.particleScale *= 1.4f; + this.fullBrightness = true; + this.canCollide = false; + } + + @Override + public void onUpdate(){ + super.onUpdate(); + // Well this is handy! Looks like vanilla uses the texture index like this too. + this.nextTextureIndexX(); + } + + @Override public ResourceLocation getTexture(){ return TEXTURE; } + @Override protected int getXFrames(){ return 4; } + @Override protected int getYFrames(){ return 8; } + + @Override + public void applyGLStateChanges(){ + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + // TESTME: Are these two actually necessary? + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + } + + @Override + public void undoGLStateChanges(){ + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java new file mode 100644 index 00000000..fbe89146 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java @@ -0,0 +1,96 @@ +package electroblob.wizardry.client.particle; + +import electroblob.wizardry.Wizardry; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleSparkle extends ParticleCustomTexture { + + /* I have now figured out what particle factories are for: they separate out the individual uses of the varargs + * parameter in spawnParticle so they are kept with the particle class. For my purposes, it would be easier to do + * that in the particle spawning method itself. */ + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/sparkle_particles.png"); + + // NOTE: Uncomment once 2.1.0 is released + //private final float initialRed; + //private final float initialGreen; + //private final float initialBlue; + + // TODO: Assign these via the constructors, as part of the refactoring for particle parameters. + // NOTE: Uncomment once 2.1.0 is released +// private final float fadeRed = 1; +// private final float fadeGreen = 1; +// private final float fadeBlue = 0; + + public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b){ + super(world, x, y, z, vx, vy, vz); + this.setRBGColorF(r, g, b); + // NOTE: Uncomment once 2.1.0 is released + //initialRed = r; + //initialGreen = g; + //initialBlue = b; + this.particleMaxAge = 48 + this.rand.nextInt(12); + } + + public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, int maxAge){ + super(world, x, y, z, vx, vy, vz, maxAge); + this.setRBGColorF(r, g, b); + // NOTE: Uncomment once 2.1.0 is released + //initialRed = r; + //initialGreen = g; + //initialBlue = b; + } + + public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, boolean doGravity){ + this(world, x, y, z, vx, vy, vz, r, g, b); + this.particleGravity = doGravity ? 1 : 0; + } + + public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, int maxAge, boolean doGravity){ + this(world, x, y, z, vx, vy, vz, r, g, b, maxAge); + this.particleGravity = doGravity ? 1 : 0; + } + + @Override + public void init(){ + this.setParticleTextureIndex(rand.nextInt(16)); + this.particleScale *= 0.75f; + this.particleGravity = 0; + this.canCollide = false; + this.fullBrightness = true; + } + + @Override public ResourceLocation getTexture(){ return TEXTURE; } + @Override protected int getXFrames(){ return 4; } + @Override protected int getYFrames(){ return 4; } + + @Override + public void onUpdate(){ + + super.onUpdate(); + // Fading + if(this.particleAge > this.particleMaxAge / 2){ + this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + } + // Colour fading TODO Uncomment once 2.1.0 is released +// float ageFraction = (float)this.particleAge / (float)this.particleMaxAge; +// this.setRBGColorF(this.initialRed + (this.fadeRed - this.initialRed)*ageFraction, +// this.initialGreen + (this.fadeGreen - this.initialGreen)*ageFraction, +// this.initialBlue + (this.fadeBlue - this.initialBlue)*ageFraction); +// +// this.setParticleTextureIndex((this.particleAge * 11)/this.particleMaxAge); + } + + /* + * As a side note, I see a lot of magic mods with fancy-looking particle effects that really seem to 'glow'. It's + * actually not that hard - you simply create a reasonably high-res texture with translucency and then set the + * OpenGL blend function to something like SRC_ALPHA, SRC_ALPHA or ONE, ONE. The thing is... they're not very + * Minecraft-y. I still maintain that part of wizardry's appeal is that it stays true to the game's pixelated charm, + * rather than trying to make it something it's not. Still, the newer textures are much better than the defaults I + * used to use. + */ +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleTornado.java b/src/main/java/electroblob/wizardry/client/particle/ParticleTornado.java new file mode 100644 index 00000000..1dd5635b --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleTornado.java @@ -0,0 +1,83 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.particle.ParticleDigging; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleTornado extends ParticleDigging { + + private double angle; + private double radius; + private double speed; + /** Velocity of the tornado itself; in other words the velocity of the point the particle circles around. */ + private double velX, velZ; + private boolean fullBrightness = false; + + public ParticleTornado(World world, int maxAge, double originX, double originZ, double radius, double yPos, double velX, double velZ, IBlockState block){ + super(world, 0, 0, 0, 0, 0, 0, block); + this.angle = this.rand.nextDouble() * Math.PI * 2; + double x = originX - Math.cos(angle)*radius; + double z = originZ + radius*Math.sin(angle); + this.radius = radius; + this.setPosition(x, yPos, z); + this.prevPosX = x; + this.prevPosY = yPos; + this.prevPosZ = z; + //this.particleScale *= 0.75F; + this.particleMaxAge = maxAge; + this.canCollide = false; + // Grass has special treatment, since it has a colourised top but the rest is normal. + // Commented out for now since vanilla does something about this now, but I'm not sure what exactly + //if(block.getBlock() != Blocks.GRASS || side == 1) this.setColour(block.getRenderColor(side)); + + // Blocks that emit light are rendered with full brightness. + if(block.getLightValue(world, new BlockPos(this.posX, this.posY, this.posZ)) == 0){ + this.particleRed *= 0.75; + this.particleGreen *= 0.75; + this.particleBlue *= 0.75; + }else{ + this.fullBrightness = true; + } + + speed = rand.nextDouble()*2 + 1; + this.velX = velX; + this.velZ = velZ; + } + + @Override + public void onUpdate(){ + + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + + if(this.particleAge++ >= this.particleMaxAge){ + this.setExpired(); + } + + // This is in radians per tick... + double omega = Math.signum(speed) * ((Math.PI*2)/20 - speed/(20*radius)); + + // v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi. + this.angle += omega; + + this.motionZ = radius * omega * Math.cos(angle); + this.motionX = radius * omega * Math.sin(angle); + this.moveEntity(motionX + velX, 0, motionZ + velZ); + + if(this.particleAge > this.particleMaxAge / 2){ + this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + } + + } + + @Override + public int getBrightnessForRender(float partialTicks){ + return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTicks); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java b/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java new file mode 100644 index 00000000..4365a842 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java @@ -0,0 +1,191 @@ +package electroblob.wizardry.client.renderer; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map.Entry; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.ClientProxy; +import electroblob.wizardry.spell.Petrify; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelBiped; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderLivingBase; +import net.minecraft.client.renderer.entity.RenderZombie; +import net.minecraft.client.renderer.entity.layers.LayerRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntityZombie; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.fml.relauncher.ReflectionHelper; + +/** + * Layer used to render the stone texture on a petrified creature. Handles dynamic tiling of the stone texture and + * reflective access for classes that don't play nicely (looking at you, {@link RenderZombie}). + * @author Electroblob + * @since Wizardry 1.2 + */ +public class LayerStone implements LayerRenderer { + + protected ModelBase model; + private final RenderLivingBase renderer; + + private static final ResourceLocation texture = new ResourceLocation("textures/blocks/stone.png"); + + private static final Field zombieLayers = ReflectionHelper.findField(RenderZombie.class, "defaultLayers", "field_177122_o"); + private static final Field zombieVillagerLayers = ReflectionHelper.findField(RenderZombie.class, "villagerLayers", "field_177121_n"); + private static final Method swapZombieModel = ReflectionHelper.findMethod(RenderZombie.class, null, + new String[]{"swapArmor", "func_82427_a"}, EntityZombie.class); // Second parameter (null) is unused + + @SuppressWarnings("unchecked") // The compiler is being annoying and I know that what I'm doing is type-safe. + public static void initialiseLayers(){ + for(Entry, Render> entry : Minecraft.getMinecraft().getRenderManager().entityRenderMap.entrySet()){ + // Zombies don't play nicely because they have their own, private lists of layers for the regular zombie + // and the zombie villager, which are assigned within the constructor for RenderZombie and swapped out + // as necessary. However, Mojang, in their infinite wisdom, haven't bothered to override addLayer to + // modify those internal lists, so that method is useless. + if(entry.getValue() instanceof RenderZombie){ + try { + Object layers = zombieLayers.get(entry.getValue()); + if(layers instanceof List){ + // Nice as the layer renderer system is, it doesn't lend itself to reflective access. + // I KNOW that 'layers' (which was obtained using reflection) is of the type + // List>, because that's what it's declared as. However, if I cast + // 'layers' to List>, I can't add a LayerStone because it's only a + // LayerRenderer, not a LayerRenderer. + ((List>)layers).add(new LayerStone((RenderLivingBase)entry.getValue())); + } + layers = zombieVillagerLayers.get(entry.getValue()); + if(layers instanceof List){ + ((List>)layers).add(new LayerStone((RenderLivingBase)entry.getValue())); + } + } catch (IllegalArgumentException | IllegalAccessException e){ + Wizardry.logger.error("Error while reflectively accessing zombie render layers"); + e.printStackTrace(); + } + }else if(entry.getValue() instanceof RenderLivingBase){ + // Adds a stone layer to all the living entity renderers in the game. Whether it is actually rendered + // is decided in doRenderLayer below on a per-entity basis. + ((RenderLivingBase)entry.getValue()).addLayer(new LayerStone((RenderLivingBase)entry.getValue())); + } + // NOTE: May have to do some special stuff for players if they are to be added; see Minecraft.getMinecraft().getRenderManager().getSkinMap() + } + } + + public LayerStone(RenderLivingBase renderer){ + this.renderer = renderer; + this.model = renderer.getMainModel(); + } + + @Override + public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){ + + if(entity.getEntityData().getBoolean(Petrify.NBT_KEY)){ + + GlStateManager.enableLighting(); + int i = this.getBlockBrightnessForEntity(entity, partialTicks); + + int j = i % 65536; + int k = i / 65536; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F); + + ResourceLocation breakingTexture = ClientProxy.renderStatue.getBlockBreakingTexture(); + + if(breakingTexture != null){ + // Block breaking animation + // TODO: Spider eyes and enderman eyes (any others?) show through the stone when the block is being broken... + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + this.renderer.bindTexture(breakingTexture); + this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale); + GlStateManager.disableBlend(); + }else{ + // Stone texture + this.renderer.bindTexture(texture); + this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale); + } + } + } + + private int getBlockBrightnessForEntity(Entity entity, float partialTicks){ + + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(MathHelper.floor_double(entity.posX), 0, MathHelper.floor_double(entity.posZ)); + + if(entity.worldObj.isBlockLoaded(pos)){ + pos.setY(MathHelper.floor_double(entity.posY + (double)entity.getEyeHeight())); + return entity.worldObj.getCombinedLight(pos, 0); + }else{ + return 0; + } + } + + private void renderEntityModel(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){ + + GlStateManager.pushMatrix(); + // Enables tiling (Also used for guardian beam, beacon beam and ender crystal beam) + // TODO: Backport this improvement + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); + + GlStateManager.depthMask(true); // Some entities set depth mask to false (i.e. no sorting of faces by depth) + // In particular, LayerSpiderEyes sets it to false when the spider is invisible, for some reason. + + // Changes the scale at which the texture is applied to the model. See LayerCreeper for a similar example, + // but with translation instead of scaling. + GlStateManager.matrixMode(GL11.GL_TEXTURE); + GlStateManager.loadIdentity(); + double scaleX = 1, scaleY = 1; + // It's more logical to use the model's texture size, but some classes don't bother setting it properly + // (e.g. ModelVillager), so to get the correct dimensions I'm getting them from the first box instead. + if(model.boxList != null && model.boxList.get(0) != null){ + scaleX = (double)model.boxList.get(0).textureWidth/16d; + scaleY = (double)model.boxList.get(0).textureHeight/16d; + }else{ // Fallback to model fields; should never be needed + scaleX = (double)model.textureWidth/16d; + scaleY = (double)model.textureHeight/16d; + } + GlStateManager.scale(scaleX, scaleY, 1); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + + // Lets RenderZombie do its (stupid and inflexible) model switching thing + if(this.renderer instanceof RenderZombie && entity instanceof EntityZombie){ + try { + swapZombieModel.invoke(this.renderer, entity); + this.model = this.renderer.getMainModel(); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + Wizardry.logger.error("Error while reflectively calling RenderZombie#swapArmor"); + e.printStackTrace(); + } + } + // Hides the hat layer for bipeds + if(this.model instanceof ModelBiped) ((ModelBiped) this.model).bipedHeadwear.isHidden = true; + + this.model.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks); + this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); + + if(this.model instanceof ModelBiped) ((ModelBiped) this.model).bipedHeadwear.isHidden = false; + + // Undoes the texture scaling + GlStateManager.matrixMode(GL11.GL_TEXTURE); + GlStateManager.loadIdentity(); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + + GlStateManager.popMatrix(); + } + + @Override + public boolean shouldCombineTextures(){ + return false; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/renderer/RayHelper.java b/src/main/java/electroblob/wizardry/client/renderer/RayHelper.java new file mode 100644 index 00000000..0fdd1e1e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RayHelper.java @@ -0,0 +1,48 @@ +package electroblob.wizardry.client.renderer; + +/** Instances of this class can calculate their distance from the camera viewpoint and sort themselves accordingly. */ +class RayHelper implements Comparable { + + int ordinal; + double x1, y1, z1; + double x2, y2, z2; + double offsetX, offsetY, offsetZ; + + RayHelper(int ordinal, double x1, double y1, double z1, double x2, double y2, double z2, double offsetX, double offsetY, double offsetZ){ + this.ordinal = ordinal; + this.x1 = x1; + this.y1 = y1; + this.z1 = z1; + this.x2 = x2; + this.y2 = y2; + this.z2 = z2; + this.offsetX = offsetX; + this.offsetY = offsetY; + this.offsetZ = offsetZ; + } + + double getDistanceFromViewpoint(){ + + double midX = (x1+x2)/2; + double midY = (y1+y2)/2; + double midZ = (z1+z2)/2; + + double absoluteX = offsetX+midX; + double absoluteY = offsetY+midY; + double absoluteZ = offsetZ+midZ; + + return Math.sqrt(absoluteX*absoluteX + absoluteY*absoluteY + absoluteZ*absoluteZ); + } + + @Override + public int compareTo(RayHelper ray){ + if(this.getDistanceFromViewpoint() > ray.getDistanceFromViewpoint()){ + return -1; + }else if(this.getDistanceFromViewpoint() < ray.getDistanceFromViewpoint()){ + return 1; + }else{ + return 0; + } + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderArc.java b/src/main/java/electroblob/wizardry/client/renderer/RenderArc.java new file mode 100644 index 00000000..6bf600d1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderArc.java @@ -0,0 +1,129 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.EntityArc; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class RenderArc extends Render { + + private static final ResourceLocation[] textures = new ResourceLocation[16]; + + public RenderArc(RenderManager renderManager){ + super(renderManager); + for(int i=0;i<16;i++){ + textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/arc_" + i + ".png"); + } + } + + @Override + public void doRender(EntityArc arc, double d0, double d1, double d2, + float fa, float fb) { + GlStateManager.pushMatrix(); + GlStateManager.translate((float)d0, (float)d1, (float)d2); + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); //This line fixes the weird brightness bug. + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + //System.out.println("Entity coords: " + entity.posX + ", " + entity.posY + ", " + entity.posZ); + //System.out.println("doRender parameters: " + d0 + ", " + d1 + ", " + d2 + ", " + fa + ", " + fb); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + bindTexture(textures[arc.textureIndex]); // This MUST be after the tessellator declaration and the gl stuff + + /** + * Note: A lot of the maths here works on similar triangles and the ratios between them, avoiding too much + * pythagoras and eliminating the need for any trig. Ratios are used for the positioning of the arc endpoints. + * Ratios are usually used swapping x and z because the triangles are rotated through 90 degrees. + */ + + double dx = -d0; + double dy = -d1; + double dz = -d2; + + if(arc.x1 != 0){ + dx = arc.x1 - arc.posX;// - d2/lengthOffsetRatio; + dy = arc.y1 - arc.posY + 0.3; + dz = arc.z1 - arc.posZ;// + d0/lengthOffsetRatio; + + + //The distance from caster to target + double arcLength = Math.sqrt(dz*dz+dx*dx); + + //The ratio between the length of the arc and the offset of the start point from the player's centre (which is always 0.3). + //double lengthOffsetRatio = arcLength/0.3; + + //EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer; + + //double xViewDist = player.posX - d0; + //double yViewDist = player.posY + player.eyeHeight - d1; + //double zViewDist = player.posZ - d2; + + //double xzViewDist = Math.sqrt(xViewDist * xViewDist + zViewDist * zViewDist); + + //The angle above the horizontal that this particular player is viewing the arc from + //double viewAngle = Math.atan(yViewDist/xzViewDist); + + //Half the width of the arc + double arcWidth = 0.3d; + + //Right hand side of vertical plane + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + //Target end + buffer.pos(0, -0.5, 0).tex(1, 1).endVertex(); + buffer.pos(0, 0.5, 0).tex(1, 0).endVertex(); + //Caster end + buffer.pos(dx, dy, dz).tex(0, 0).endVertex(); + buffer.pos(dx, dy-1, dz).tex(0, 1).endVertex(); + tessellator.draw(); + + //Left + buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + //Target end + buffer.pos(0, -0.5, 0).tex(1, 1).endVertex(); + //Caster end + buffer.pos(dx, dy-1, dz).tex(0, 1).endVertex(); + buffer.pos(dx, dy, dz).tex(0, 0).endVertex(); + //Target end + buffer.pos(0, 0.5, 0).tex(1, 0).endVertex(); + tessellator.draw(); + + //Bottom of horizontal plane + buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + buffer.pos((arcWidth/arcLength)*dz, 0, (-arcWidth/arcLength)*dx).tex(1, 1).endVertex(); + buffer.pos(dx + (arcWidth/arcLength)*dz, dy-0.5, dz - (arcWidth/arcLength)*dx).tex(0, 1).endVertex(); + buffer.pos(dx - (arcWidth/arcLength)*dz, dy-0.5, dz + (arcWidth/arcLength)*dx).tex(0, 0).endVertex(); + buffer.pos((-arcWidth/arcLength)*dz, 0, (arcWidth/arcLength)*dx).tex(1, 0).endVertex(); + tessellator.draw(); + + //Top + buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + buffer.pos((arcWidth/arcLength)*dz, 0, (-arcWidth/arcLength)*dx).tex(1, 1).endVertex(); + buffer.pos((-arcWidth/arcLength)*dz, 0, (arcWidth/arcLength)*dx).tex(1, 0).endVertex(); + buffer.pos(dx - (arcWidth/arcLength)*dz, dy-0.5, dz + (arcWidth/arcLength)*dx).tex(0, 0).endVertex(); + buffer.pos(dx + (arcWidth/arcLength)*dz, dy-0.5, dz - (arcWidth/arcLength)*dx).tex(0, 1).endVertex(); + tessellator.draw(); + } + + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityArc entity) { + return textures[entity.textureIndex]; + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneWorkbench.java b/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneWorkbench.java new file mode 100644 index 00000000..12203694 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneWorkbench.java @@ -0,0 +1,99 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.tileentity.ContainerArcaneWorkbench; +import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +public class RenderArcaneWorkbench extends TileEntitySpecialRenderer { + + private static final ResourceLocation runeTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/rune.png"); + + public RenderArcaneWorkbench(){} + + @Override + public void renderTileEntityAt(TileEntityArcaneWorkbench tileentity, double x, double y, double z, float partialTicks, int destroyStage) { + + GlStateManager.pushMatrix(); + // This line makes stuff render in the same place relative to the world wherever the player is. + GlStateManager.translate((float)x + 0.5F, (float)y + 1.5F, (float)z + 0.5F); + GlStateManager.rotate(180, 0F, 0F, 1F); + GlStateManager.pushMatrix(); + double angle = 0.0d; + if(x < -0.5){ + angle = Math.toDegrees(Math.atan((z+0.5)/(x+0.5))) + 180; + }else{ + angle = Math.toDegrees(Math.atan((z+0.5)/(x+0.5))); + } + this.renderEffect(tileentity); + this.renderWand(tileentity, angle); + GlStateManager.popMatrix(); + GlStateManager.popMatrix(); + } + + private void renderEffect(TileEntityArcaneWorkbench tileentity) { + + ItemStack itemstack = tileentity.getStackInSlot(ContainerArcaneWorkbench.WAND_SLOT); + + if(itemstack != null){ + GlStateManager.pushMatrix(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); //This line fixes the weird brightness bug. + GlStateManager.rotate(tileentity.timer, 0.0f, 1.0f, 0.0f); + GlStateManager.translate(0.0f, 0.65f, 0.0f); + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + bindTexture(runeTexture); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-0.5f, 0, -0.5f).tex(0, 0).endVertex(); + buffer.pos(0.5f, 0, -0.5f).tex(1, 0).endVertex(); + buffer.pos(0.5f, 0, 0.5f).tex(1, 1).endVertex(); + buffer.pos(-0.5f, 0, 0.5f).tex(0, 1).endVertex(); + tessellator.draw(); + + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + GlStateManager.popMatrix(); + } + } + + /** + * Renders the wand on the workbench as 3D on the model. Currently doesn't do much on 'fast' graphics! + * @param tileentity The instance of the workbench tile entity + */ + private void renderWand(TileEntityArcaneWorkbench tileentity, double viewAngle) + { + ItemStack stack = tileentity.getStackInSlot(ContainerArcaneWorkbench.WAND_SLOT); + + if(stack != null){ + + GlStateManager.pushMatrix(); + GlStateManager.rotate(180.0F, 1.0F, 0.0F, 0.0F); + GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F); + + GlStateManager.rotate(180, 0, 1, 0); + // View angle is negated because of the 180 flip. + GlStateManager.rotate((float)(-viewAngle-90f), 0, 0, 1); + // Does the floaty thing + GlStateManager.translate(0.0F, 0.0F, (float)tileentity.yOffset/5000.0F - 0.55f); + GlStateManager.scale(0.75F, 0.75F, 0.75F); + // This is what the item frame uses so it's definitely what we want. + Minecraft.getMinecraft().getRenderItem().renderItem(stack, TransformType.FIXED); + GlStateManager.popMatrix(); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderBlackHole.java b/src/main/java/electroblob/wizardry/client/renderer/RenderBlackHole.java new file mode 100644 index 00000000..67cdd6e8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderBlackHole.java @@ -0,0 +1,180 @@ +package electroblob.wizardry.client.renderer; + +import java.util.ArrayList; +import java.util.Collections; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.construct.EntityBlackHole; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class RenderBlackHole extends Render { + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/dark_ray.png"); + private static final ResourceLocation texture2 = new ResourceLocation(Wizardry.MODID, "textures/entity/black_hole.png"); + + public RenderBlackHole(RenderManager renderManager) { + super(renderManager); + } + + @Override + public void doRender(EntityBlackHole blackhole, double x, double y, double z, float fa, float fb) { + + GlStateManager.pushMatrix(); + + GlStateManager.disableCull(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + RenderHelper.disableStandardItemLighting(); + + GlStateManager.translate(x, y, z); + + //float pitch = (float) Math.toDegrees(Math.atan(y/(x*x+z*z))); + //float yaw = (float) Math.toDegrees(Math.atan(x/z)); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + if(blackhole.ticksExisted < 10){ + GlStateManager.scale((float)blackhole.ticksExisted/10, (float)blackhole.ticksExisted/10, (float)blackhole.ticksExisted/10); + } + if(blackhole.ticksExisted > blackhole.lifetime - 10){ + GlStateManager.scale((float)(blackhole.lifetime-blackhole.ticksExisted)/10, (float)(blackhole.lifetime-blackhole.ticksExisted)/10, (float)(blackhole.lifetime-blackhole.ticksExisted)/10); + } + + this.bindTexture(texture); + + // In theory this stuff should sort the rays into the correct render order based on the distance from + // the 'camera' (i.e. the player's viewpoint) + // In the end it was easier to do away with the openGL rotation because for some reason it produced + // coordinates which were inconsistent with my calculated ones. Since I know those will give the desired + // effect anyway, I just used them directly instead. + + ArrayList rays = new ArrayList(1); + + for(int j=0; j<30; j++){ + + float scale = 3.0f; + + int a = blackhole.randomiser[j]; + int b = blackhole.randomiser2[j]; + + int sliceAngle = 20 + a; + + double x1 = scale*Math.sin((blackhole.ticksExisted + 40*j)*(Math.PI/180)); + //double y1 = 0.7*Math.cos((blackhole.timer - 40*j)*(Math.PI/180))*j/10; + double z1 = scale*Math.cos((blackhole.ticksExisted + 40*j)*(Math.PI/180)); + + double x2 = scale*Math.sin((blackhole.ticksExisted + 40*j - sliceAngle)*(Math.PI/180)); + //double y2 = 0.7*Math.sin((blackhole.timer - 40*j)*(Math.PI/180))*j/10; + double z2 = scale*Math.cos((blackhole.ticksExisted + 40*j - sliceAngle)*(Math.PI/180)); + + double absoluteX = x1*Math.cos(31*b); + double absoluteY = z1*Math.sin(31*a) + x1*Math.cos(31*a)*Math.sin(31*b); + double absoluteZ = z1*Math.cos(31*a); + + double absoluteX2 = x2*Math.cos(31*b); + double absoluteY2 = z2*Math.sin(31*a) + x2*Math.cos(31*a)*Math.sin(31*b); + double absoluteZ2 = z2*Math.cos(31*a); + /* + buffer.begin(0, DefaultVertexFormats.POSITION_TEX); + + tessellator.setColorOpaque(255, 255, 255); + GL11.glPointSize(5); + + tessellator.addVertex(absoluteX-x, 0, 0); + tessellator.addVertex(0, absoluteY-y, 0); + tessellator.addVertex(0, 0, absoluteZ-z); + + tessellator.draw(); + */ + rays.add(new RayHelper(j, absoluteX, absoluteY, absoluteZ, absoluteX2, absoluteY2, absoluteZ2, x, y, z)); + + } + + Collections.sort(rays); + + for(RayHelper ray : rays){ + + GlStateManager.pushMatrix(); + //GlStateManager.rotate(31*blackhole.randomiser[ray.ordinal], 1, 0, 0); + //GlStateManager.rotate(31*blackhole.randomiser2[ray.ordinal], 0, 0, 1); + + buffer.begin(5, DefaultVertexFormats.POSITION_TEX); + + //tessellator.setColorRGBA(255, 255, 255, 0); + buffer.pos(0, 0, 0).tex(0, 0).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).endVertex(); + + //tessellator.setColorRGBA(0, 0, 0, 255); + buffer.pos(ray.x1, ray.y1, ray.z1).tex(1, 0).endVertex(); + buffer.pos(ray.x2, ray.y2, ray.z2).tex(1, 1).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + } + + GlStateManager.pushMatrix(); + + /* Deprecated in favour of particle style method. + GlStateManager.rotate(yaw, 0, 1, 0); + // GL transformations are relative, hence only x rotation + if(z < 0){ + GlStateManager.rotate(pitch, 1, 0, 0); + }else{ + GlStateManager.rotate(-1*pitch, 1, 0, 0); + } + */ + + // Renders the aura effect + + // This counteracts the reverse rotation behaviour when in front f5 view. Vanilla now has this fix too. + float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? this.renderManager.playerViewX : -this.renderManager.playerViewX; + GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + this.bindTexture(texture2); + + buffer.pos(-0.4, 0.4, 0).tex(0, 0).endVertex(); + buffer.pos(0.4, 0.4, 0).tex(1, 0).endVertex(); + buffer.pos(0.4, -0.4, 0).tex(1, 1).endVertex(); + buffer.pos(-0.4, -0.4, 0).tex(0, 1).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + + + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableCull(); + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + RenderHelper.enableStandardItemLighting(); + + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityBlackHole entity) { + return texture; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderBlank.java b/src/main/java/electroblob/wizardry/client/renderer/RenderBlank.java new file mode 100644 index 00000000..01926ccc --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderBlank.java @@ -0,0 +1,25 @@ +package electroblob.wizardry.client.renderer; + +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; + +public class RenderBlank extends Render { + + public RenderBlank(RenderManager renderManager) { + super(renderManager); + } + + @Override + public void doRender(Entity entity, double d0, double d1, double d2, + float f, float f1) { + + } + + @Override + protected ResourceLocation getEntityTexture(Entity entity) { + return null; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderBubble.java b/src/main/java/electroblob/wizardry/client/renderer/RenderBubble.java new file mode 100644 index 00000000..d96a1020 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderBubble.java @@ -0,0 +1,104 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.construct.EntityBubble; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class RenderBubble extends Render { + + private static final ResourceLocation particleTextures = new ResourceLocation("textures/particle/particles.png"); + private static final ResourceLocation darkOrbTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/dark_orb.png"); + + public RenderBubble(RenderManager renderManager) { + super(renderManager); + } + + @Override + public void doRender(EntityBubble entity, double par2, double par4, double par6, float par8, float par9){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + float yOffset = 0; + + if(WizardryUtilities.getRider(entity) != null){ + yOffset = WizardryUtilities.getRider(entity).height/2; + } + + GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6); + + this.bindTexture(((EntityBubble)entity).isDarkOrb ? darkOrbTexture : particleTextures); + float f6 = 1.0F; + float f7 = 0.5F; + float f8 = 0.5F; + + if(((EntityBubble)entity).isDarkOrb){ + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + }else{ + int j = entity.getBrightnessForRender(par9); + int k = j % 65536; + int l = j / 65536; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)k / 1.0F, (float)l / 1.0F); + } + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + // This counteracts the reverse rotation behaviour when in front f5 view. + // Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example. + float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? this.renderManager.playerViewX : -this.renderManager.playerViewX; + GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F); + + float f11 = 3.0F; + GlStateManager.scale(f11, f11, f11); + + double pixelwidth = (1.0d/128); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + //tessellator.setColorRGBA_I(k1, 128); + //buffer.normal(0.0F, 1.0F, 0.0F); + + if(((EntityBubble)entity).isDarkOrb){ + buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.0D).tex(0, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.0D).tex(1, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.0D).tex(1, 0).endVertex(); + buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.0D).tex(0, 0).endVertex(); + }else{ + buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.0D).tex(pixelwidth, pixelwidth * 24).endVertex(); + buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.0D).tex(pixelwidth*8, pixelwidth * 24).endVertex(); + buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.0D).tex(pixelwidth*8, pixelwidth * 17).endVertex(); + buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.0D).tex(pixelwidth, pixelwidth * 17).endVertex(); + } + + tessellator.draw(); + + GlStateManager.disableBlend(); + if(((EntityBubble)entity).isDarkOrb){ + GlStateManager.enableLighting(); + } + GlStateManager.disableRescaleNormal(); + GlStateManager.popMatrix(); + + } + + @Override + protected ResourceLocation getEntityTexture(EntityBubble entity) { + return null; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderDecay.java b/src/main/java/electroblob/wizardry/client/renderer/RenderDecay.java new file mode 100644 index 00000000..f849f967 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderDecay.java @@ -0,0 +1,74 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.construct.EntityDecay; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class RenderDecay extends Render { + + private static final ResourceLocation[] textures = new ResourceLocation[10]; + + public RenderDecay(RenderManager renderManager){ + super(renderManager); + for(int i=0;i<10;i++){ + textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/decay_" + i + ".png"); + } + } + + @Override + public void doRender(EntityDecay entity, double par2, double par4, double par6, float par8, float par9){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + float yOffset = 0; + + GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6); + + this.bindTexture(textures[((EntityDecay)entity).textureIndex]); + float f6 = 1.0F; + float f7 = 0.5F; + float f8 = 0.5F; + + GlStateManager.rotate(-90, 1, 0, 0); + + float scale = 2*Math.min(1, (float)(EntityDecay.LIFETIME - entity.ticksExisted)/50f); + + GlStateManager.scale(scale, scale, scale); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + //tessellator.setColorRGBA_I(k1, 128); + //buffer.normal(0.0F, 1.0F, 0.0F); + buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex(); + buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + GlStateManager.disableRescaleNormal(); + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityDecay entity) { + return null; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderDecoy.java b/src/main/java/electroblob/wizardry/client/renderer/RenderDecoy.java new file mode 100644 index 00000000..8e373b04 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderDecoy.java @@ -0,0 +1,108 @@ +package electroblob.wizardry.client.renderer; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.living.EntityDecoy; +import net.minecraft.client.model.ModelBiped; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderBiped; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +// TODO: Backport the rewrite of this entire class. +@SideOnly(Side.CLIENT) +public class RenderDecoy extends RenderBiped { + + private static final ResourceLocation steveTextures = new ResourceLocation("textures/entity/steve.png"); + + private static final Method getEntityTexture = ReflectionHelper.findMethod(Render.class, null, + new String[]{"getEntityTexture", "func_110775_a"}, Entity.class); // Generic parameter T is erased to Entity at runtime. + + public RenderDecoy(RenderManager manager){ + super(manager, new ModelBiped(0.0f), 0.5f); + } + + @Override + public void doRender(EntityDecoy entity, double x, double y, double z, float entityYaw, float partialTicks) { + + if(entity.getCaster() != null){ + + this.renderName(entity, x, y, z); + + // Save relevant animation fields from the caster to local variables + float pitch = entity.getCaster().rotationPitch; + float prevPitch = entity.getCaster().prevRotationPitch; + float swing = entity.getCaster().swingProgress; + float prevSwing = entity.getCaster().prevSwingProgress; + float yawOffset = entity.getCaster().renderYawOffset; + float prevYawOffset = entity.getCaster().prevRenderYawOffset; + float yaw = entity.getCaster().rotationYawHead; + float prevYaw = entity.getCaster().prevRotationYawHead; + float limbSwing = entity.getCaster().limbSwing; + float limbSwingAmount = entity.getCaster().limbSwingAmount; + float prevLimbSwingAmount = entity.getCaster().prevLimbSwingAmount; + int hurtTime = entity.getCaster().hurtTime; + boolean sneak = entity.getCaster().isSneaking(); + Entity mount = entity.getCaster().getRidingEntity(); + + // Assign decoy's animation fields to the caster + entity.getCaster().rotationPitch = entity.rotationPitch; + entity.getCaster().prevRotationPitch = entity.prevRotationPitch; + entity.getCaster().swingProgress = entity.swingProgress; + entity.getCaster().prevSwingProgress = entity.prevSwingProgress; + entity.getCaster().renderYawOffset = entity.renderYawOffset; + entity.getCaster().prevRenderYawOffset = entity.prevRenderYawOffset; + entity.getCaster().rotationYawHead = entity.rotationYawHead; + entity.getCaster().prevRotationYawHead = entity.prevRotationYawHead; + entity.getCaster().limbSwing = entity.limbSwing; + entity.getCaster().limbSwingAmount = entity.limbSwingAmount; + entity.getCaster().prevLimbSwingAmount = entity.prevLimbSwingAmount; + entity.getCaster().hurtTime = entity.hurtTime; + entity.getCaster().setSneaking(false); // Decoys can't sneak FIXME Not working! + entity.getCaster().dismountRidingEntity(); // Decoys can't ride anything + + // Do the rendering + renderManager.getEntityRenderObject(entity.getCaster()).doRender(entity.getCaster(), x, y, z, entityYaw, partialTicks); + + // Reset caster's animation fields to their original values + entity.getCaster().rotationPitch = pitch; + entity.getCaster().prevRotationPitch = prevPitch; + entity.getCaster().swingProgress = swing; + entity.getCaster().prevSwingProgress = prevSwing; + entity.getCaster().renderYawOffset = yawOffset; + entity.getCaster().prevRenderYawOffset = prevYawOffset; + entity.getCaster().rotationYawHead = yaw; + entity.getCaster().prevRotationYawHead = prevYaw; + entity.getCaster().limbSwing = limbSwing; + entity.getCaster().limbSwingAmount = limbSwingAmount; + entity.getCaster().prevLimbSwingAmount = prevLimbSwingAmount; + entity.getCaster().hurtTime = hurtTime; + entity.getCaster().setSneaking(sneak); + if(mount != null) entity.getCaster().startRiding(mount); + + }else{ + super.doRender(entity, x, y, z, entityYaw, partialTicks); + } + } + + @Override + protected ResourceLocation getEntityTexture(EntityDecoy entity){ + if(entity.getCaster() != null){ + try { + return (ResourceLocation)getEntityTexture.invoke(renderManager.getEntityRenderObject(entity.getCaster())); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassCastException e){ + Wizardry.logger.error("Error while reflectively calling Render#getEntityTexture as part of decoy rendering"); + e.printStackTrace(); + } + } + // Fallback to steve textures + return steveTextures; + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderEvilWizard.java b/src/main/java/electroblob/wizardry/client/renderer/RenderEvilWizard.java new file mode 100644 index 00000000..d61329f4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderEvilWizard.java @@ -0,0 +1,34 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.model.ModelWizard; +import electroblob.wizardry.entity.living.EntityEvilWizard; +import net.minecraft.client.renderer.entity.RenderBiped; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.entity.layers.LayerBipedArmor; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class RenderEvilWizard extends RenderBiped +{ + static final ResourceLocation[] textures = new ResourceLocation[6]; + + public RenderEvilWizard(RenderManager renderManager){ + + super(renderManager, new ModelWizard(), 0.5F); + + for(int i=0;i<6;i++){ + textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/evil_wizard_" + i + ".png"); + } + // Just using the default without overriding models, since the armour sets its own model anyway. + this.addLayer(new LayerBipedArmor(this)); + } + + @Override + protected ResourceLocation getEntityTexture(EntityEvilWizard wizard) { + return textures[wizard.textureIndex]; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderFireRing.java b/src/main/java/electroblob/wizardry/client/renderer/RenderFireRing.java new file mode 100644 index 00000000..1f70169f --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderFireRing.java @@ -0,0 +1,180 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.entity.construct.EntityFireRing; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.init.Blocks; +import net.minecraft.util.ResourceLocation; + +public class RenderFireRing extends Render { + + private final ResourceLocation texture; + private float scale = 1.0f; + + public RenderFireRing(RenderManager renderManager, ResourceLocation texture, float scale) { + super(renderManager); + this.texture = texture; + this.scale = scale; + } + + @Override + public void doRender(EntityFireRing entity, double par2, double par4, double par6, float par8, float par9){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + float yOffset = 0; + + GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6); + + this.bindTexture(texture); + float f6 = 1.0F; + float f7 = 0.5F; + float f8 = 0.5F; + + GlStateManager.rotate(-90, 1, 0, 0); + + GlStateManager.scale(scale, scale, scale); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex(); + buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + GlStateManager.disableRescaleNormal(); + GlStateManager.popMatrix(); + + // Fire + + GlStateManager.disableLighting(); + TextureAtlasSprite icon = Minecraft.getMinecraft().getBlockRendererDispatcher().getModelForState(Blocks.FIRE.getDefaultState()).getParticleTexture(); + int sides = 16; + float height = 1.0f; + + for(int k=0; k 0.0F){ + + this.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + float f71 = icon.getMinU(); + float f81 = icon.getMinV(); + float f9 = icon.getMaxU(); + float f10 = icon.getMaxV(); + + if (i / 2 % 2 == 0) + { + float f11 = f9; + f9 = f71; + f71 = f11; + } + + buffer.pos((double)(f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f9, (double)f10).endVertex(); + buffer.pos((double)(-f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f71, (double)f10).endVertex(); + buffer.pos((double)(-f2 - f3), (double)(height - f5), (double)f61).tex((double)f71, (double)f81).endVertex(); + buffer.pos((double)(f2 - f3), (double)(height - f5), (double)f61).tex((double)f9, (double)f81).endVertex(); + f4 -= 0.45F; + f5 -= 0.45F; + f2 *= 0.9F; + f61 += 0.03F; + ++i; + } + + tessellator.draw(); + GlStateManager.popMatrix(); + } + + for(int k=0; k 0.0F){ + + this.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + float f71 = icon.getMinU(); + float f81 = icon.getMinV(); + float f9 = icon.getMaxU(); + float f10 = icon.getMaxV(); + + if (i / 2 % 2 == 0) + { + float f11 = f9; + f9 = f71; + f71 = f11; + } + + buffer.pos((double)(f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f9, (double)f10).endVertex(); + buffer.pos((double)(-f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f71, (double)f10).endVertex(); + buffer.pos((double)(-f2 - f3), (double)(height - f5), (double)f61).tex((double)f71, (double)f81).endVertex(); + buffer.pos((double)(f2 - f3), (double)(height - f5), (double)f61).tex((double)f9, (double)f81).endVertex(); + f4 -= 0.45F; + f5 -= 0.45F; + f2 *= 0.9F; + f61 += 0.03F; + ++i; + } + + tessellator.draw(); + GlStateManager.popMatrix(); + } + + GlStateManager.enableLighting(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityFireRing entity) { + return null; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java b/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java new file mode 100644 index 00000000..db37b23d --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java @@ -0,0 +1,127 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.projectile.EntityForceArrow; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class RenderForceArrow extends Render{ + + private static final ResourceLocation arrowTextures = new ResourceLocation(Wizardry.MODID, "textures/entity/force_arrow.png"); + + public RenderForceArrow(RenderManager renderManager){ + super(renderManager); + } + + @Override + public void doRender(EntityForceArrow arrow, double par2, double par4, double par6, float par8, float par9){ + + this.bindEntityTexture(arrow); + GlStateManager.pushMatrix(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + GlStateManager.translate((float)par2, (float)par4, (float)par6); + GlStateManager.rotate(arrow.prevRotationYaw + (arrow.rotationYaw - arrow.prevRotationYaw) * par9 - 90.0F, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(arrow.prevRotationPitch + (arrow.rotationPitch - arrow.prevRotationPitch) * par9, 0.0F, 0.0F, 1.0F); + GlStateManager.rotate(180, 0, 1, 0); + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + float pixel = 1.0f/32.0f; + float u1 = 0.0f; + float u2 = pixel*14; + float v1 = 0.0f; + float v2 = pixel*7; + float u3 = pixel*16; + float u4 = 1.0f; + float v3 = 0.0f; + float v4 = pixel*16; + float u5 = 0.0f; + float u6 = pixel*7; + float v5 = pixel*25; + float v6 = 1.0f; + float scale = 0.05625F; + float f11 = 0.0f; + GlStateManager.enableRescaleNormal(); + //f11 = (float)par1EntityArrow.arrowShake - par9; + if (f11 > 0.0F) + { + float f12 = -MathHelper.sin(f11 * 3.0F) * f11; + GlStateManager.rotate(f12, 0.0F, 0.0F, 1.0F); + } + + scale*=0.8f; + + GlStateManager.rotate(45.0F, 1.0F, 0.0F, 0.0F); + GlStateManager.scale(scale, scale, scale); + GlStateManager.translate(-4.0F, 0.0F, 0.0F); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-5, 3.5, -3.5).tex((double)u5, (double)v5).endVertex(); + buffer.pos(-5, 3.5, 3.5).tex((double)u6, (double)v5).endVertex(); + buffer.pos(-5, -3.5, 3.5).tex((double)u6, (double)v6).endVertex(); + buffer.pos(-5, -3.5, -3.5).tex((double)u5, (double)v6); + tessellator.draw(); + + for(int i=0; i<5; i++){ + GlStateManager.color(1, 1, 1, 1 - i*0.2f); + double j = i + ((double)arrow.ticksExisted%3)/3; + double width = 2.0d + (Math.sqrt(j*2)-0.6)*2; + GL11.glNormal3f(scale, 0.0F, 0.0F); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-10 + j*4, -width, -width).tex((double)u3, (double)v3).endVertex(); + buffer.pos(-10 + j*4, -width, width).tex((double)u4, (double)v3).endVertex(); + buffer.pos(-10 + j*4, width, width).tex((double)u4, (double)v4).endVertex(); + buffer.pos(-10 + j*4, width, -width).tex((double)u3, (double)v4).endVertex(); + tessellator.draw(); + GL11.glNormal3f(-scale, 0.0F, 0.0F); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-10 + j*4, width, -width).tex((double)u3, (double)v3).endVertex(); + buffer.pos(-10 + j*4, width, width).tex((double)u4, (double)v3).endVertex(); + buffer.pos(-10 + j*4, -width, width).tex((double)u4, (double)v4).endVertex(); + buffer.pos(-10 + j*4, -width, -width).tex((double)u3, (double)v4).endVertex(); + tessellator.draw(); + } + + GlStateManager.color(1, 1, 1, 1); + + for (int i = 0; i < 4; ++i) + { + GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F); + GL11.glNormal3f(0.0F, 0.0F, scale); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-10.0D, -4.0D, 0.0D).tex((double)u1, (double)v1).endVertex(); + buffer.pos(10.0D, -4.0D, 0.0D).tex((double)u2, (double)v1).endVertex(); + buffer.pos(10.0D, 4.0D, 0.0D).tex((double)u2, (double)v2).endVertex(); + buffer.pos(-10.0D, 4.0D, 0.0D).tex((double)u1, (double)v2).endVertex(); + tessellator.draw(); + } + + GlStateManager.disableBlend(); + + GlStateManager.disableRescaleNormal(); + GlStateManager.enableLighting(); + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityForceArrow par1Entity) + { + return arrowTextures; + } +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderHammer.java b/src/main/java/electroblob/wizardry/client/renderer/RenderHammer.java new file mode 100644 index 00000000..b93fe9d2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderHammer.java @@ -0,0 +1,39 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.model.ModelHammer; +import electroblob.wizardry.entity.construct.EntityHammer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.util.ResourceLocation; + +public class RenderHammer extends Render { + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_hammer.png"); + private ModelHammer model = new ModelHammer(); + + public RenderHammer(RenderManager renderManager){ + super(renderManager); + } + + @Override + public void doRender(EntityHammer entity, double x, double y, double z, float f, float f1) { + + GlStateManager.pushMatrix(); + GlStateManager.translate(x, y+1.5, z); + GlStateManager.rotate(180, 0F, 0F, 1F); + + this.bindTexture(texture); + + model.render(entity, 0, 0, 0, 0, 0, 0.0625f); + + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityHammer entity) { + return texture; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderIceGiant.java b/src/main/java/electroblob/wizardry/client/renderer/RenderIceGiant.java new file mode 100644 index 00000000..4ee0812e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderIceGiant.java @@ -0,0 +1,39 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.model.ModelIceGiant; +import electroblob.wizardry.entity.living.EntityIceGiant; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.RenderLiving; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class RenderIceGiant extends RenderLiving { + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_giant.png"); + + public RenderIceGiant(RenderManager renderManager){ + super(renderManager, new ModelIceGiant(), 0.5F); + } + + @Override + protected ResourceLocation getEntityTexture(EntityIceGiant entity){ + return texture; + } + + @Override + protected void rotateCorpse(EntityIceGiant entityLiving, float pitch, float yaw, float partialTicks){ + + super.rotateCorpse(entityLiving, pitch, yaw, partialTicks); + + if ((double)entityLiving.limbSwingAmount >= 0.01D){ + float f3 = 13.0F; + float f4 = entityLiving.limbSwing - entityLiving.limbSwingAmount * (1.0F - partialTicks) + 6.0F; + float f5 = (Math.abs(f4 % f3 - f3 * 0.5F) - f3 * 0.25F) / (f3 * 0.25F); + GlStateManager.rotate(6.5F * f5, 0.0F, 0.0F, 1.0F); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderIceSpike.java b/src/main/java/electroblob/wizardry/client/renderer/RenderIceSpike.java new file mode 100644 index 00000000..0c4db9ef --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderIceSpike.java @@ -0,0 +1,84 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.construct.EntityIceSpike; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class RenderIceSpike extends Render { + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_spike.png"); + + public RenderIceSpike(RenderManager renderManager){ + super(renderManager); + } + + @Override + public void doRender(EntityIceSpike entity, double x, double y, double z, float fa, float partialTickTime) { + + GlStateManager.pushMatrix(); + + GlStateManager.translate((float)x, (float)y, (float)z); + // Apparently, disabling lighting... doesn't disable lighting. Or at least, you can still set the brightness + // with setLightmapTextureCoords. + GlStateManager.disableLighting(); + + int j = entity.getBrightnessForRender(partialTickTime); + int k = j % 65536; + int l = j / 65536; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)k / 1.0F, (float)l / 1.0F); + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + bindTexture(texture); + + // West face + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(0, 0, 0.5).tex(1, 1).endVertex(); + buffer.pos(0, 1, 0.5).tex(1, 0).endVertex(); + buffer.pos(0, 1, -0.5).tex(0, 0).endVertex(); + buffer.pos(0, 0, -0.5).tex(0, 1).endVertex(); + tessellator.draw(); + // South face + buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + buffer.pos( 0.5, 0, 0).tex(1, 1).endVertex(); + buffer.pos( 0.5, 1, 0).tex(1, 0).endVertex(); + buffer.pos(-0.5, 1, 0).tex(0, 0).endVertex(); + buffer.pos(-0.5, 0, 0).tex(0, 1).endVertex(); + tessellator.draw(); + // East face + buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + buffer.pos(0, 0, -0.5).tex(0, 1).endVertex(); + buffer.pos(0, 1, -0.5).tex(0, 0).endVertex(); + buffer.pos(0, 1, 0.5).tex(1, 0).endVertex(); + buffer.pos(0, 0, 0.5).tex(1, 1).endVertex(); + tessellator.draw(); + // North face + buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + buffer.pos(-0.5, 0, 0).tex(0, 1).endVertex(); + buffer.pos(-0.5, 1, 0).tex(0, 0).endVertex(); + buffer.pos( 0.5, 1, 0).tex(1, 0).endVertex(); + buffer.pos( 0.5, 0, 0).tex(1, 1).endVertex(); + tessellator.draw(); + + GlStateManager.enableLighting(); + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityIceSpike entity) { + return texture; + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderLightningDisc.java b/src/main/java/electroblob/wizardry/client/renderer/RenderLightningDisc.java new file mode 100644 index 00000000..a9b620fa --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderLightningDisc.java @@ -0,0 +1,82 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.entity.projectile.EntityLightningDisc; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class RenderLightningDisc extends Render { + + private final ResourceLocation texture; + private float scale = 1.0f; + + public RenderLightningDisc(RenderManager renderManager, ResourceLocation texture, float scale) { + super(renderManager); + this.texture = texture; + this.scale = scale; + } + + @Override + public void doRender(EntityLightningDisc entity, double par2, double par4, double par6, float par8, float par9){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + float yOffset = 0; + + GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6); + + this.bindTexture(texture); + float f6 = 1.0F; + float f7 = 0.5F; + float f8 = 0.5F; + + GlStateManager.rotate(-90, 1, 0, 0); + + GlStateManager.rotate(entity.ticksExisted*8, 0, 0, 1); + + GlStateManager.scale(scale, scale, scale); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + //tessellator.setColorRGBA_I(k1, 128); + //buffer.normal(0.0F, 1.0F, 0.0F); + buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex(); + buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + //buffer.normal(0.0F, 1.0F, 0.0F); + buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex(); + buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex(); + buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex(); + buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex(); + + tessellator.draw(); + + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + GlStateManager.disableRescaleNormal(); + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityLightningDisc entity) { + return null; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderLightningPulse.java b/src/main/java/electroblob/wizardry/client/renderer/RenderLightningPulse.java new file mode 100644 index 00000000..2190011a --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderLightningPulse.java @@ -0,0 +1,72 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.construct.EntityLightningPulse; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class RenderLightningPulse extends Render { + + private final ResourceLocation[] textures = new ResourceLocation[8]; + private float scale = 1.0f; + + public RenderLightningPulse(RenderManager renderManager, float scale) { + super(renderManager); + for(int i=0; i { + + private final ResourceLocation texture; + private boolean blend; + private boolean renderEnds; + private double length = 8.0, width = 2.0; + private int pixelsLong = 16, pixelsWide = 5; + + public RenderMagicArrow(RenderManager renderManager, ResourceLocation texture, boolean blend, double length, double width, int pixelsLong, int pixelsWide, boolean renderEnds){ + super(renderManager); + this.texture = texture; + this.blend = blend; + this.renderEnds = renderEnds; + this.length = length; + this.width = width; + this.pixelsLong = pixelsLong; + this.pixelsWide = pixelsWide; + } + + @Override + public void doRender(EntityMagicArrow entity, double par2, double par4, double par6, float par8, float par9){ + + this.bindEntityTexture(entity); + GlStateManager.pushMatrix(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + if(this.blend){ + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + } + + GlStateManager.translate((float)par2, (float)par4, (float)par6); + GlStateManager.rotate(entity.prevRotationYaw + (entity.rotationYaw - entity.prevRotationYaw) * par9 - 90.0F, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(entity.prevRotationPitch + (entity.rotationPitch - entity.prevRotationPitch) * par9, 0.0F, 0.0F, 1.0F); + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + float f2 = 0.0F; + float f3 = pixelsLong / 32.0F; + float f4 = 0.0F; + float f5 = pixelsWide / 32.0F; + float f6 = 0.0F; + float f7 = 0.15625F; + float f8 = (float)5 / 32.0F; + float f9 = (float)10 / 32.0F; + float f10 = 0.05625F; + float f11 = 0.0f; + GlStateManager.enableRescaleNormal(); + //f11 = (float)par1EntityArrow.arrowShake - par9; + if (f11 > 0.0F) + { + float f12 = -MathHelper.sin(f11 * 3.0F) * f11; + GlStateManager.rotate(f12, 0.0F, 0.0F, 1.0F); + } + + GlStateManager.rotate(45.0F, 1.0F, 0.0F, 0.0F); + GlStateManager.scale(f10, f10, f10); + GlStateManager.translate(-4.0F, 0.0F, 0.0F); + GL11.glNormal3f(f10, 0.0F, 0.0F); + + if(renderEnds){ + // Ends + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-7.0D, -width, -width).tex((double)f6, (double)f8).endVertex(); + buffer.pos(-7.0D, -width, width).tex((double)f7, (double)f8).endVertex(); + buffer.pos(-7.0D, width, width).tex((double)f7, (double)f9).endVertex(); + buffer.pos(-7.0D, width, -width).tex((double)f6, (double)f9).endVertex(); + tessellator.draw(); + GL11.glNormal3f(-f10, 0.0F, 0.0F); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-7.0D, width, -width).tex((double)f6, (double)f8).endVertex(); + buffer.pos(-7.0D, width, width).tex((double)f7, (double)f8).endVertex(); + buffer.pos(-7.0D, -width, width).tex((double)f7, (double)f9).endVertex(); + buffer.pos(-7.0D, -width, -width).tex((double)f6, (double)f9).endVertex(); + tessellator.draw(); + } + + for (int i = 0; i < 4; ++i){ + // Sides + GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F); + GL11.glNormal3f(0.0F, 0.0F, f10); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-length, -width, 0.0D).tex((double)f2, (double)f4).endVertex(); + buffer.pos(length, -width, 0.0D).tex((double)f3, (double)f4).endVertex(); + buffer.pos(length, width, 0.0D).tex((double)f3, (double)f5).endVertex(); + buffer.pos(-length, width, 0.0D).tex((double)f2, (double)f5).endVertex(); + tessellator.draw(); + } + + if(this.blend){ + GlStateManager.disableBlend(); + } + + GlStateManager.disableRescaleNormal(); + GlStateManager.enableLighting(); + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityMagicArrow arrow) + { + return texture; + } +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderMagicLight.java b/src/main/java/electroblob/wizardry/client/renderer/RenderMagicLight.java new file mode 100644 index 00000000..1d49c546 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderMagicLight.java @@ -0,0 +1,130 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.tileentity.TileEntityMagicLight; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class RenderMagicLight extends TileEntitySpecialRenderer { + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/light_ray.png"); + private static final ResourceLocation texture2 = new ResourceLocation(Wizardry.MODID, "textures/entity/light_aura.png"); + + @Override + public void renderTileEntityAt(TileEntityMagicLight tileentity, double x, double y, double z, float f, int destroyStage){ + + GlStateManager.pushMatrix(); + + GlStateManager.disableCull(); + GlStateManager.enableBlend(); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + RenderHelper.disableStandardItemLighting(); + + GlStateManager.translate(x + 0.5, y + 0.5, z + 0.5); + + if(tileentity.timer < 10){ + GlStateManager.scale((float)tileentity.timer/10, (float)tileentity.timer/10, (float)tileentity.timer/10); + } + if(tileentity.timer > tileentity.maxTimer-10){ + GlStateManager.scale((float)(tileentity.maxTimer-tileentity.timer)/10, (float)(tileentity.maxTimer-tileentity.timer)/10, (float)(tileentity.maxTimer-tileentity.timer)/10); + } + + // Renders the aura effect + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + GlStateManager.pushMatrix(); + + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + // This counteracts the reverse rotation behaviour when in front f5 view. + // Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example. + float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? Minecraft.getMinecraft().getRenderManager().playerViewX : -Minecraft.getMinecraft().getRenderManager().playerViewX; + GlStateManager.rotate(180.0F - Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + this.bindTexture(texture2); + + buffer.pos(-0.6, 0.6, 0).tex(0, 0).endVertex(); + buffer.pos(0.6, 0.6, 0).tex(1, 0).endVertex(); + buffer.pos(0.6, -0.6, 0).tex(1, 1).endVertex(); + buffer.pos(-0.6, -0.6, 0).tex(0, 1).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + + // Renders the rays + + // For some reason, the old blend function (GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA) caused the innermost + // ends of the rays to appear black, so I have changed it to this, which looks very slightly different. + GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA); + + this.bindTexture(texture); + + if(tileentity.randomiser.length >= 30){ + for(int j=0; j<30; j++){ + + int sliceAngle = 20 + tileentity.randomiser[j]; + float scale = 0.5f; + + GlStateManager.pushMatrix(); + + GlStateManager.rotate(31*tileentity.randomiser[j], 1, 0, 0); + GlStateManager.rotate(31*tileentity.randomiser2[j], 0, 0, 1); + + /* + * OK, so here are the changes to rendering as far as I know: + * Vertex formats specify how the methods are arranged + * Color has to be called for every vertex, I think. + * The new methods thing is a bit weird, because other than the number of arguments there is + * essentially no difference between pos, tex, color, normal and lightmap. At least they make + * the code more readable. + */ + + buffer.begin(5, DefaultVertexFormats.POSITION_TEX_COLOR); + + buffer.pos(0, 0, 0).tex(0, 0).color(255, 255, 255, 0).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).color(255, 255, 255, 0).endVertex(); + + double x1 = scale*Math.sin((tileentity.timer + 40*j)*(Math.PI/180)); + //double y1 = 0.7*Math.cos((timerentity.timer - 40*j)*(Math.PI/180))*j/10; + double z1 = scale*Math.cos((tileentity.timer + 40*j)*(Math.PI/180)); + + double x2 = scale*Math.sin((tileentity.timer + 40*j - sliceAngle)*(Math.PI/180)); + //double y2 = 0.7*Math.sin((timerentity.timer - 40*j)*(Math.PI/180))*j/10; + double z2 = scale*Math.cos((tileentity.timer + 40*j - sliceAngle)*(Math.PI/180)); + + buffer.pos(x1, 0, z1).tex(1, 0).color(0, 0, 0, 255).endVertex(); + buffer.pos(x2, 0, z2).tex(1, 1).color(0, 0, 0, 255).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + } + } + + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableCull(); + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + RenderHelper.enableStandardItemLighting(); + + GlStateManager.popMatrix(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderPhoenix.java b/src/main/java/electroblob/wizardry/client/renderer/RenderPhoenix.java new file mode 100644 index 00000000..bd070796 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderPhoenix.java @@ -0,0 +1,52 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.model.ModelPhoenix; +import electroblob.wizardry.entity.living.EntityPhoenix; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.entity.RenderLiving; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class RenderPhoenix extends RenderLiving { + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/phoenix.png"); + + public RenderPhoenix(RenderManager renderManager){ + super(renderManager, new ModelPhoenix(), 1.0f); + } + + @Override + protected ResourceLocation getEntityTexture(EntityPhoenix entity){ + return texture; + } + + @Override + protected void rotateCorpse(EntityPhoenix par1EntityPhoenix, float par2, float par3, float par4){ + GlStateManager.translate(0.0F, -0.1F, 0.0F); + super.rotateCorpse(par1EntityPhoenix, par2, par3, par4); + } + + @Override + public void doRender(EntityPhoenix phoenix, double par2, double par4, double par6, float par8, float par9){ + + GlStateManager.pushMatrix(); + + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + super.doRender(phoenix, par2, par4, par6, par8, par9); + + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + } +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderProjectile.java b/src/main/java/electroblob/wizardry/client/renderer/RenderProjectile.java new file mode 100644 index 00000000..dc00bf41 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderProjectile.java @@ -0,0 +1,88 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.entity.projectile.EntityMagicProjectile; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class RenderProjectile extends Render { + + private float scale; + private boolean blend = false; + + private final ResourceLocation texture; + + public RenderProjectile(RenderManager renderManager, float scale, ResourceLocation texture, boolean doBlending) + { + super(renderManager); + this.scale = scale; + this.texture = texture; + this.blend = doBlending; + } + + @Override + public void doRender(EntityMagicProjectile entity, double par2, double par4, double par6, float par8, float par9){ + + GlStateManager.pushMatrix(); + this.bindTexture(texture); + GlStateManager.translate((float)par2, (float)par4, (float)par6); + GlStateManager.enableRescaleNormal(); + if(blend){ + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + } + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + float f2 = this.scale; + GlStateManager.scale(f2 / 1.0F, f2 / 1.0F, f2 / 1.0F); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + + float f3 = 0.0f; + float f4 = 1.0f; + float f5 = 0.0f; + float f6 = 1.0f; + float f7 = 1.0F; + float f8 = 0.5F; + float f9 = 0.25F; + + // This counteracts the reverse rotation behaviour when in front f5 view. + // Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example. + float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? this.renderManager.playerViewX : -this.renderManager.playerViewX; + GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + //buffer.normal(0.0F, 1.0F, 0.0F); + buffer.pos((double)(0.0F - f8), (double)(0.0F - f9), 0.0D).tex((double)f3, (double)f6).endVertex(); + buffer.pos((double)(f7 - f8), (double)(0.0F - f9), 0.0D).tex((double)f4, (double)f6).endVertex(); + buffer.pos((double)(f7 - f8), (double)(1.0F - f9), 0.0D).tex((double)f4, (double)f5).endVertex(); + buffer.pos((double)(0.0F - f8), (double)(1.0F - f9), 0.0D).tex((double)f3, (double)f5).endVertex(); + tessellator.draw(); + + GlStateManager.disableRescaleNormal(); + if(blend){ + GlStateManager.disableBlend(); + } + GlStateManager.enableLighting(); + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityMagicProjectile par1Entity){ + return texture; + } +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderSigil.java b/src/main/java/electroblob/wizardry/client/renderer/RenderSigil.java new file mode 100644 index 00000000..bb33b60d --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderSigil.java @@ -0,0 +1,89 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.entity.construct.EntityHealAura; +import electroblob.wizardry.entity.construct.EntityMagicConstruct; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; + +public class RenderSigil extends Render { + + private final ResourceLocation texture; + private float scale = 1.0f; + private boolean invisibleToEnemies; + + public RenderSigil(RenderManager renderManager, ResourceLocation texture, float scale, boolean invisibleToEnemies) { + super(renderManager); + this.texture = texture; + this.scale = scale; + this.invisibleToEnemies = invisibleToEnemies; + } + + @Override + public void doRender(EntityMagicConstruct entity, double par2, double par4, double par6, float par8, float par9){ + + // Makes the sigil invisible to enemies of the player that created it + if(this.invisibleToEnemies){ + + if(entity.getCaster() instanceof EntityPlayer + && !WizardryUtilities.isPlayerAlly((EntityPlayer)entity.getCaster(), Minecraft.getMinecraft().thePlayer)){ + return; + } + } + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + float yOffset = 0; + + GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6); + + this.bindTexture(texture); + float f6 = 1.0F; + float f7 = 0.5F; + float f8 = 0.5F; + + GlStateManager.rotate(-90, 1, 0, 0); + + // Healing aura rotates slowly + if(entity instanceof EntityHealAura) GlStateManager.rotate(entity.ticksExisted/3.0f, 0, 0, 1); + + GlStateManager.scale(scale, scale, scale); + + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + //tessellator.setColorRGBA_I(k1, 128); + //buffer.normal(0.0F, 1.0F, 0.0F); + buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex(); + buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex(); + buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.disableBlend(); + GlStateManager.enableLighting(); + GlStateManager.disableRescaleNormal(); + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityMagicConstruct entity) { + return null; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritHorse.java b/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritHorse.java new file mode 100644 index 00000000..dda80293 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritHorse.java @@ -0,0 +1,36 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.model.ModelHorse; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.RenderHorse; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.entity.passive.EntityHorse; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class RenderSpiritHorse extends RenderHorse { + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/spirit_horse.png"); + + public RenderSpiritHorse(RenderManager renderManager, float par2){ + super(renderManager, new ModelHorse(), par2); + } + + @Override + protected ResourceLocation getEntityTexture(EntityHorse entity) { + return texture; + } + + @Override + protected void preRenderCallback(EntityHorse entitylivingbaseIn, float partialTickTime){ + super.preRenderCallback(entitylivingbaseIn, partialTickTime); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritWolf.java b/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritWolf.java new file mode 100644 index 00000000..e1ffe797 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritWolf.java @@ -0,0 +1,35 @@ +package electroblob.wizardry.client.renderer; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.model.ModelWolf; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.entity.RenderWolf; +import net.minecraft.entity.passive.EntityWolf; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class RenderSpiritWolf extends RenderWolf { + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/spirit_wolf.png"); + + public RenderSpiritWolf(RenderManager renderManager, float par3){ + super(renderManager, new ModelWolf(), par3); + } + + @Override + protected ResourceLocation getEntityTexture(EntityWolf entity) { + return texture; + } + + @Override + protected void preRenderCallback(EntityWolf entity, float partialTickTime){ + super.preRenderCallback(entity, partialTickTime); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + } +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderStatue.java b/src/main/java/electroblob/wizardry/client/renderer/RenderStatue.java new file mode 100644 index 00000000..33301d84 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderStatue.java @@ -0,0 +1,64 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.tileentity.TileEntityStatue; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; + +public class RenderStatue extends TileEntitySpecialRenderer { + + private int destroyStage = 0; // Gets set each time a statue is rendered to allow access from the layer renderer + + @Override + public void renderTileEntityAt(TileEntityStatue statue, double x, double y, double z, float partialTicks, int destroyStage){ + + // Multiblock support for the breaking animation. The chest has its own way of doing this in + // TileEntityRendererDispatcher, but I don't have access to that. + if(statue.position != 1 && destroyStage >= 0){ + TileEntity tileentity = statue.getWorld().getTileEntity(statue.getPos().down(statue.position-1)); + //System.out.println(tileentity); + if(tileentity instanceof TileEntityStatue){ + // If this is the block breaking animation pass and this isn't the bottom block, divert the call to + // the bottom block. + this.renderTileEntityAt((TileEntityStatue)tileentity, x, y - (statue.position-1), z, partialTicks, destroyStage); + } + } + + if(statue.creature != null && statue.position == 1){ + + this.destroyStage = destroyStage; + + GlStateManager.pushMatrix(); + // The next line makes stuff render in the same place relative to the world wherever the player is. + GlStateManager.translate((float)x + 0.5F, (float)y, (float)z + 0.5F); + GlStateManager.enableLighting(); + + float yaw = statue.creature.prevRotationYaw; + int i = statue.creature.getBrightnessForRender(0); + + int j = i % 65536; + int k = i / 65536; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + GlStateManager.rotate(-yaw, 0F, 1F, 0F); + // Stops the normal model from rendering. + if(!statue.isIce) statue.creature.setInvisible(true); + // Setting the last parameter to true prevents the debug bounding box from rendering. + // For some reason, passing in the partialTicks causes the entity to spin round really fast + Minecraft.getMinecraft().getRenderManager().doRenderEntity(statue.creature, 0, 0, 0, 0, 0, true); + if(!statue.isIce) statue.creature.setInvisible(false); + + GlStateManager.popMatrix(); + + } + } + + public ResourceLocation getBlockBreakingTexture(){ + return destroyStage < 0 ? null : DESTROY_STAGES[destroyStage]; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderWizard.java b/src/main/java/electroblob/wizardry/client/renderer/RenderWizard.java new file mode 100644 index 00000000..e2043d5b --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderWizard.java @@ -0,0 +1,34 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.model.ModelWizard; +import electroblob.wizardry.entity.living.EntityWizard; +import net.minecraft.client.renderer.entity.RenderBiped; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.entity.layers.LayerBipedArmor; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class RenderWizard extends RenderBiped { + + static final ResourceLocation[] textures = new ResourceLocation[6]; + + public RenderWizard(RenderManager renderManager){ + + super(renderManager, new ModelWizard(), 0.5F); + + for(int i=0;i<6;i++){ + textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/wizard_" + i + ".png"); + } + // Just using the default without overriding models, since the armour sets its own model anyway. + this.addLayer(new LayerBipedArmor(this)); + } + + @Override + protected ResourceLocation getEntityTexture(EntityWizard wizard) { + return textures[wizard.textureIndex]; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderWraithMinion.java b/src/main/java/electroblob/wizardry/client/renderer/RenderWraithMinion.java new file mode 100644 index 00000000..2c31a7cb --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderWraithMinion.java @@ -0,0 +1,26 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.entity.living.EntityBlazeMinion; +import net.minecraft.client.model.ModelBlaze; +import net.minecraft.client.renderer.entity.RenderLiving; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class RenderWraithMinion extends RenderLiving +{ + private ResourceLocation texture = new ResourceLocation("textures/entity/blaze.png"); + + public RenderWraithMinion(RenderManager renderManagerIn) + { + super(renderManagerIn, new ModelBlaze(), 0.5F); + } + + @Override + protected ResourceLocation getEntityTexture(EntityBlazeMinion entity) + { + return texture; + } +} diff --git a/src/main/java/electroblob/wizardry/command/CommandCastSpell.java b/src/main/java/electroblob/wizardry/command/CommandCastSpell.java new file mode 100644 index 00000000..7685851b --- /dev/null +++ b/src/main/java/electroblob/wizardry/command/CommandCastSpell.java @@ -0,0 +1,183 @@ +package electroblob.wizardry.command; + +import java.util.List; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketCastSpell; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.NumberInvalidException; +import net.minecraft.command.PlayerNotFoundException; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.JsonToNBT; +import net.minecraft.nbt.NBTException; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +public class CommandCastSpell extends CommandBase { + + @Override + public String getCommandName(){ + return Wizardry.settings.castCommandName; + } + + @Override + public int getRequiredPermissionLevel(){ + // I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console... + return 2; + } + + @Override + public String getCommandUsage(ICommandSender p_71518_1_){ + // Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there + // the custom command name will not display. + return "commands.wizardry:cast.usage"; + //return I18n.format("commands.wizardry:cast.usage", Wizardry.settings.castCommandName); + } + + @Override + public List getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) { + switch(arguments.length){ + case 1: return getListOfStringsMatchingLastWord(arguments, Spell.getSpellNames()); + case 2: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames()); + } + return super.getTabCompletionOptions(server, sender, arguments, pos); + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException { + + if(arguments.length < 1){ + throw new WrongUsageException("commands.wizardry:cast.usage", Wizardry.settings.castCommandName); + }else{ + + int i=0; + + EntityPlayerMP entityplayermp = null; + + try{ + entityplayermp = getCommandSenderAsPlayer(sender); + }catch(PlayerNotFoundException exception){ + // Nothing here since the player specifying is done later, I just don't want it to throw an exception here. + } + + Spell spell = Spell.get(arguments[i++]); + + if(spell == null){ + throw new NumberInvalidException("commands.wizardry:cast.not_found", new Object[]{arguments[i-1]}); + } + + boolean castAsOtherPlayer = false; + + if(i < arguments.length){ + try{ + // If the second argument is a player and is not the player that gave the command, the spell is cast + // as the given player rather than the command sender, and there is a different chat readout. + EntityPlayerMP entityplayermp1 = getPlayer(server, sender, arguments[i++]); + if(entityplayermp != entityplayermp1){ + castAsOtherPlayer = true; + entityplayermp = entityplayermp1; + } + }catch(PlayerNotFoundException exception){ + // If no player was found, rather than give an error it simply assumes the player was unspecified. + i--; + } + } + + // If, after this point, the player is still null, the sender must be a command block or the console and the + // player must not have been specified, meaning an exception should be thrown. + if(entityplayermp == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on."); + + SpellModifiers modifiers = new SpellModifiers(); + + if(i < arguments.length){ + + // Copied from CommandGive. Why it doesn't just use arguments[i] itself I don't know. + String nbt = getChatComponentFromNthArg(sender, arguments, i++).getUnformattedText(); + + try{ + modifiers = SpellModifiers.fromNBT(JsonToNBT.getTagFromJson(nbt)); + }catch(NBTException nbtexception){ + throw new CommandException("commands.wizardry:cast.tag_error", nbtexception.getMessage()); + } + + for(float multiplier : modifiers.getModifiers().values()){ + if(multiplier < 0){ + throw new NumberInvalidException("commands.generic.double.tooSmall", multiplier, 0); + }else if(multiplier > Wizardry.settings.maxSpellCommandMultiplier){ + throw new NumberInvalidException("commands.generic.double.tooBig", multiplier, Wizardry.settings.maxSpellCommandMultiplier); + } + } + + } + + if(spell.isContinuous){ + + WizardData properties = WizardData.get((EntityPlayer)entityplayermp); + + if(properties != null){ + if(properties.isCasting()){ + WizardData.get((EntityPlayer)entityplayermp).stopCastingContinuousSpell(); + }else{ + + WizardData.get((EntityPlayer)entityplayermp).startCastingContinuousSpell(spell, modifiers); + + if(castAsOtherPlayer){ + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success_remote_continuous", spell.getNameForTranslationFormatted(), entityplayermp.getName())); + }else{ + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success_continuous", spell.getNameForTranslationFormatted())); + } + } + + return; + } + + }else{ + + if(spell.cast(entityplayermp.worldObj, entityplayermp, EnumHand.MAIN_HAND, 0, modifiers)){ + + if(spell.doesSpellRequirePacket()){ + // Sends a packet to all players in dimension to tell them to spawn particles. + // Only sent if the spell succeeded, because if the spell failed, you wouldn't + // need to spawn any particles! + IMessage msg = new PacketCastSpell.Message(entityplayermp.getEntityId(), null, spell.id(), modifiers); + WizardryPacketHandler.net.sendToDimension(msg, entityplayermp.worldObj.provider.getDimension()); + } + + if(WizardData.get((EntityPlayer)entityplayermp) != null){ + // Added optimisation from 1.7.10: if the spell was already discovered, nothing happens. + if(WizardData.get((EntityPlayer)entityplayermp).discoverSpell(spell)){ + // If the spell didn't send a packet itself, the extended player needs to be synced so the + // spell discovery updates on the client. + if(!spell.doesSpellRequirePacket()) WizardData.get((EntityPlayer)entityplayermp).sync(); + } + } + + if(castAsOtherPlayer){ + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success_remote", spell.getNameForTranslationFormatted(), entityplayermp.getName())); + }else{ + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success", spell.getNameForTranslationFormatted())); + } + return; + } + } + + ITextComponent message = new TextComponentTranslation("commands.wizardry:cast.fail", spell.getNameForTranslationFormatted()); + message.getStyle().setColor(TextFormatting.RED); + sender.addChatMessage(message); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java b/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java new file mode 100644 index 00000000..c2496614 --- /dev/null +++ b/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java @@ -0,0 +1,130 @@ +package electroblob.wizardry.command; + +import java.util.List; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.NumberInvalidException; +import net.minecraft.command.PlayerNotFoundException; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentTranslation; + +public class CommandDiscoverSpell extends CommandBase { + + @Override + public String getCommandName(){ + return Wizardry.settings.discoverspellCommandName; + } + + @Override + public int getRequiredPermissionLevel(){ + // I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console... + return 2; + } + + /* + @Override + public boolean checkPermission(MinecraftServer server, ICommandSender sender){ + // Only ops (multiplayer) or players with cheats enabled (singleplayer/LAN) can use /discoverspell. + return !(sender instanceof EntityPlayer) || server.getServer().getConfigurationManager().func_152596_g(((EntityPlayer)sender).getGameProfile()); + } + */ + + @Override + public String getCommandUsage(ICommandSender p_71518_1_){ + // Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there + // the custom command name will not display. + return "commands.wizardry:discoverspell.usage"; + //return I18n.format("commands.wizardry:discoverspell.usage", Wizardry.settings.discoverspellCommandName); + } + + @Override + public List getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) { + switch(arguments.length){ + case 1: return getListOfStringsMatchingLastWord(arguments, Spell.getSpellNames()); + case 2: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames()); + } + return super.getTabCompletionOptions(server, sender, arguments, pos); + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException { + + if(arguments.length < 1){ + throw new WrongUsageException("commands.wizardry:discoverspell.usage", Wizardry.settings.discoverspellCommandName); + }else{ + + int i=0; + boolean clear = false; + boolean all = false; + + EntityPlayerMP entityplayermp = null; + + try{ + entityplayermp = getCommandSenderAsPlayer(sender); + }catch(PlayerNotFoundException exception){ + // Nothing here since the player specifying is done later, I just don't want it to throw an exception here. + } + + Spell spell = Spells.none; + + if(arguments[i].equals("clear")){ + clear = true; + i++; + }else if(arguments[i].equals("all")){ + all = true; + i++; + }else{ + + spell = Spell.get(arguments[i++]); + + if(spell == null){ + throw new NumberInvalidException("commands.wizardry:discoverspell.not_found", new Object[]{arguments[i-1]}); + } + } + + if(i < arguments.length){ + // If the second argument is a player and is not the player that gave the command, the spell is + // discovered as the given player rather than the command sender. + EntityPlayerMP entityplayermp1 = getPlayer(server, sender, arguments[i++]); + if(entityplayermp != entityplayermp1){ + entityplayermp = entityplayermp1; + } + } + + // If, after this point, the player is still null, the sender must be a command block or the console and the + // player must not have been specified, meaning an exception should be thrown. + if(entityplayermp == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on."); + + WizardData properties = WizardData.get(entityplayermp); + + if(properties != null){ + if(clear){ + properties.spellsDiscovered.clear(); + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.clear", entityplayermp.getName())); + }else if(all){ + properties.spellsDiscovered.addAll(Spell.getSpells(Spell.allSpells)); + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.all", entityplayermp.getName())); + }else{ + if(properties.hasSpellBeenDiscovered(spell)){ + properties.spellsDiscovered.remove(spell); + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.removespell", spell.getNameForTranslationFormatted(), entityplayermp.getName())); + }else{ + properties.discoverSpell(spell); + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.addspell", spell.getNameForTranslationFormatted(), entityplayermp.getName())); + } + } + properties.sync(); + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/command/CommandSetAlly.java b/src/main/java/electroblob/wizardry/command/CommandSetAlly.java new file mode 100644 index 00000000..b566306c --- /dev/null +++ b/src/main/java/electroblob/wizardry/command/CommandSetAlly.java @@ -0,0 +1,113 @@ +package electroblob.wizardry.command; + +import java.util.List; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.NumberInvalidException; +import net.minecraft.command.PlayerNotFoundException; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; + +public class CommandSetAlly extends CommandBase { + + @Override + public String getCommandName(){ + return Wizardry.settings.allyCommandName; + } + + @Override + public int getRequiredPermissionLevel(){ + // I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console... + return 0; + } + + @Override + public boolean checkPermission(MinecraftServer server, ICommandSender p_71519_1_) + { + return true; + } + + @Override + public String getCommandUsage(ICommandSender p_71518_1_){ + // Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there + // the custom command name will not display. + return "commands.wizardry:ally.usage"; + //return I18n.format("commands.wizardry:ally.usage", Wizardry.settings.allyCommandName); + } + + @Override + public List getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) { + switch(arguments.length){ + case 1: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames()); + case 2: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames()); + } + return super.getTabCompletionOptions(server, sender, arguments, pos); + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException { + + if(arguments.length < 1){ + throw new WrongUsageException("commands.wizardry:ally.usage", Wizardry.settings.allyCommandName); + }else{ + + EntityPlayerMP allyOf = null; + + try{ + allyOf = getCommandSenderAsPlayer(sender); + }catch(PlayerNotFoundException exception){ + // Nothing here since the player specifying is done later, I just don't want it to throw an exception here. + } + + boolean executeAsOtherPlayer = false; + + EntityPlayerMP ally = getPlayer(server, sender, arguments[0]); + // Don't want to catch the exception here, because the first player argument is always required. + + if(arguments.length > 1){ + + allyOf = getPlayer(server, sender, arguments[1]); + // Don't want to catch the exception here either, because there can be no other second argument. + + if(allyOf != sender && sender instanceof EntityPlayer && !WizardryUtilities.isPlayerOp((EntityPlayer)sender, server)){ + // Displays a chat message if a non-op tries to modify another player's allies. + TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation("commands.wizardry:ally.permission"); + TextComponentTranslation2.getStyle().setColor(TextFormatting.RED); + allyOf.addChatMessage(TextComponentTranslation2); + return; + } + + if(allyOf != sender) executeAsOtherPlayer = true; + } + + // If, after this point, allyOf is still null, the sender must be a command block or the console and two + // players must not have been specified, meaning an exception should be thrown. + if(allyOf == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on."); + + if(allyOf == ally) throw new NumberInvalidException("commands.wizardry:ally.self"); + + if(WizardData.get(allyOf) != null){ + String string = WizardData.get(allyOf).toggleAlly(ally) ? "add" : "remove"; + if(executeAsOtherPlayer){ + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:ally." + string + "ally", ally.getName(), allyOf.getName())); + // In this case, the player whose allies have been modified is also notified. + allyOf.addChatMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName())); + }else{ + sender.addChatMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName())); + } + } + + } + } + +} diff --git a/src/main/java/electroblob/wizardry/command/CommandViewAllies.java b/src/main/java/electroblob/wizardry/command/CommandViewAllies.java new file mode 100644 index 00000000..257b4b85 --- /dev/null +++ b/src/main/java/electroblob/wizardry/command/CommandViewAllies.java @@ -0,0 +1,112 @@ +package electroblob.wizardry.command; + +import java.util.List; +import java.util.Set; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.resources.I18n; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.PlayerNotFoundException; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; + +public class CommandViewAllies extends CommandBase { + + @Override + public String getCommandName(){ + return Wizardry.settings.alliesCommandName; + } + + @Override + public int getRequiredPermissionLevel(){ + // I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console... + return 0; + } + + @Override + public boolean checkPermission(MinecraftServer server, ICommandSender p_71519_1_) + { + return true; + } + + @Override + public String getCommandUsage(ICommandSender p_71518_1_){ + // Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there + // the custom command name will not display. + return "commands.wizardry:allies.usage"; + //return I18n.format("commands.wizardry:allies.usage", Wizardry.settings.alliesCommandName); + } + + @Override + public List getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) { + switch(arguments.length){ + case 1: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames()); + } + return super.getTabCompletionOptions(server, sender, arguments, pos); + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException { + + EntityPlayerMP player = null; + + try{ + player = getCommandSenderAsPlayer(sender); + }catch(PlayerNotFoundException exception){ + // Nothing here since the player specifying is done later, I just don't want it to throw an exception here. + } + + boolean executeAsOtherPlayer = false; + + if(arguments.length > 0){ + + player = getPlayer(server, sender, arguments[0]); + // Don't want to catch the exception here either, because there can be no other first argument. + + if(player != sender && sender instanceof EntityPlayer && !WizardryUtilities.isPlayerOp((EntityPlayer)sender, server)){ + // Displays a chat message if a non-op tries to view another player's allies. + TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation("commands.wizardry:allies.permission"); + TextComponentTranslation2.getStyle().setColor(TextFormatting.RED); + player.addChatMessage(TextComponentTranslation2); + return; + } + + if(player != sender) executeAsOtherPlayer = true; + } + + // If, after this point, player is still null, the sender must be a command block or the console and the + // player must not have been specified, meaning an exception should be thrown. + if(player == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on."); + + if(WizardData.get(player) != null){ + + String string = ""; + Set names = WizardData.get(player).allyNames; + + if(!names.isEmpty()){ + for(String name : names){ + string = string + name + ", "; + } + // Cuts the last " ," off of the string. + string = string.substring(0, string.length() - 2); + }else{ + string = I18n.format("commands.wizardry:allies.none"); + } + + if(executeAsOtherPlayer){ + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:allies.list_other", player.getName(), string)); + }else{ + sender.addChatMessage(new TextComponentTranslation("commands.wizardry:allies.list", string)); + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/constants/Constants.java b/src/main/java/electroblob/wizardry/constants/Constants.java new file mode 100644 index 00000000..95b79b9c --- /dev/null +++ b/src/main/java/electroblob/wizardry/constants/Constants.java @@ -0,0 +1,44 @@ +package electroblob.wizardry.constants; + +import electroblob.wizardry.WizardryEventHandler; + +/** Stores various global constants used in Wizardry. */ +public final class Constants { + + /** The amount of mana each magic crystal is worth */ + public static final int MANA_PER_CRYSTAL = 100; + /** The amount of mana each mana flask can hold */ + public static final int MANA_PER_FLASK = 700; + /** The maximum number of one type of wand upgrade which can be applied to a wand. */ + public static final int UPGRADE_STACK_LIMIT = 3; + /** The fraction by which cooldowns are reduced for each level of cooldown upgrade. */ + public static final float COOLDOWN_REDUCTION_PER_LEVEL = 0.15f; + /** The fraction by which maximum charge is increased for each level of storage upgrade. */ + public static final float STORAGE_INCREASE_PER_LEVEL = 0.15f; + /** The fraction by which damage is increased for each tier of matching wand. */ + public static final float DAMAGE_INCREASE_PER_TIER = 0.15f; + /** The fraction by which costs are reduced for each piece of matching armour. Note that changing this value will not + * affect continuous spells, since they are handled differently. */ + public static final float COST_REDUCTION_PER_ARMOUR = 0.2f; + /** The fraction by which spell duration is increased for each level of duration upgrade. */ + public static final float DURATION_INCREASE_PER_LEVEL = 0.25f; + /** The fraction by which spell range is increased for each level of range upgrade. */ + public static final float RANGE_INCREASE_PER_LEVEL = 0.25f; + /** The fraction by which spell blast radius is increased for each level of range upgrade. */ + public static final float BLAST_RADIUS_INCREASE_PER_LEVEL = 0.25f; + /** The fraction by which movement speed is reduced per level of frost effect. */ + public static final double FROST_SLOWNESS_PER_LEVEL = 0.5; + /** The fraction by which movement speed is reduced per level of decay effect. */ + public static final double DECAY_SLOWNESS_PER_LEVEL = 0.2; + /** The fraction by which dig speed is reduced per level of frost effect. */ + public static final float FROST_FATIGUE_PER_LEVEL = 0.45f; + /** The number of ticks between each mana increase for wands with the condenser upgrade. */ + public static final int CONDENSER_TICK_INTERVAL = 50; + /** The amount of mana given for a kill for each level of siphon upgrade. A random amount from 0 to this number - 1 + * is also added. See {@link WizardryEventHandler#onLivingDeathEvent} for more details. */ + public static final int SIPHON_MANA_PER_LEVEL = 3; + /** The number of ticks between the spawning of patches of decay when an entity has the decay effect. + * Note that decay won't spawn again if something is already standing in it. */ + public static final int DECAY_SPREAD_INTERVAL = 8; + +} diff --git a/src/main/java/electroblob/wizardry/constants/Element.java b/src/main/java/electroblob/wizardry/constants/Element.java new file mode 100644 index 00000000..48dd01f4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/constants/Element.java @@ -0,0 +1,67 @@ +package electroblob.wizardry.constants; + +import electroblob.wizardry.Wizardry; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public enum Element { + + /** The 'default' element, with {@link electroblob.wizardry.spell.MagicMissile MagicMissile} being its only spell. */ + MAGIC(new Style().setColor(TextFormatting.GRAY), "simple", Wizardry.MODID), + FIRE(new Style().setColor(TextFormatting.DARK_RED), "fire", Wizardry.MODID), + ICE(new Style().setColor(TextFormatting.AQUA), "ice", Wizardry.MODID), + LIGHTNING(new Style().setColor(TextFormatting.DARK_AQUA), "lightning", Wizardry.MODID), + NECROMANCY(new Style().setColor(TextFormatting.DARK_PURPLE), "necromancy", Wizardry.MODID), + EARTH(new Style().setColor(TextFormatting.DARK_GREEN), "earth", Wizardry.MODID), + SORCERY(new Style().setColor(TextFormatting.GREEN), "sorcery", Wizardry.MODID), + HEALING(new Style().setColor(TextFormatting.YELLOW), "healing", Wizardry.MODID); + + /** Display colour for this element */ + private final Style colour; + /** Unlocalised name for this element */ + private final String unlocalisedName; + /** The {@link ResourceLocation} for this element's 8x8 icon (displayed in the arcane workbench GUI) */ + private final ResourceLocation icon; + + private Element(Style colour, String name, String modid){ + this.colour = colour; + this.unlocalisedName = name; + this.icon = new ResourceLocation(modid, "textures/gui/element_icon_" + unlocalisedName + ".png"); + } + + /** Returns the translated display name of this element, without formatting. */ + @SideOnly(Side.CLIENT) + public String getDisplayName(){ + return net.minecraft.client.resources.I18n.format("element." + getUnlocalisedName()); + } + + /** Returns the {@link Style} object representing the colour of this element. */ + public Style getColour(){ + return colour; + } + + /** Returns the string formatting code which corresponds to the colour of this element. */ + public String getFormattingCode(){ + return colour.getFormattingCode(); + } + + /** Returns the translated display name for wizards of this element, shown in the trading GUI. */ + public ITextComponent getWizardName(){ + return new TextComponentTranslation("element." + getUnlocalisedName() + ".wizard"); + } + + /** Returns this element's unlocalised name. */ + public String getUnlocalisedName(){ + return unlocalisedName; + } + + /** Returns the {@link ResourceLocation} for this element's 8x8 icon (displayed in the arcane workbench GUI). */ + public ResourceLocation getIcon(){ + return icon; + } +} diff --git a/src/main/java/electroblob/wizardry/constants/SpellType.java b/src/main/java/electroblob/wizardry/constants/SpellType.java new file mode 100644 index 00000000..807d878c --- /dev/null +++ b/src/main/java/electroblob/wizardry/constants/SpellType.java @@ -0,0 +1,23 @@ +package electroblob.wizardry.constants; + +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public enum SpellType { + + ATTACK("attack"), + DEFENCE("defence"), + UTILITY("utility"), + MINION("minion"); + + private final String unlocalisedName; + + SpellType(String name){ + this.unlocalisedName = name; + } + + @SideOnly(Side.CLIENT) + public String getDisplayName(){ + return net.minecraft.client.resources.I18n.format("spelltype." + unlocalisedName); + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/constants/Tier.java b/src/main/java/electroblob/wizardry/constants/Tier.java new file mode 100644 index 00000000..f989b82b --- /dev/null +++ b/src/main/java/electroblob/wizardry/constants/Tier.java @@ -0,0 +1,81 @@ +package electroblob.wizardry.constants; + +import java.util.Random; + +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public enum Tier { + + BASIC(700, 3, 12, new Style().setColor(TextFormatting.WHITE), "basic"), + APPRENTICE(1000, 4, 5, new Style().setColor(TextFormatting.AQUA), "apprentice"), + ADVANCED(1500, 5, 2, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"), + MASTER(2500, 6, 1, new Style().setColor(TextFormatting.DARK_PURPLE), "master"); + + /** Maximum mana a wand of this tier can store. */ + public final int maxCharge; + /** Just an ordinal. Shouldn't really be needed but no point changing it now. */ + public final int level; + /** The maximum number of upgrades that can be applied to a wand of this tier. */ + public final int upgradeLimit; + /** The weight given to this tier in the standard weighting. */ + public final int weight; + /** The colour of text associated with this tier. */ + // Changed to a Style object for consistency. + private final Style colour; + + private final String unlocalisedName; + + private Tier(int maxCharge, int upgradeLimit, int weight, Style colour, String name){ + this.maxCharge = maxCharge; + this.level = ordinal(); + this.upgradeLimit = upgradeLimit; + this.weight = weight; + this.colour = colour; + this.unlocalisedName = name; + } + + @SideOnly(Side.CLIENT) + public String getDisplayName() { + return net.minecraft.client.resources.I18n.format("tier." + unlocalisedName); + } + + @SideOnly(Side.CLIENT) + public String getDisplayNameWithFormatting() { + return this.getFormattingCode() + net.minecraft.client.resources.I18n.format("tier." + unlocalisedName); + } + + public String getUnlocalisedName(){ + return unlocalisedName; + } + + public String getFormattingCode(){ + return colour.getFormattingCode(); + } + + /** Returns a random tier based on the standard weighting. Currently, the standard weighting is: Basic (Novice) 60%, + * Apprentice 25%, Advanced 10%, Master 5%. If an array of tiers is given, it picks a tier from the array, with the + * same relative weights for each. For example, if the array contains APPRENTICE and MASTER, then the weighting will + * become: Apprentice 83.3%, Master 16.7%. */ + public static Tier getWeightedRandomTier(Random random, Tier... tiers){ + + if(tiers.length == 0) tiers = values(); + + int totalWeight = 0; + + for(Tier tier : tiers) totalWeight += tier.weight; + + int randomiser = random.nextInt(totalWeight); + int cumulativeWeight = 0; + + for(Tier tier : tiers){ + cumulativeWeight += tier.weight; + if(randomiser < cumulativeWeight) return tier; + } + + // This will never happen, but it might as well be a sensible result. + return tiers[tiers.length-1]; + } +} diff --git a/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicSword.java b/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicSword.java new file mode 100644 index 00000000..0aca94ba --- /dev/null +++ b/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicSword.java @@ -0,0 +1,59 @@ +package electroblob.wizardry.enchantment; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentDamage; +import net.minecraft.entity.EnumCreatureAttribute; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.ItemStack; + +// This one is for imbued swords. The only reason this is separate is that the way vanilla is written allows me to hook +// into the damage increase for melee weapons, meaning I don't have to use events - always handy! +public class EnchantmentMagicSword extends EnchantmentDamage implements Imbuement { + + public EnchantmentMagicSword() { + super(Enchantment.Rarity.COMMON, 0, EntityEquipmentSlot.MAINHAND); + // Setting this to null stops the book appearing in the creative inventory + this.type = null; + } + + @Override + public boolean canApply(ItemStack p_92089_1_){ + return false; + } + + /** + * Returns the maximum level that the enchantment can have. + */ + // Here, enchantment level is the damage multiplier of the spell used to apply the enchantment, i.e. with an + // non-sorcerer wand it is level 1, a basic sorcerer wand is level 2, and so on. Note that basic sorcerer wands can't + // cast the imbue weapon spell, so level 2 is actually for apprentice wands. + @Override + public int getMaxLevel() + { + return 4; + } + + // Returns the number by which the damage should be increased (or something) + @Override + public float calcDamageByCreature(int p_152376_1_, EnumCreatureAttribute p_152376_2_) + { + return (float)p_152376_1_ * 1.25F; + } + + @Override + public String getName() + { + return "enchantment." + this.getRegistryName(); + } + + @Override + public boolean isAllowedOnBooks(){ + return false; + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack) { + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/enchantment/EnchantmentTimed.java b/src/main/java/electroblob/wizardry/enchantment/EnchantmentTimed.java new file mode 100644 index 00000000..d30252d1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/enchantment/EnchantmentTimed.java @@ -0,0 +1,48 @@ +package electroblob.wizardry.enchantment; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.ItemStack; + +// This one is for everything other than imbued swords. +public class EnchantmentTimed extends Enchantment implements Imbuement { + + public EnchantmentTimed() { + // Setting enchantment type to null stops the book appearing in the creative inventory + super(Enchantment.Rarity.COMMON, null, new EntityEquipmentSlot[]{EntityEquipmentSlot.MAINHAND}); + } + + @Override + public boolean canApply(ItemStack p_92089_1_){ + return false; + } + + @Override + public String getName() + { + return "enchantment." + this.getRegistryName(); + } + + /** + * Returns the maximum level that the enchantment can have. + */ + // Here, enchantment level is the damage multiplier of the spell used to apply the enchantment, i.e. with an + // non-sorcerer wand it is level 1, an apprentice sorcerer wand is level 2, and so on. Note that basic sorcerer wands can't + // cast the imbue weapon spell, so level 2 is actually for apprentice wands. + @Override + public int getMaxLevel() + { + return 4; + } + + @Override + public boolean isAllowedOnBooks(){ + return false; + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack) { + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/enchantment/Imbuement.java b/src/main/java/electroblob/wizardry/enchantment/Imbuement.java new file mode 100644 index 00000000..4acf7f95 --- /dev/null +++ b/src/main/java/electroblob/wizardry/enchantment/Imbuement.java @@ -0,0 +1,11 @@ +package electroblob.wizardry.enchantment; + +/** Interface for temporary enchantments that last for a certain duration ('imbuements'). This interface allows + * {@link EnchantmentMagicSword} and {@link EnchantmentTimed} to both be treated as instances of a + * single type, rather than having to deal with each of them separately, + * which would be inefficient and cumbersome (the former of those classes cannot extend the latter because they both + * need to extend different subclasses of {@link net.minecraft.enchantment.Enchantment}). + * @since Wizardry 1.2 */ +public interface Imbuement { + +} diff --git a/src/main/java/electroblob/wizardry/entity/EntityArc.java b/src/main/java/electroblob/wizardry/entity/EntityArc.java new file mode 100644 index 00000000..dc68f0eb --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/EntityArc.java @@ -0,0 +1,73 @@ +package electroblob.wizardry.entity; + +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; + +public class EntityArc extends Entity implements IEntityAdditionalSpawnData { + + public int textureIndex = 0; + public double x1, y1, z1, x2, y2, z2; + // The number of ticks the arc lasts for before disappearing + public int lifetime = 3; + public double offsetX, offsetZ; + + public EntityArc(World par1World) { + super(par1World); + textureIndex = this.rand.nextInt(16); + this.ignoreFrustumCheck = true; + } + + public void setEndpointCoords(double x1, double y1, double z1, double x2, double y2, double z2){ + this.x1 = x1; + this.y1 = y1; + this.z1 = z1; + this.x2 = x2; + this.y2 = y2; + this.z2 = z2; + this.setPosition(x2, y2, z2); + } + + @Override + public void onUpdate(){ + if(this.ticksExisted >= lifetime){ + this.setDead(); + } + } + + protected void entityInit() + { + } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { + + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { + // Nothing needed here; arc is merely a graphic effect that only exists for a few ticks; as such there is no need to save it. + } + + @Override + public boolean isInRangeToRenderDist(double distance) { + return true; + } + + @Override + public void writeSpawnData(ByteBuf data) { + data.writeDouble(this.x1); + data.writeDouble(this.y1); + data.writeDouble(this.z1); + } + + @Override + public void readSpawnData(ByteBuf data) { + this.x1 = data.readDouble(); + this.y1 = data.readDouble(); + this.z1 = data.readDouble(); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/EntityMeteor.java b/src/main/java/electroblob/wizardry/entity/EntityMeteor.java new file mode 100644 index 00000000..fce647ce --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/EntityMeteor.java @@ -0,0 +1,127 @@ +package electroblob.wizardry.entity; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.item.EntityFallingBlock; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class EntityMeteor extends EntityFallingBlock { + + /** The entity blast multiplier. Only some projectiles cause a blast, which is why this isn't in EntityMagicProjectile. */ + public float blastMultiplier; + + public EntityMeteor(World world){ + super(world); + // Superconstructor doesn't call this. + this.setSize(0.98F, 0.98F); + } + + public EntityMeteor(World world, double x, double y, double z, float blastMultiplier){ + super(world, x, y, z, WizardryBlocks.meteor.getDefaultState()); + this.motionY = -1.0D; + this.setFire(200); + this.blastMultiplier = blastMultiplier; + } + + @Override + public double getYOffset() { + return this.height / 2.0F; + } + + @Override + public void onUpdate(){ + + if(this.ticksExisted % 16 == 1 && worldObj.isRemote){ + Wizardry.proxy.playMovingSound(this, WizardrySounds.SPELL_LOOP_FIRE, 3.0f, 1.0f, false); + } + + // You'd think the best way to do this would be to call super and do all the exploding stuff in fall() instead. + // However, for some reason, fallTile is null on the client side, causing an NPE in super.onUpdate() + + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + ++this.fallTime; + this.motionY -= 0.1d; //0.03999999910593033D; + this.moveEntity(this.motionX, this.motionY, this.motionZ); + this.motionX *= 0.9800000190734863D; + this.motionY *= 0.9800000190734863D; + this.motionZ *= 0.9800000190734863D; + + if(!this.worldObj.isRemote){ + + if(this.onGround){ + + this.motionX *= 0.699999988079071D; + this.motionZ *= 0.699999988079071D; + this.motionY *= -0.5D; + this.worldObj.createExplosion(this, this.posX, this.posY, this.posZ, 2.0f*blastMultiplier, true); + for(int i1=-3; i1<4; i1++){ + for(int j1=-3; j1<4; j1++){ + int y = WizardryUtilities.getNearestFloorLevelB(this.worldObj, new BlockPos(this.posX + i1, this.posY, this.posZ + j1), 7); + //System.out.println(y); + double dist = this.getDistance((int)this.posX + i1, y, (int)this.posZ + j1); + // Randomised with weighting so that the nearer the block the more likely it is to be set on fire. + if(y != -1 && rand.nextInt((int)dist*2 + 1) < 3 && dist < 4){ + this.worldObj.setBlockState(new BlockPos(this.posX + i1, y, this.posZ + j1), Blocks.FIRE.getDefaultState()); + } + } + } + this.setDead(); + } + } + } + + @Override + public void fall(float distance, float damageMultiplier){ + // Don't need to do anything here, the meteor should have already exploded. + } + + @SideOnly(Side.CLIENT) + @Override + public boolean canRenderOnFire(){ + return true; + } + + @Override + public IBlockState getBlock(){ + return WizardryBlocks.meteor.getDefaultState(); // For some reason the superclass version returns null on the client + } + + @SideOnly(Side.CLIENT) + @Override + public int getBrightnessForRender(float partialTicks){ + return 15728880; + } + + @Override + public float getBrightness(float partialTicks){ + return 1.0F; + } + + @Override + public boolean isInRangeToRenderDist(double distance){ + return true; + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + blastMultiplier = nbttagcompound.getFloat("blastMultiplier"); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + nbttagcompound.setFloat("blastMultiplier", blastMultiplier); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/EntityShield.java b/src/main/java/electroblob/wizardry/entity/EntityShield.java new file mode 100644 index 00000000..c884ea07 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/EntityShield.java @@ -0,0 +1,94 @@ +package electroblob.wizardry.entity; + +import java.lang.ref.WeakReference; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.registry.WizardrySounds; +import net.minecraft.entity.Entity; +import net.minecraft.entity.IProjectile; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.DamageSource; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.world.World; + +public class EntityShield extends Entity { + + public WeakReference player; + + public EntityShield(World world){ + super(world); + this.noClip = true; + this.width = 1.2f; + this.height = 1.4f; + } + + public EntityShield(World par1World, EntityPlayer player) { + super(par1World); + this.width = 1.2f; + this.height = 1.4f; + this.player = new WeakReference(player); + this.noClip = true; + this.setPositionAndRotation(player.posX + player.getLookVec().xCoord, player.posY + 1 + player.getLookVec().yCoord, player.posZ + player.getLookVec().zCoord, player.rotationYawHead, player.rotationPitch); + this.setEntityBoundingBox(new AxisAlignedBB(this.posX - 0.6f, this.posY - 0.7f, this.posZ - 0.6f, this.posX + 0.6f, this.posY + 0.7f, this.posZ + 0.6f)); + } + + @Override + public void onUpdate(){ + //System.out.println("Shield exists, ID: " + this.getUniqueID().toString()); + EntityPlayer entityplayer = player != null ? player.get() : null; + if(entityplayer != null){ + this.setPositionAndRotation(entityplayer.posX + entityplayer.getLookVec().xCoord*0.3, entityplayer.posY + 1 + entityplayer.getLookVec().yCoord*0.3, entityplayer.posZ + entityplayer.getLookVec().zCoord*0.3, entityplayer.rotationYawHead, entityplayer.rotationPitch); + if(!entityplayer.isHandActive() || entityplayer.getHeldItem(entityplayer.getActiveHand()) == null || !(entityplayer.getHeldItem(entityplayer.getActiveHand()).getItem() instanceof ItemWand)){ + WizardData.get(entityplayer).shield = null; + this.setDead(); + } + }else if(!worldObj.isRemote){ + this.setDead(); + } + } + + // Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow + // it to stick in blocks. + public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) + { + this.setPosition(par1, par3, par5); + this.setRotation(par7, par8); + } + + public boolean attackEntityFrom(DamageSource par1DamageSource, float par2) + { + if(par1DamageSource != null && par1DamageSource.getSourceOfDamage() instanceof IProjectile){ + par1DamageSource.getSourceOfDamage().playSound(WizardrySounds.SPELL_DEFLECTION, 0.3f, 1.3f); + } + super.attackEntityFrom(par1DamageSource, par2); + return false; + } + + public boolean canBeCollidedWith() + { + return !this.isDead; + } + + public AxisAlignedBB getCollisionBox(Entity par1Entity) + { + return par1Entity.getEntityBoundingBox(); + } + + @Override + protected void entityInit() { + + } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { + + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { + + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java b/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java new file mode 100644 index 00000000..ddee05da --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java @@ -0,0 +1,39 @@ +package electroblob.wizardry.entity.construct; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.projectile.EntityTippedArrow; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public class EntityArrowRain extends EntityMagicConstruct { + + public EntityArrowRain(World par1World) { + super(par1World); + this.height = 3.0f; + this.width = 5.0f; + } + + public EntityArrowRain(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) { + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.height = 3.0f; + this.width = 5.0f; + } + + public void onUpdate(){ + + super.onUpdate(); + + if(!this.worldObj.isRemote){ + EntityTippedArrow arrow = new EntityTippedArrow(worldObj, this.posX + rand.nextDouble()*6 - 3, this.posY + rand.nextDouble()*4 - 2, this.posZ + rand.nextDouble()*6 - 3); + arrow.motionX = Math.cos(Math.toRadians(this.rotationYaw + 90)); + arrow.motionY = -0.6; + arrow.motionZ = Math.sin(Math.toRadians(this.rotationYaw + 90)); + arrow.shootingEntity = this.getCaster(); + arrow.setDamage(7.0d*damageMultiplier); + arrow.setPotionEffect(new ItemStack(Items.ARROW)); + this.worldObj.spawnEntityInWorld(arrow); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java new file mode 100644 index 00000000..56f85762 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java @@ -0,0 +1,138 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.SoundEvents; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class EntityBlackHole extends EntityMagicConstruct { + + public int[] randomiser; + public int[] randomiser2; + + public EntityBlackHole(World world){ + super(world); + this.width = 6.0f; + this.height = 3.0f; + randomiser = new int[30]; + for(int i=0; i targets = WizardryUtilities.getEntitiesWithinRadius(6.0d, this.posX, this.posY, this.posZ, this.worldObj); + + if(!this.worldObj.isRemote){ + + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + // Sucks the target in + if(this.posX > target.posX && target.motionX < 1){ + target.motionX+=0.1; + }else if(this.posX < target.posX && target.motionX > -1){ + target.motionX-=0.1; + } + + if(this.posY > target.posY && target.motionY < 1){ + target.motionY+=0.1; + }else if(this.posY < target.posY && target.motionY > -1){ + target.motionY-=0.1; + } + + if(this.posZ > target.posZ && target.motionZ < 1){ + target.motionZ+=0.1; + }else if(this.posZ < target.posZ && target.motionZ > -1){ + target.motionZ-=0.1; + } + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + + if(this.getDistanceToEntity(target) <= 2){ + // Damages the target if it is close enough + if(this.getCaster() != null){ + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC), 2*damageMultiplier); + }else{ + target.attackEntityFrom(DamageSource.magic, 2*damageMultiplier); + } + } + } + } + } + } + + /** + * Checks using a Vec3dd to determine if this entity is within range of that vector to be rendered. Args: Vec3dD + */ + public boolean isInRangeToRenderVec3dD(Vec3d par1Vec3d) + { + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java new file mode 100644 index 00000000..342ad185 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java @@ -0,0 +1,68 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.world.World; + +public class EntityBlizzard extends EntityMagicConstruct { + + public EntityBlizzard(World par1World) { + super(par1World); + this.height = 1.0f; + this.width = 1.0f; + } + + public EntityBlizzard(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) { + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.height = 1.0f; + this.width = 1.0f; + } + + public void onUpdate(){ + + if(this.ticksExisted % 120 == 1){ + this.playSound(WizardrySounds.SPELL_LOOP_WIND, 1.0f, 1.0f); + } + + super.onUpdate(); + + if(!this.worldObj.isRemote){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(3.0d, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + if(this.getCaster() != null){ + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.FROST), 1*damageMultiplier); + }else{ + WizardryUtilities.attackEntityWithoutKnockback(target, DamageSource.magic, 1*damageMultiplier); + } + } + + // All entities are slowed, even the caster (except those immune to frost effects) + if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) + target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 20, 0)); + } + }else{ + // For some reason this number of particles now causes the game to lag significantly, despite it being fine + // in 1.7.10. I thought particles were supposed to be LESS laggy now... + for(int i=1; i<6; i++){ + float brightness = 0.5f + (rand.nextFloat()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.BLIZZARD, worldObj, this.posX, this.posY + rand.nextDouble()*3, this.posZ, 0, 0, 0, 100, brightness, brightness + 0.1f, 1.0f, false, rand.nextDouble() * 2.5d + 0.5d); + Wizardry.proxy.spawnParticle(WizardryParticleType.BLIZZARD, worldObj, this.posX, this.posY + rand.nextDouble()*3, this.posZ, 0, 0, 0, 100, 1.0f, 1.0f, 1.0f, false, rand.nextDouble() * 2.5d + 0.5d); + } + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java new file mode 100644 index 00000000..5ac8b2a7 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java @@ -0,0 +1,123 @@ +package electroblob.wizardry.entity.construct; + +import java.lang.ref.WeakReference; + +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.world.World; + +public class EntityBubble extends EntityMagicConstruct { + + public boolean isDarkOrb; + + private WeakReference rider; + + public EntityBubble(World world){ + super(world); + } + + public EntityBubble(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, boolean isDarkOrb, float damageMultiplier) { + super(world, x, y, z, caster, lifetime, damageMultiplier); + //this.setSize(0.1f, 0.1f); + this.isDarkOrb = isDarkOrb; + } + + @Override + public double getMountedYOffset() + { + return 0.1; + } + + @Override + public boolean shouldRiderSit(){ + return false; + } + + public void onUpdate(){ + + super.onUpdate(); + + // Synchronises the rider field + if((this.rider == null || this.rider.get() == null) && WizardryUtilities.getRider(this) instanceof EntityLivingBase + && !WizardryUtilities.getRider(this).isDead){ + this.rider = new WeakReference((EntityLivingBase) WizardryUtilities.getRider(this)); + } + + // Prevents dismounting + if(WizardryUtilities.getRider(this) == null && this.rider != null && this.rider.get() != null && !this.rider.get().isDead){ + this.rider.get().startRiding(this); + } + + // Stops the bubble bursting instantly. + if(this.ticksExisted < 1 && !isDarkOrb) ((EntityLivingBase)WizardryUtilities.getRider(this)).hurtTime = 0; + + this.moveEntity(0, 0.03, 0); + + if(isDarkOrb){ + + if(WizardryUtilities.getRider(this) != null && this.ticksExisted % 30 == 0){ + if(this.getCaster() != null){ + WizardryUtilities.getRider(this).attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC), 1*damageMultiplier); + }else{ + WizardryUtilities.getRider(this).attackEntityFrom(DamageSource.magic, 1*damageMultiplier); + } + } + + for(int i=0; i<5; i++){ + this.worldObj.spawnParticle(EnumParticleTypes.PORTAL, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height + 0.5d, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, (this.rand.nextDouble() - 0.5D) * 2.0D, -this.rand.nextDouble(), (this.rand.nextDouble() - 0.5D) * 2.0D); + } + if(lifetime - this.ticksExisted == 75){ + this.playSound(SoundEvents.BLOCK_PORTAL_TRIGGER, 1.5f, 1.0f); + }else if(this.ticksExisted % 100 == 1 && this.ticksExisted < 150){ + this.playSound(SoundEvents.BLOCK_PORTAL_AMBIENT, 1.5f, 1.0f); + } + } + + // Bubble bursts if the entity is hurt (see event handler) or killed, or if the bubble has existed for more than 10 seconds. + if(WizardryUtilities.getRider(this) == null && this.ticksExisted > 1){ + if(!this.isDarkOrb) this.playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f); + this.setDead(); + } + } + + @Override + public void despawn(){ + if(WizardryUtilities.getRider(this) != null){ + ((EntityLivingBase)WizardryUtilities.getRider(this)).dismountEntity(this); + } + if(!this.isDarkOrb) this.playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f); + super.despawn(); + } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { + super.readEntityFromNBT(nbttagcompound); + isDarkOrb = nbttagcompound.getBoolean("isDarkOrb"); + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { + super.writeEntityToNBT(nbttagcompound); + nbttagcompound.setBoolean("isDarkOrb", isDarkOrb); + } + + @Override + public void writeSpawnData(ByteBuf data) { + super.writeSpawnData(data); + data.writeBoolean(this.isDarkOrb); + } + + @Override + public void readSpawnData(ByteBuf data) { + super.readSpawnData(data); + this.isDarkOrb = data.readBoolean(); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java new file mode 100644 index 00000000..f8d33151 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java @@ -0,0 +1,78 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class EntityDecay extends EntityMagicConstruct { + + public int textureIndex = 0; + public static final int LIFETIME = 400; + + public EntityDecay(World par1World) { + super(par1World); + textureIndex = this.rand.nextInt(10); + this.height = 0.2f; + this.width = 2.0f; + } + + public EntityDecay(World par1World, double x, double y, double z, EntityLivingBase caster) { + super(par1World, x, y, z, caster, LIFETIME, 1); + textureIndex = this.rand.nextInt(10); + this.height = 0.2f; + this.width = 2.0f; + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(this.rand.nextInt(700) == 0 && this.ticksExisted+100 < LIFETIME) this.playSound(SoundEvents.BLOCK_LAVA_AMBIENT, 0.2F + rand.nextFloat() * 0.2F, 0.6F + rand.nextFloat() * 0.15F); + + if(!this.worldObj.isRemote){ + List targets = WizardryUtilities.getEntitiesWithinRadius(1.0d, this.posX, this.posY, this.posZ, this.worldObj); + for(EntityLivingBase target : targets){ + if(target != this.getCaster()){ + // If this check wasn't here the potion would be reapplied every tick and hence the entity would be damaged each tick. + // In this case, we do want particles to be shown. + if(!target.isPotionActive(WizardryPotions.decay)) target.addPotionEffect(new PotionEffect(WizardryPotions.decay, LIFETIME, 0)); + } + } + }else if(this.rand.nextInt(15) == 0){ + double radius = rand.nextDouble()*0.8; + double angle = rand.nextDouble()*Math.PI*2; + float brightness = rand.nextFloat()*0.4f; + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + radius*Math.cos(angle), this.posY, this.posZ + radius*Math.sin(angle), 0, 0, 0, 0, brightness, 0, brightness+0.1f); + } + } + + protected void entityInit(){} + + @Override + protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { + + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { + + } + + /** + * Checks using a Vec3dd to determine if this entity is within range of that vector to be rendered. Args: Vec3dD + */ + public boolean isInRangeToRenderVec3dD(Vec3d par1Vec3d) + { + return true; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java b/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java new file mode 100644 index 00000000..10d32231 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java @@ -0,0 +1,107 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityFallingBlock; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.MobEffects; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class EntityEarthquake extends EntityMagicConstruct { + + public EntityEarthquake(World world){ + super(world); + this.height = 1.0f; + this.width = 1.0f; + } + + public EntityEarthquake(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, + float damageMultiplier) { + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.height = 1.0f; + this.width = 1.0f; + } + + public void onUpdate(){ + + super.onUpdate(); + + if(!worldObj.isRemote){ + + double speed = 0.4; + + // The further the earthquake is going to spread, the finer the angle increments. + for(double angle=0; angle < 2*Math.PI; angle+=Math.PI/(lifetime*1.5)){ + + // Calculates coordinates for the block to be moved. The radius increases with time. The +1.5 is to leave + // blocks in the centre untouched. + int x = this.posX < 0 ? (int)(this.posX + ((this.ticksExisted*speed)+1.5)*Math.sin(angle) - 1) : (int)(this.posX + ((this.ticksExisted*speed)+1.5)*Math.sin(angle)); + int y = (int)(this.posY - 0.5); + int z = this.posZ < 0 ? (int)(this.posZ + ((this.ticksExisted*speed)+1.5)*Math.cos(angle) - 1) : (int)(this.posZ + ((this.ticksExisted*speed)+1.5)*Math.cos(angle)); + + BlockPos pos = new BlockPos(x, y, z); + + if(!WizardryUtilities.isBlockUnbreakable(worldObj, pos) && !worldObj.isAirBlock(pos) && worldObj.isBlockNormalCube(pos, false) + // Checks that the block above is not solid, since this causes the falling sand to vanish. + && !worldObj.isBlockNormalCube(pos.up(), false)){ + + // Falling blocks do the setting block to air themselves. + EntityFallingBlock fallingblock = new EntityFallingBlock(worldObj, x+0.5, y+0.5, z+0.5, worldObj.getBlockState(new BlockPos(x, y, z))); + fallingblock.motionY = 0.3; + worldObj.spawnEntityInWorld(fallingblock); + } + } + + List targets = WizardryUtilities.getEntitiesWithinRadius((this.ticksExisted*speed)+1.5, this.posX, this.posY, this.posZ, worldObj); + + // In this particular instance, the caster is completely unaffected because they will always be in the centre. + targets.remove(this.getCaster()); + + for(EntityLivingBase target : targets){ + + // Searches in a 1 wide ring. + if(this.getDistanceToEntity(target) > (this.ticksExisted*speed)+0.5 && target.posY < this.posY + 1 && target.posY > this.posY - 1){ + + // Knockback must be removed in this instance, or the target will fall into the floor. + double motionX = target.motionX; + double motionZ = target.motionZ; + + if(this.isValidTarget(target)){ + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), DamageType.BLAST), 10*this.damageMultiplier); + target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 400, 1)); + } + + // All targets are thrown, even those immune to the damage, so they don't fall into the ground. + target.motionX = motionX; + target.motionY = 0.8; // Throws target into the air. + target.motionZ = motionZ; + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + } + } + // TODO: Uncomment once 2.1.0 is released +// }else{ +// +// // Constant 15 blocks for now +// List targets = WizardryUtilities.getEntitiesWithinRadius(15, this.posX, this.posY, this.posZ, worldObj, EntityPlayer.class); +// +// float magnitude = 6f * ((float)(this.lifetime - this.ticksExisted))/(float)this.lifetime; +// +// // Makes the screen shake +// for(EntityLivingBase target : targets){ +// target.setAngles(0, this.ticksExisted % 4 < 2 ? magnitude : -magnitude); +// } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java new file mode 100644 index 00000000..e2055da5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java @@ -0,0 +1,67 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.DamageSource; +import net.minecraft.world.World; + +public class EntityFireRing extends EntityMagicConstruct { + + public EntityFireRing(World par1World) { + super(par1World); + this.height = 1.0f; + this.width = 5.0f; + } + + public EntityFireRing(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) { + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.height = 1.0f; + this.width = 5.0f; + } + + public void onUpdate(){ + + if(this.ticksExisted % 40 == 1){ + this.playSound(SoundEvents.BLOCK_FIRE_AMBIENT, 4.0f, 0.7f); + } + + super.onUpdate(); + + if(!this.worldObj.isRemote){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(2.5d, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + double velX = target.motionX; + double velY = target.motionY; + double velZ = target.motionZ; + + if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)){ + + target.setFire(10); + + if(this.getCaster() != null){ + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.FIRE), 1*damageMultiplier); + }else{ + target.attackEntityFrom(DamageSource.magic, 1*damageMultiplier); + } + } + + // Removes knockback + target.motionX = velX; + target.motionY = velY; + target.motionZ = velZ; + } + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java new file mode 100644 index 00000000..9913006e --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java @@ -0,0 +1,87 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.world.World; + +public class EntityFireSigil extends EntityMagicConstruct { + + public EntityFireSigil(World par1World) { + super(par1World); + this.height = 0.2f; + this.width = 2.0f; + } + + public EntityFireSigil(World par1World, double x, double y, double z, EntityLivingBase caster, float damageMultiplier) { + super(par1World, x, y, z, caster, -1, damageMultiplier); + this.height = 0.2f; + this.width = 2.0f; + } + + // Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow + // it to stick in blocks. + public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) + { + this.setPosition(par1, par3, par5); + this.setRotation(par7, par8); + } + + public void onUpdate(){ + + super.onUpdate(); + + if(!this.worldObj.isRemote){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(1.0d, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + double velX = target.motionX; + double velY = target.motionY; + double velZ = target.motionZ; + + target.attackEntityFrom(this.getCaster() != null ? MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), DamageType.FIRE) : DamageSource.magic, 6); + + // Removes knockback + target.motionX = velX; + target.motionY = velY; + target.motionZ = velZ; + + if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)) target.setFire(10); + + this.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + + // The trap is destroyed once triggered. + this.setDead(); + } + } + }else if(this.rand.nextInt(15) == 0){ + double radius = 0.5 + rand.nextDouble()*0.3; + double angle = rand.nextDouble()*Math.PI*2; + worldObj.spawnParticle(EnumParticleTypes.FLAME, this.posX + radius*Math.cos(angle), this.posY + 0.1, this.posZ + radius*Math.sin(angle), 0, 0, 0); + } + } + + @Override + protected void entityInit() { + + } + + /** + * Return whether this entity should be rendered as on fire. + */ + public boolean canRenderOnFire() + { + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java new file mode 100644 index 00000000..f0f817eb --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java @@ -0,0 +1,91 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.util.DamageSource; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.world.World; + +public class EntityForcefield extends EntityMagicConstruct { + + public EntityForcefield(World world) { + super(world); + this.height = 6; + this.width = 6; + this.setEntityBoundingBox(new AxisAlignedBB(this.posX - 3, this.posY - 3, this.posZ - 3, this.posX + 3, this.posY + 3, this.posZ + 3)); + } + + public EntityForcefield(World world, double x, double y, double z, EntityLivingBase caster, int lifetime) { + // y-3 because it needs to be centred on the given position + // Damage multiplier is 1 because forcefields do no damage! + super(world, x, y-3, z, caster, lifetime, 1.0f); + this.height = 6; + this.width = 6; + this.setEntityBoundingBox(new AxisAlignedBB(this.posX - 3, this.posY - 3, this.posZ - 3, this.posX + 3, this.posY + 3, this.posZ + 3)); + } + + public boolean canBeCollidedWith() + { + return !this.isDead; + } + + public AxisAlignedBB getCollisionBox(Entity par1Entity) + { + return par1Entity.getEntityBoundingBox(); + } + + public void onUpdate(){ + + super.onUpdate(); + + if(!this.worldObj.isRemote){ + List targets = WizardryUtilities.getEntitiesWithinRadius(3.5, this.posX, this.posY + 3, this.posZ, this.worldObj); + for(EntityLivingBase target : targets){ + if(this.isValidTarget(target)){ + double multiplier = (3.5 - target.getDistance(this.posX, this.posY+3, this.posZ))*0.1; + target.addVelocity((target.posX - this.posX)*multiplier, (target.posY - (this.posY + 3))*multiplier, (target.posZ - this.posZ)*multiplier); + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + } + } + }else{ + for(int i=1; i<40; i++){ + float brightness = 0.5f + (rand.nextFloat()*0.5f); + double radius = 3; + double yaw = rand.nextDouble()*Math.PI*2; + double pitch = (rand.nextDouble()-0.5)*Math.PI; + // Generates a spherical pattern of particles + Wizardry.proxy.spawnParticle(WizardryParticleType.BRIGHT_DUST, worldObj, this.posX + radius*Math.cos(yaw)*Math.cos(pitch), this.posY + 3 + radius*Math.sin(pitch), this.posZ + radius*Math.sin(yaw)*Math.cos(pitch), 0, 0, 0, 48 + this.rand.nextInt(12), brightness, brightness, 1.0f); + } + } + } + + public boolean attackEntityFrom(DamageSource source, float par2){ + + if(source != null && source.getSourceOfDamage() != null){ + // Now works for any source of damage. + source.getSourceOfDamage().playSound(WizardrySounds.SPELL_DEFLECTION, 0.3f, 1.3f); + } + super.attackEntityFrom(source, par2); + return false; + } + + /** + * Return whether this entity should be rendered as on fire. + */ + public boolean canRenderOnFire() + { + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java new file mode 100644 index 00000000..f2cb3ffe --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java @@ -0,0 +1,91 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.world.World; + +public class EntityFrostSigil extends EntityMagicConstruct { + + public EntityFrostSigil(World par1World) { + super(par1World); + this.height = 0.2f; + this.width = 2.0f; + } + + public EntityFrostSigil(World par1World, double x, double y, double z, EntityLivingBase caster, float damageMultiplier) { + super(par1World, x, y, z, caster, -1, damageMultiplier); + this.height = 0.2f; + this.width = 2.0f; + } + + // Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow + // it to stick in blocks. + public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) + { + this.setPosition(par1, par3, par5); + this.setRotation(par7, par8); + } + + public void onUpdate(){ + + super.onUpdate(); + + if(!this.worldObj.isRemote){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(1.0d, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + double velX = target.motionX; + double velY = target.motionY; + double velZ = target.motionZ; + + target.attackEntityFrom(this.getCaster() != null ? MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), DamageType.FROST) : DamageSource.magic, 8); + + // Removes knockback + target.motionX = velX; + target.motionY = velY; + target.motionZ = velZ; + + if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) + target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 200, 1)); + + this.playSound(WizardrySounds.SPELL_FREEZE, 1.0f, 1.0f); + + // The trap is destroyed once triggered. + this.setDead(); + } + } + }else if(this.rand.nextInt(15) == 0){ + double radius = 0.5 + rand.nextDouble()*0.3; + double angle = rand.nextDouble()*Math.PI*2; + Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, worldObj, this.posX + radius*Math.cos(angle), this.posY + 0.1, this.posZ + radius*Math.sin(angle), 0, 0, 0, 40 + rand.nextInt(10)); + } + } + + @Override + protected void entityInit() { + + } + + /** + * Return whether this entity should be rendered as on fire. + */ + public boolean canRenderOnFire() + { + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java new file mode 100644 index 00000000..6b627bdd --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java @@ -0,0 +1,37 @@ +package electroblob.wizardry.entity.construct; + +import electroblob.wizardry.entity.projectile.EntityIceShard; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.world.World; + +public class EntityHailstorm extends EntityMagicConstruct { + + public EntityHailstorm(World par1World) { + super(par1World); + this.height = 3.0f; + this.width = 5.0f; + } + + public EntityHailstorm(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) { + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.height = 3.0f; + this.width = 5.0f; + } + + public void onUpdate(){ + + super.onUpdate(); + + if(!this.worldObj.isRemote){ + //System.out.println(this.rotationYaw); + EntityIceShard iceshard = new EntityIceShard(worldObj, this.posX + rand.nextDouble()*6 - 3, this.posY + rand.nextDouble()*4 - 2, this.posZ + rand.nextDouble()*6 - 3); + iceshard.motionX = Math.cos(Math.toRadians(this.rotationYaw + 90)); + iceshard.motionY = -0.6; + iceshard.motionZ = Math.sin(Math.toRadians(this.rotationYaw + 90)); + iceshard.setShootingEntity(this.getCaster()); + iceshard.damageMultiplier = this.damageMultiplier; + this.worldObj.spawnEntityInWorld(iceshard); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java new file mode 100644 index 00000000..67950d41 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java @@ -0,0 +1,183 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.effect.EntityLightningBolt; +import net.minecraft.init.SoundEvents; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class EntityHammer extends EntityMagicConstruct { + + /** How long the hammer has been falling for. */ + public int fallTime; + + public EntityHammer(World par1World){ + super(par1World); + this.setSize(1.0f, 1.9F); + this.noClip = false; + } + + public EntityHammer(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier){ + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.setSize(1.0f, 1.9F); + this.motionX = 0.0D; + this.motionY = 0.0D; + this.motionZ = 0.0D; + this.noClip = false; + } + + @Override + public boolean isBurning(){ + return false; + } + + @Override + public boolean canBeCollidedWith(){ + return true; + } + + @Override + public AxisAlignedBB getCollisionBoundingBox(){ + return this.getEntityBoundingBox(); + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(this.ticksExisted % 20 == 1 && !this.onGround && worldObj.isRemote){ + // Though this sound does repeat, it stops when it hits the ground. + Wizardry.proxy.playMovingSound(this, WizardrySounds.SPELL_LOOP_LIGHTNING, 3.0f, 1.0f, false); + } + + if(this.worldObj.isRemote && this.ticksExisted % 3 == 0){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, this.posX - 0.5d + rand.nextDouble(), this.posY + 2*rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble(), 0, 0, 0, 3); + } + + if(!this.worldObj.isRemote){ + + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + ++this.fallTime; + this.motionY -= 0.03999999910593033D; + this.moveEntity(this.motionX, this.motionY, this.motionZ); + this.motionX *= 0.9800000190734863D; + this.motionY *= 0.9800000190734863D; + this.motionZ *= 0.9800000190734863D; + + if(this.onGround){ + + this.motionX *= 0.699999988079071D; + this.motionZ *= 0.699999988079071D; + this.motionY *= -0.5D; + + if(this.ticksExisted % 40 == 0){ + + double seekerRange = 10.0d; + + List targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX, this.posY+1, this.posZ, worldObj); + + // For this spell there is no limit to the amount of secondary targets! + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + if(!worldObj.isRemote){ + EntityArc arc = new EntityArc(worldObj); + arc.setEndpointCoords(this.posX, this.posY + this.height - 0.1, this.posZ, + target.posX, target.posY + target.height/2, target.posZ); + worldObj.spawnEntityInWorld(arc); + }else{ + for(int j=0;j<8;j++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, target.posX + worldObj.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + worldObj.rand.nextFloat()*2 - 1, target.posZ + worldObj.rand.nextFloat() - 0.5, 0, 0, 0, 3); + worldObj.spawnParticle(EnumParticleTypes.SMOKE_LARGE, target.posX + rand.nextFloat(), target.getEntityBoundingBox().minY + target.height/2 + rand.nextFloat(), target.posZ + rand.nextFloat(), 0, 0, 0); + } + } + + target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, rand.nextFloat() * 0.4F + 1.5F); + + if(this.getCaster() != null){ + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.SHOCK), 6*damageMultiplier); + WizardryUtilities.applyStandardKnockback(this, target); + }else{ + target.attackEntityFrom(DamageSource.magic, 6*damageMultiplier); + } + } + } + } + } + } + } + + @Override + public void despawn(){ + + this.playSound(SoundEvents.ENTITY_GENERIC_EXPLODE, 1.0F, 1.0f); + + if(this.worldObj.isRemote){ + this.worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); + } + + super.despawn(); + } + + @Override + public void fall(float distance, float damageMultiplier) { + + if(worldObj.isRemote){ + for(int i=0; i<40; i++){ + double particleX = this.posX - 1.0d + 2*rand.nextDouble(); + double particleZ = this.posZ - 1.0d + 2*rand.nextDouble(); + // Roundabout way of getting a block instance for the block the hammer is standing on (if any). + IBlockState block = worldObj.getBlockState(new BlockPos(this.posX, this.posY-2, this.posZ)); + + if(block != null){ + worldObj.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, this.posY, particleZ, + particleX - this.posX, 0, particleZ - this.posZ, Block.getStateId(block)); + } + } + }else{ + // Just to check the hammer has actually fallen from the sky, rather than the block under it being broken. + if(this.fallDistance > 10){ + EntityLightningBolt entitylightning = new EntityLightningBolt(worldObj, this.posX, this.posY, this.posZ, false); + worldObj.addWeatherEffect(entitylightning); + } + } + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound) + { + super.writeEntityToNBT(nbttagcompound); + nbttagcompound.setByte("Time", (byte)this.fallTime); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound) + { + super.readEntityFromNBT(nbttagcompound); + this.fallTime = nbttagcompound.getByte("Time") & 255; + } + + @Override + public boolean isInRangeToRenderDist(double distance) { + return true; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java new file mode 100644 index 00000000..34a96dd8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java @@ -0,0 +1,85 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.DamageSource; +import net.minecraft.world.World; + +public class EntityHealAura extends EntityMagicConstruct { + + public EntityHealAura(World world) { + super(world); + this.height = 1.0f; + this.width = 5.0f; + } + + public EntityHealAura(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) { + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.height = 1.0f; + this.width = 5.0f; + } + + public void onUpdate(){ + + if(this.ticksExisted % 25 == 1){ + this.playSound(WizardrySounds.SPELL_LOOP_SPARKLE, 0.1f, 1.0f); + } + + super.onUpdate(); + + if(!this.worldObj.isRemote){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(2.5d, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + if(target.isEntityUndead()){ + + double velX = target.motionX; + double velY = target.motionY; + double velZ = target.motionZ; + + if(this.getCaster() != null){ + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.RADIANT), 1*damageMultiplier); + }else{ + target.attackEntityFrom(DamageSource.magic, 1*damageMultiplier); + } + + // Removes knockback + target.motionX = velX; + target.motionY = velY; + target.motionZ = velZ; + } + + }else if(target.getHealth() < target.getMaxHealth() && this.ticksExisted % 5 == 0){ + target.heal(1*damageMultiplier); + } + } + }else{ + for(int i=1; i<3; i++){ + float brightness = 0.5f + (rand.nextFloat()*0.5f); + double radius = rand.nextDouble()*2.0; + double angle = rand.nextDouble()*Math.PI*2; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX + radius*Math.cos(angle), this.posY, this.posZ + radius*Math.sin(angle), 0, 0.05f, 0, 48 + this.rand.nextInt(12), 1.0f, 1.0f, brightness); + } + } + } + + /** + * Return whether this entity should be rendered as on fire. + */ + public boolean canRenderOnFire() + { + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java b/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java new file mode 100644 index 00000000..b314a2cf --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java @@ -0,0 +1,50 @@ +package electroblob.wizardry.entity.construct; + +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.potion.PotionEffect; +import net.minecraft.world.World; + +public class EntityIceSpike extends EntityMagicConstruct { + + public EntityIceSpike(World world) { + super(world); + this.setSize(0.5f, 1.0f); + } + + public EntityIceSpike(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier){ + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.setSize(0.5f, 1.0f); + } + + public void onUpdate(){ + + if(lifetime - this.ticksExisted < 15){ + this.motionY = -0.01*(this.ticksExisted-(lifetime-15)); + }else if(lifetime - this.ticksExisted < 25){ + this.motionY = 0; + }else if(lifetime - this.ticksExisted < 28){ + this.motionY = 0.25; + } + + this.moveEntity(this.motionX, this.motionY, this.motionZ); + + if(lifetime - this.ticksExisted == 30) this.playSound(WizardrySounds.SPELL_ICE, 1, 2); + + if(!this.worldObj.isRemote){ + for(Object entity : this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.getEntityBoundingBox())){ + if(entity instanceof EntityLivingBase && this.isValidTarget((EntityLivingBase)entity)){ + // Potion effect only gets added if the damage succeeded. + if(((EntityLivingBase)entity).attackEntityFrom(MagicDamage.causeDirectMagicDamage(this.getCaster(), DamageType.FROST), 5*this.damageMultiplier)) + ((EntityLivingBase)entity).addPotionEffect(new PotionEffect(WizardryPotions.frost, 100, 0)); + } + } + } + + super.onUpdate(); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java new file mode 100644 index 00000000..59653c0b --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java @@ -0,0 +1,26 @@ +package electroblob.wizardry.entity.construct; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.world.World; + +public class EntityLightningPulse extends EntityMagicConstruct { + + public EntityLightningPulse(World world) { + super(world); + this.setSize(6, 0.2f); + } + + public EntityLightningPulse(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) { + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.setSize(6, 0.2f); + } + + /** + * Return whether this entity should be rendered as on fire. + */ + public boolean canRenderOnFire() + { + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java new file mode 100644 index 00000000..8ecb646d --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java @@ -0,0 +1,125 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.world.World; + +public class EntityLightningSigil extends EntityMagicConstruct { + + public EntityLightningSigil(World par1World) { + super(par1World); + this.height = 0.2f; + this.width = 2.0f; + } + + public EntityLightningSigil(World par1World, double x, double y, double z, EntityLivingBase caster, float damageMultiplier) { + super(par1World, x, y, z, caster, -1, damageMultiplier); + this.height = 0.2f; + this.width = 2.0f; + } + + // Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow + // it to stick in blocks. + public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) + { + this.setPosition(par1, par3, par5); + this.setRotation(par7, par8); + } + + public void onUpdate(){ + + super.onUpdate(); + + if(this.ticksExisted > 600 && this.getCaster() == null && !this.worldObj.isRemote){ + this.setDead(); + } + + //if(!this.worldObj.isRemote){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(1.0d, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + double velX = target.motionX; + double velY = target.motionY; + double velZ = target.motionZ; + + // Only works if target is actually damaged to account for hurtResistantTime + if(target.attackEntityFrom(getCaster() != null ? MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.SHOCK) : DamageSource.magic, 6)){ + + // Removes knockback + target.motionX = velX; + target.motionY = velY; + target.motionZ = velZ; + + this.playSound(WizardrySounds.SPELL_SPARK, 1.0f, 1.0f); + + // Secondary chaining effect + double seekerRange = 5.0d; + + List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, target.posX, target.posY + target.height/2, target.posZ, worldObj); + + for(int j=0;j + * When extending this class, override both constructors. Generally speaking, subclasses of this class are areas + * of effect which deal damage or apply effects over time. + * @since Wizardry 1.0 + */ +public abstract class EntityMagicConstruct extends Entity implements IEntityAdditionalSpawnData { + + /** The entity that created this construct */ + private WeakReference caster; + + /** The UUID of the caster. Note that this is only for loading purposes; during normal updates + * the actual entity instance is stored (so that getEntityByUUID is not called constantly), + * so this will not always be synced (this is why it is private). */ + private UUID casterUUID; + + /** The time in ticks this magical construct lasts for; defaults to 600 (30 seconds). If this is -1 the construct + * doesn't despawn. */ + public int lifetime = 600; + + /** The damage multiplier for this construct, determined by the wand with which it was cast. */ + public float damageMultiplier = 1.0f; + + public EntityMagicConstruct(World par1World) { + super(par1World); + this.height = 1.0f; + this.width = 1.0f; + this.noClip = true; + } + + public EntityMagicConstruct(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) { + super(world); + this.height = 1.0f; + this.width = 1.0f; + this.setPosition(x, y, z); + this.caster = new WeakReference(caster); + this.noClip = true; + this.lifetime = lifetime; + this.damageMultiplier = damageMultiplier; + } + + // Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow + // it to stick in blocks. + @Override + public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, int posRotationIncrements, boolean teleport) + { + this.setPosition(x, y, z); + this.setRotation(yaw, pitch); + } + + public void onUpdate(){ + + if(this.getCaster() == null && this.casterUUID != null){ + Entity entity = WizardryUtilities.getEntityByUUID(worldObj, casterUUID); + if(entity instanceof EntityLivingBase){ + this.caster = new WeakReference((EntityLivingBase)entity); + } + } + + if(this.ticksExisted > lifetime && lifetime != -1){ + this.despawn(); + } + + super.onUpdate(); + + } + + /** + * Defaults to just setDead() in EntityMagicConstruct, but is provided to allow subclasses to override this + * e.g. bubble uses it to dismount the entity inside it and play the 'pop' sound before calling super(). You + * should always call super() when overriding this method, in case it changes. There is no need, therefore, to + * call setDead() when overriding. + */ + public void despawn(){ + this.setDead(); + } + + @Override + protected void entityInit() { + + } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbttagcompound){ + casterUUID = nbttagcompound.getUniqueId("casterUUID"); + lifetime = nbttagcompound.getInteger("lifetime"); + damageMultiplier = nbttagcompound.getFloat("damageMultiplier"); + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbttagcompound){ + if(this.getCaster() != null){ + nbttagcompound.setUniqueId("casterUUID", this.getCaster().getUniqueID()); + } + nbttagcompound.setInteger("lifetime", lifetime); + nbttagcompound.setFloat("damageMultiplier", damageMultiplier); + } + + @Override + public void writeSpawnData(ByteBuf data){ + data.writeInt(lifetime); + } + + @Override + public void readSpawnData(ByteBuf data){ + lifetime = data.readInt(); + } + + /** + * Returns the EntityLivingBase that created this construct, or null if it no longer exists. Cases where the + * entity may no longer exist are: entity died or was deleted, mob despawned, player logged out, entity teleported + * to another dimension, or this construct simply had no caster in the first place. + */ + public EntityLivingBase getCaster() { + return caster == null ? null : caster.get(); + } + + /** + * Shorthand for {@link WizardryUtilities#isValidTarget(Entity, Entity)}, with the owner of this construct as the + * attacker. Also allows subclasses to override it if they wish to do so. + */ + public boolean isValidTarget(Entity target){ + return WizardryUtilities.isValidTarget(this.getCaster(), target); + } + + @Override + public boolean canRenderOnFire() + { + return false; + } + + @Override + public boolean isPushedByWater() { + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java new file mode 100644 index 00000000..2e1625a9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java @@ -0,0 +1,184 @@ +package electroblob.wizardry.entity.construct; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.passive.EntityPig; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.util.DamageSource; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class EntityTornado extends EntityMagicConstruct { + + private double velX, velZ; + + public EntityTornado(World world) { + super(world); + this.height = 8.0f; + this.width = 5.0f; + this.isImmuneToFire = false; + } + + public EntityTornado(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, double velX, double velZ, float damageMultiplier) { + super(world, x, y, z, caster, lifetime, damageMultiplier); + this.height = 8.0f; + this.width = 5.0f; + this.velX = velX; + this.velZ = velZ; + this.isImmuneToFire = false; + } + + public void onUpdate(){ + + super.onUpdate(); + + if(this.ticksExisted % 120 == 1 && worldObj.isRemote){ + // Repeat is false so that the sound fades out when the tornado does rather than stopping suddenly + Wizardry.proxy.playMovingSound(this, WizardrySounds.SPELL_LOOP_WIND, 1.0f, 1.0f, false); + } + + this.moveEntity(velX, motionY, velZ); + + BlockPos pos = new BlockPos(this); + int y = WizardryUtilities.getNearestFloorLevelC(worldObj, pos.up(3), 5); + pos = new BlockPos(pos.getX(), y, pos.getZ()); + + if(this.worldObj.getBlockState(pos).getMaterial() == Material.LAVA){ + // Fire tornado! + this.setFire(5); + } + + if(!this.worldObj.isRemote){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(4.0d, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + double velY = target.motionY; + + double dx = this.posX-target.posX > 0? 0.5 - (this.posX-target.posX)/8 : -0.5 - (this.posX-target.posX)/8; + double dz = this.posZ-target.posZ > 0? 0.5 - (this.posZ-target.posZ)/8 : -0.5 - (this.posZ-target.posZ)/8; + + if(this.isBurning()){ + target.setFire(4); + } + + if(this.getCaster() != null){ + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC), 1*damageMultiplier); + }else{ + target.attackEntityFrom(DamageSource.magic, 1*damageMultiplier); + } + + target.motionX = dx; + target.motionY = velY+0.2; + target.motionZ = dz; + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + + // The 'Not Again...' achievement + if(target instanceof EntityPig && WizardryUtilities.getRider(target) instanceof EntityPlayer){ + ((EntityPlayer)WizardryUtilities.getRider(target)).addStat(WizardryAchievements.pig_tornado); + } + } + } + }else{ + for(int i=1; i<10; i++){ + + double yPos = rand.nextDouble()*8; + + int blockX = (int)this.posX - 2 + this.rand.nextInt(4); + int blockZ = (int)this.posZ - 2 + this.rand.nextInt(4); + + BlockPos pos1 = new BlockPos(blockX, this.posY+3, blockZ); + + int blockY = WizardryUtilities.getNearestFloorLevelC(worldObj, pos1, 5) - 1; + + pos1 = new BlockPos(pos1.getX(), blockY, pos1.getZ()); + + IBlockState block = this.worldObj.getBlockState(pos1); + + // If the block it found was air or something it can't pick up, it makes a best guess based on the biome. + if(!canTornadoPickUpBitsOf(block)){ + block = worldObj.getBiome(pos1).topBlock; + } + + Wizardry.proxy.spawnTornadoParticle(worldObj, this.posX, this.posY + yPos, this.posZ, this.velX, this.velZ, yPos/3 + 0.5d, 100, block, pos1); + Wizardry.proxy.spawnTornadoParticle(worldObj, this.posX, this.posY + yPos, this.posZ, this.velX, this.velZ, yPos/3 + 0.5d, 100, block, pos1); + + // Sometimes spawns leaf particles if the block is leaves + if(block.getMaterial() == Material.LEAVES && this.rand.nextInt(3) == 0){ + double yPos1 = rand.nextDouble()*8; + Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, worldObj, this.posX + (rand.nextDouble()*2-1)*(yPos1/3 + 0.5d), this.posY + yPos1, this.posZ + (rand.nextDouble()*2-1)*(yPos1/3 + 0.5d), 0, -0.05, 0, 40 + rand.nextInt(10)); + } + + // Sometimes spawns snow particles if the block is snow + if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW && this.rand.nextInt(3) == 0){ + double yPos1 = rand.nextDouble()*8; + Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, worldObj, this.posX + (rand.nextDouble()*2-1)*(yPos1/3 + 0.5d), this.posY + yPos1, this.posZ + (rand.nextDouble()*2-1)*(yPos1/3 + 0.5d), 0, -0.02, 0, 40 + rand.nextInt(10)); + } + } + } + } + + private static boolean canTornadoPickUpBitsOf(IBlockState block){ + Material material = block.getMaterial(); + return material == Material.CRAFTED_SNOW + || material == Material.GROUND + || material == Material.GRASS + || material == Material.LAVA + || material == Material.SAND + || material == Material.SNOW + || material == Material.WATER + || material == Material.PLANTS + || material == Material.LEAVES + || material == Material.VINE; + } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { + super.readEntityFromNBT(nbttagcompound); + velX = nbttagcompound.getDouble("velX"); + velZ = nbttagcompound.getDouble("velZ"); + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { + super.writeEntityToNBT(nbttagcompound); + nbttagcompound.setDouble("velX", velX); + nbttagcompound.setDouble("velZ", velZ); + } + + @Override + public void writeSpawnData(ByteBuf data) { + super.writeSpawnData(data); + data.writeDouble(velX); + data.writeDouble(velZ); + } + + @Override + public void readSpawnData(ByteBuf data) { + super.readSpawnData(data); + this.velX = data.readDouble(); + this.velZ = data.readDouble(); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java new file mode 100644 index 00000000..07222f34 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java @@ -0,0 +1,211 @@ +package electroblob.wizardry.entity.living; + +import java.util.ArrayList; +import java.util.List; + +import electroblob.wizardry.packet.PacketNPCCastSpell; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.util.EnumHand; +import net.minecraftforge.fml.common.network.NetworkRegistry.TargetPoint; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +/** Entity AI class for use by instances of {@link ISpellCaster}. This deals with pathing, the spell casting itself + * and the attack cooldown. Also provides an automatic implementation of continuous spell casting using the methods + * specified in {@code ISpellCaster}; all the entity class needs to do is implement those methods. */ +public class EntityAIAttackSpell extends EntityAIBase { + + /** The entity the AI instance has been applied to. */ + private final EntityLiving attacker; + /** The entity the AI instance has been applied to, but as an ISpellCaster. */ + private final ISpellCaster caster; + /** The tagret to be attacked. */ + private EntityLivingBase target; + /** Decremented each tick while greater than 0. When a spell is cast, this is set to that spell's cooldown plus + * the base cooldown. */ + private int cooldown; + /** The number of ticks between the entity finding a new target and when it first starts attacking, and also the + * amount that is added to the spell's cooldown between casting spells. */ + private final int baseCooldown; + /** Decremented each tick while greater than 0. When a continuous spell is first cast, this is set to + * the value of {@link EntityAIAttackSpell#continuousSpellDuration}. */ + // I think that in this case this is only necessary on the server side. If any inconsistent behaviour + // occurs, look into syncing this as well. + private int continuousSpellTimer; + /** The number of ticks that continuous spells will be cast for before cooling down. */ + private final int continuousSpellDuration; + /** The speed that the entity should move when attacking. Only used when passed into the navigator. */ + private final double speed; + private int seeTime; + private final float maxAttackDistance; + + /** + * Creates a new spell attack AI with the given parameters. + * @param attacker The entity that that uses this AI. + * @param speed The speed that the entity should move when attacking. Only used when passed into the navigator. + * @param maxDistance The maximum distance the entity should be from its target. + * @param baseCooldown The number of ticks between the entity finding a new target and when it first starts attacking, + * and also the amount that is added to the cooldown of the spell that has just been cast. + * @param continuousSpellDuration The number of ticks that continuous spells will be cast for before cooling down. + */ + public EntityAIAttackSpell(ISpellCaster attacker, double speed, float maxDistance, int baseCooldown, int continuousSpellDuration){ + + this.cooldown = -1; + + if(!(attacker instanceof EntityLiving)){ + throw new IllegalArgumentException("Tried to create an EntityAICastSpell for an entity that isn't an EntityLiving"); + }else{ + this.caster = attacker; + this.attacker = (EntityLiving)attacker; + this.baseCooldown = baseCooldown; + this.continuousSpellDuration = continuousSpellDuration; + this.speed = speed; + this.maxAttackDistance = maxDistance * maxDistance; + this.setMutexBits(3); + } + } + + @Override + public boolean shouldExecute(){ + + EntityLivingBase entitylivingbase = this.attacker.getAttackTarget(); + + if(entitylivingbase == null){ + return false; + }else{ + this.target = entitylivingbase; + return true; + } + } + + @Override + public boolean continueExecuting(){ + return this.shouldExecute() || !this.attacker.getNavigator().noPath(); + } + + @Override + public void resetTask(){ + this.target = null; + this.seeTime = 0; + this.cooldown = -1; + this.setContinuousSpellAndNotify(Spells.none, new SpellModifiers()); + this.continuousSpellTimer = 0; + } + + private void setContinuousSpellAndNotify(Spell spell, SpellModifiers modifiers){ + caster.setContinuousSpell(spell); + WizardryPacketHandler.net.sendToAllAround(new PacketNPCCastSpell.Message(attacker.getEntityId(), + target == null ? -1 : target.getEntityId(), EnumHand.MAIN_HAND, spell.id(), modifiers), + // Particles are usually only visible from 16 blocks away, so 128 is more than far enough. + new TargetPoint(attacker.dimension, attacker.posX, attacker.posY, attacker.posZ, 128)); + } + + @Override + public void updateTask(){ + + // Only executed server side. + + double distanceSq = this.attacker.getDistanceSq(this.target.posX, this.target.getEntityBoundingBox().minY, this.target.posZ); + boolean targetIsVisible = this.attacker.getEntitySenses().canSee(this.target); + + if(targetIsVisible){ + ++this.seeTime; + }else{ + this.seeTime = 0; + } + + if(distanceSq <= (double)this.maxAttackDistance && this.seeTime >= 20){ + this.attacker.getNavigator().clearPathEntity(); + }else{ + this.attacker.getNavigator().tryMoveToEntityLiving(this.target, this.speed); + } + + this.attacker.getLookHelper().setLookPositionWithEntity(this.target, 30.0F, 30.0F); + + if(this.continuousSpellTimer > 0){ + + this.continuousSpellTimer--; + + if(distanceSq > (double)this.maxAttackDistance || !targetIsVisible + || !caster.getContinuousSpell().cast(attacker.worldObj, attacker, EnumHand.MAIN_HAND, + this.continuousSpellDuration - this.continuousSpellTimer, target, caster.getModifiers()) + || this.continuousSpellTimer == 0){ + // If the spell no longer succeeds, the target goes out of range or sight, or the time has elapsed, + // reset the continuous spell timer and start the cooldown. + this.continuousSpellTimer = 0; + setContinuousSpellAndNotify(Spells.none, new SpellModifiers()); + this.cooldown = this.baseCooldown; + return; + } + + }else if(--this.cooldown == 0){ + + if(distanceSq > (double)this.maxAttackDistance || !targetIsVisible){ + return; + } + + if(!attacker.isPotionActive(WizardryPotions.arcane_jammer)){ + + double dx = target.posX - attacker.posX; + double dz = target.posZ - attacker.posZ; + + List spells = new ArrayList(caster.getSpells()); + + if(spells.size() > 0){ + + if(!attacker.worldObj.isRemote){ + + // New way of choosing a spell; keeps trying until one works or all have been tried + + Spell spell; + + while(!spells.isEmpty()){ + + spell = spells.get(attacker.worldObj.rand.nextInt(spells.size())); + + SpellModifiers modifiers = caster.getModifiers(); + + if(spell != null && spell.cast(attacker.worldObj, attacker, EnumHand.MAIN_HAND, 0, target, modifiers)){ + + if(spell.isContinuous){ + // -1 because the spell has been cast once already! + this.continuousSpellTimer = this.continuousSpellDuration - 1; + setContinuousSpellAndNotify(spell, modifiers); + + }else{ + // For now, the cooldown is just added to the constant base cooldown. I think this + // is a reasonable way of doing things; it's certainly better than before. + this.cooldown = this.baseCooldown + spell.cooldown; + + if(spell.doesSpellRequirePacket()){ + // Sends a packet to all players in dimension to tell them to spawn particles. + IMessage msg = new PacketNPCCastSpell.Message(attacker.getEntityId(), + target.getEntityId(), EnumHand.MAIN_HAND, spell.id(), modifiers); + WizardryPacketHandler.net.sendToDimension(msg, attacker.worldObj.provider.getDimension()); + } + } + + attacker.rotationYaw = (float)(Math.atan2(dz, dx) * 180.0D / Math.PI) - 90.0F; + + return; + + }else{ + spells.remove(spell); + } + } + } + } + } + + }else if(this.cooldown < 0){ + // This should only be reached when the entity first starts attacking. Stops it attacking instantly. + this.cooldown = this.baseCooldown; + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityAISelectSpell.java b/src/main/java/electroblob/wizardry/entity/living/EntityAISelectSpell.java new file mode 100644 index 00000000..286dc93c --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityAISelectSpell.java @@ -0,0 +1,14 @@ +package electroblob.wizardry.entity.living; + +import net.minecraft.entity.ai.EntityAIBase; + +public class EntityAISelectSpell extends EntityAIBase { + + // TODO: Write this class + + @Override + public boolean shouldExecute(){ + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java new file mode 100644 index 00000000..473f30b7 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java @@ -0,0 +1,160 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; +import java.util.UUID; + +import electroblob.wizardry.Wizardry; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.monster.EntityBlaze; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class EntityBlazeMinion extends EntityBlaze implements ISummonedCreature { + + // Field implementations + private int lifetime = 600; + private WeakReference casterReference; + private UUID casterUUID; + + // Setter + getter implementations + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID() { return casterUUID; } + @Override public void setCasterUUID(UUID uuid) { this.casterUUID = uuid; } + + /** + * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't + * matter because the client side entity immediately gets the lifetime value copied over to it by this class + * anyway. When extending this class, you must override this constructor or Minecraft won't like it, but there's + * no need to do anything inside it other than call super(). + */ + public EntityBlazeMinion(World world){ + super(world); + this.experienceValue = 0; + } + + /** + * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when + * extending this class (be sure to call super()) so that AI and other things can be added. + */ + public EntityBlazeMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world); + this.setPosition(x, y, z); + this.casterReference = new WeakReference(caster); + this.experienceValue = 0; + this.lifetime = lifetime; + } + + // EntityBlaze overrides + + // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its + // targeting system with one that targets hostile mobs and takes the ADS into account. + @Override + protected void initEntityAI() + { + super.initEntityAI(); + this.targetTasks.taskEntries.clear(); + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.getTargetSelector())); + } + + // Implementations + + @Override + public void setRevengeTarget(EntityLivingBase entity){ + if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity); + } + + @Override + public void onUpdate(){ + super.onUpdate(); + this.updateDelegate(); + } + + @Override + public void onSpawn(){ + this.spawnParticleEffect(); + } + + @Override + public void onDespawn(){ + this.spawnParticleEffect(); + } + + /** Normally this would be private, but since this class has subclasses with different spawn/despawn particle + * effects, it makes sense to have them override this rather than both onSpawn() and onDespawn(). */ + protected void spawnParticleEffect(){ + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + this.worldObj.spawnParticle(EnumParticleTypes.FLAME, this.posX + this.rand.nextFloat(), this.posY + 1 + this.rand.nextFloat(), this.posZ + this.rand.nextFloat(), 0, 0, 0); + } + } + } + + @Override + public boolean hasParticleEffect() { + return false; + } + + @Override + protected boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack) { + // In this case, the delegate method determines whether super is called. + // Rather handily, we can make use of Java's 'stop as soon as you find true' method of evaluating OR statements. + return this.interactDelegate(player, hand, stack) || super.processInteract(player, hand, stack); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + // Recommended overrides + + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + // This vanilla method has nothing to do with the custom despawn() method. + @Override protected boolean canDespawn(){ return false; } + + @Override + public boolean canAttackClass(Class entityType){ + return true; + } + + @Override + public ITextComponent getDisplayName(){ + if(getCaster() != null){ + return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java new file mode 100644 index 00000000..f4d9a423 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java @@ -0,0 +1,107 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryParticleType; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.EntityAILookIdle; +import net.minecraft.entity.ai.EntityAISwimming; +import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.DamageSource; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.world.World; + +public class EntityDecoy extends EntitySummonedCreature { + + public EntityDecoy(World world){ + super(world); + } + + public EntityDecoy(World world, double x, double y, double z, EntityLivingBase caster, int lifetime) { + super(world, x, y, z, caster, lifetime); + this.setAlwaysRenderNameTag(caster instanceof EntityPlayer); + } + + @Override + protected void initEntityAI() { + // Decoys just wander around aimlessly, watching anything living. + this.tasks.addTask(0, new EntityAISwimming(this)); + this.tasks.addTask(1, new EntityAIWander(this, 1.0D)); + this.tasks.addTask(2, new EntityAIWatchClosest(this, EntityLivingBase.class, 6.0F)); + this.tasks.addTask(3, new EntityAILookIdle(this)); + } + + @Override + public void onDespawn(){ + super.onDespawn(); + for(int i=0; i<20; i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, worldObj, this.posX + (this.rand.nextDouble()-0.5)*this.width, + this.getEntityBoundingBox().minY + this.rand.nextDouble()*this.height, this.posZ + (this.rand.nextDouble()-0.5)*this.width, + 0, 0, 0, 40, 0.2f, 1.0f, 0.8f); + } + } + + @Override + public boolean isEntityInvulnerable(DamageSource source){ + return true; + } + + @Override + public boolean isSneaking(){ + return false; + } + + @Override + public void onUpdate() { + super.onUpdate(); + if(this.getCaster() == null || this.getCaster().isDead){ + this.setDead(); + this.onDespawn(); + } + } + + @Override + protected void applyEntityAttributes() + { + super.applyEntityAttributes(); + this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.25D); + } + + @Override + public ITextComponent getDisplayName(){ + if(getCaster() instanceof EntityPlayer){ + return this.getCaster().getDisplayName(); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + return getCaster() instanceof EntityPlayer; + } + + @Override + public boolean hasRangedAttack() { + return false; + } + + @Override + public void writeSpawnData(ByteBuf data){ + super.writeSpawnData(data); + if(this.getCaster() != null) data.writeInt(this.getCaster().getEntityId()); + } + + @Override + public void readSpawnData(ByteBuf data){ + super.readSpawnData(data); + if(!data.isReadable()) return; + this.setCasterReference(new WeakReference((EntityLivingBase)this.worldObj.getEntityByID(data.readInt()))); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java new file mode 100644 index 00000000..3e10cd47 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java @@ -0,0 +1,364 @@ +package electroblob.wizardry.entity.living; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import com.google.common.base.Predicate; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.ai.EntityAIOpenDoor; +import net.minecraft.entity.ai.EntityAIRestrictOpenDoor; +import net.minecraft.entity.ai.EntityAISwimming; +import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.entity.ai.EntityAIWatchClosest2; +import net.minecraft.entity.monster.EntityMob; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagInt; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.pathfinding.PathNavigateGround; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants.NBT; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; + +public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData { + + private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell(this, 0.5D, 14.0F, 30, 50); + + public int textureIndex = 0; + + public boolean hasTower = false; + + /** The entity selector passed into the new AI methods. */ + protected Predicate targetSelector; + + /** Data parameter for the cooldown time for wizards healing themselves. */ + private static final DataParameter HEAL_COOLDOWN = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT); + /** Data parameter for the wizard's element. */ + private static final DataParameter ELEMENT = EntityDataManager.createKey(EntityEvilWizard.class, DataSerializers.VARINT); + /** The resource location for the evil wizard's loot table. */ + private static final ResourceLocation LOOT_TABLE = new ResourceLocation(Wizardry.MODID, "entities/evil_wizard"); + + // Field implementations + private List spells = new ArrayList(4); + private Spell continuousSpell; + + public EntityEvilWizard(World world){ + + super(world); + this.setSize(0.6F, 1.8F); + ((PathNavigateGround)this.getNavigator()).setBreakDoors(true); + + // For some reason this can't be done in initEntityAI + this.tasks.addTask(3, this.spellCastingAI); + + this.detachHome(); + } + + @Override + protected void entityInit(){ + super.entityInit(); + this.dataManager.register(HEAL_COOLDOWN, -1); + this.dataManager.register(ELEMENT, 0); + } + + @Override + protected void initEntityAI(){ + this.tasks.addTask(0, new EntityAISwimming(this)); + this.tasks.addTask(4, new EntityAIRestrictOpenDoor(this)); + this.tasks.addTask(5, new EntityAIOpenDoor(this, true)); + this.tasks.addTask(6, new EntityAIMoveTowardsRestriction(this, 0.6D)); + this.tasks.addTask(7, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F)); + this.tasks.addTask(7, new EntityAIWander(this, 0.6D)); + + this.targetSelector = new Predicate(){ + + public boolean apply(Entity entity){ + + // If the target is valid and not invisible... + if(entity != null && !entity.isInvisible() && WizardryUtilities.isValidTarget(EntityEvilWizard.this, entity)){ + + //... and is a player, a summoned creature, another (non-evil) wizard ... + if(entity instanceof EntityPlayer || (entity instanceof ISummonedCreature || entity instanceof EntityWizard + // ... or in the whitelist ... + || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist).contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))) + // ... and isn't in the blacklist ... + && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist).contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))){ + // ... it can be attacked. + return true; + } + } + + return false; + } + }; + + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); + this.targetTasks.addTask(0, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.targetSelector)); + } + + @Override + protected void applyEntityAttributes() + { + super.applyEntityAttributes(); + this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.5D); + this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(30); + } + + private int getHealCooldown(){ + return this.dataManager.get(HEAL_COOLDOWN); + } + + private void setHealCooldown(int cooldown){ + this.dataManager.set(HEAL_COOLDOWN, cooldown); + } + + public Element getElement(){ + return Element.values()[this.dataManager.get(ELEMENT)]; + } + + public void setElement(Element element){ + this.dataManager.set(ELEMENT, element.ordinal()); + } + + @Override + public List getSpells(){ + return this.spells; + } + + @Override + public SpellModifiers getModifiers(){ + return new SpellModifiers(); + } + + @Override + public void setContinuousSpell(Spell spell){ + this.continuousSpell = spell; + } + + @Override + public Spell getContinuousSpell(){ + return this.continuousSpell; + } + + @Override + public void onLivingUpdate(){ + + super.onLivingUpdate(); + + int healCooldown = this.getHealCooldown(); + + // This is now done slightly differently because isPotionActive doesn't work on client here, meaning that when + // affected with arcane jammer and healCooldown == 0, whilst the wizard didn't actually heal or play the sound, + // the particles still spawned, and since healCooldown wasn't reset they spawned every tick until the arcane + // jammer wore off. + if(healCooldown == 0 && this.getHealth() < this.getMaxHealth() && this.getHealth() > 0 && !this.isPotionActive(WizardryPotions.arcane_jammer)){ + + // Healer wizards use greater heal. + this.heal(this.getElement() == Element.HEALING ? 8 : 4); + this.setHealCooldown(-1); + + // deathTime == 0 checks the wizard isn't currently dying + }else if(healCooldown == -1 && this.deathTime == 0){ + + // Heal particles + if(worldObj.isRemote){ + for(int i=0; i<10; i++){ + double d0 = (double)((float)this.posX + rand.nextFloat()*2 - 1.0F); + // Apparently the client side spawns the particles 1 block higher than it should... hence the - 0.5F. + double d1 = (double)((float)this.posY - 0.5F + rand.nextFloat()); + double d2 = (double)((float)this.posZ + rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, d0, d1, d2, 0, 0.1F, 0, 48 + rand.nextInt(12), 1.0f, 1.0f, 0.3f); + } + }else{ + if(this.getHealth() < 10){ + // Wizard heals himself more often if he has low health + this.setHealCooldown(150); + }else{ + this.setHealCooldown(400); + } + + this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); + } + } + if(healCooldown > 0){ + this.setHealCooldown(healCooldown - 1); + } + } + + @Override + protected boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack){ + + // Debugging + //player.addChatComponentMessage(new TextComponentTranslation("wizard.debug", Spell.get(spells[1]).getDisplayName(), Spell.get(spells[2]).getDisplayName(), Spell.get(spells[3]).getDisplayName())); + + // When right-clicked with a spell book in creative, sets one of the spells to that spell + if(player.capabilities.isCreativeMode && stack != null && stack.getItem() instanceof ItemSpellBook){ + if(this.spells.size() >= 4 && Spell.get(stack.getItemDamage()).canBeCastByNPCs()){ + this.spells.set(rand.nextInt(3)+1, Spell.get(stack.getItemDamage())); + return true; + } + } + + return false; + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbt){ + super.writeEntityToNBT(nbt); + nbt.setInteger("element", this.getElement().ordinal()); + nbt.setInteger("skin", this.textureIndex); + nbt.setTag("spells", WizardryUtilities.listToNBT(spells, spell -> new NBTTagInt(spell.id()))); + nbt.setBoolean("hasTower", this.hasTower); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbt){ + super.readEntityFromNBT(nbt); + this.setElement(Element.values()[nbt.getInteger("element")]); + this.textureIndex = nbt.getInteger("skin"); + this.spells = (List) WizardryUtilities.NBTToList(nbt.getTagList("spells", NBT.TAG_INT), + (NBTTagInt tag) -> Spell.get(tag.getInt())); + this.hasTower = nbt.getBoolean("hasTower"); + } + + @Override + protected boolean canDespawn(){ + // Evil wizards can only despawn if they don't have a tower (i.e. if they spawned naturally at night) + return !this.hasTower; + } + + @Override + protected float getSoundPitch(){ + return (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 0.6F; + } + + @Override + protected SoundEvent getAmbientSound() { + return SoundEvents.ENTITY_WITCH_AMBIENT; + } + + @Override + protected SoundEvent getHurtSound() + { + return SoundEvents.ENTITY_WITCH_HURT; + } + + @Override + protected SoundEvent getDeathSound() + { + return SoundEvents.ENTITY_WITCH_DEATH; + } + + // Although it *looks* like this is still called, in actual fact the only method that calls it is overridden in + // EntityLiving to use the loot table system instead. This has been kept as a fallback in case the loot table is + // not found. + @Override + protected void dropFewItems(boolean hitByPlayer, int lootingLevel){ + // Drops 3-5 crystals without looting bonuses + int j = 3 + this.rand.nextInt(3) + this.rand.nextInt(1 + lootingLevel); + + for(int k=0; k 0 && rand.nextInt(100) - lootingLevel < 5) this.entityDropItem(new ItemStack(WizardryItems.spell_book, 1, this.spells.get(1 + rand.nextInt(this.spells.size() - 1)).id()), 0); + } + + @Override + protected ResourceLocation getLootTable(){ + return LOOT_TABLE; + } + + @Override + public void onDeath(DamageSource source){ + + super.onDeath(source); + if(source.getEntity() instanceof EntityPlayer){ + ((EntityPlayer)source.getEntity()).addStat(WizardryAchievements.defeat_evil_wizard); + } + } + + @Override + public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, IEntityLivingData data){ + + data = super.onInitialSpawn(difficulty, data); + + textureIndex = this.rand.nextInt(6); + + if(rand.nextBoolean()){ + this.setElement(Element.values()[rand.nextInt(Element.values().length - 1) + 1]); + }else{ + this.setElement(Element.MAGIC); + } + + Element element = this.getElement(); + + // Adds armour. + for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ + this.setItemStackToSlot(slot, new ItemStack(WizardryUtilities.getArmour(element, slot))); + } + + // Default chance is 0.085f, for reference. + for(EntityEquipmentSlot slot : EntityEquipmentSlot.values()) this.setDropChance(slot, 0.0f); + + // All wizards know magic missile, even if it is disabled. + spells.add(Spells.magic_missile); + + Tier maxTier = EntityWizard.populateSpells(spells, element, 3, rand); + + // Now done after the spells so it can take the tier into account. For evil wizards this is slightly different; + // it picks a random wand which is at least a high enough tier for the spells the wizard has. + Tier tier = Tier.values()[maxTier.ordinal() + rand.nextInt(Tier.values().length - maxTier.ordinal())]; + this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(WizardryUtilities.getWand(tier, element))); + + return data; + } + + @Override + public void writeSpawnData(ByteBuf data){ + data.writeInt(textureIndex); + } + + @Override + public void readSpawnData(ByteBuf data){ + textureIndex = data.readInt(); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java new file mode 100644 index 00000000..18d18e39 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java @@ -0,0 +1,199 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; +import java.util.UUID; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.EntityFlying; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIAttackMelee; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAILookIdle; +import net.minecraft.entity.ai.EntityAIMoveTowardsTarget; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.monster.EntityIronGolem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.village.Village; +import net.minecraft.world.World; + +public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature { + + // Field implementations + private int lifetime = 600; + private WeakReference casterReference; + private UUID casterUUID; + + // Setter + getter implementations + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID() { return casterUUID; } + @Override public void setCasterUUID(UUID uuid) { this.casterUUID = uuid; } + + /** + * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't + * matter because the client side entity immediately gets the lifetime value copied over to it by this class + * anyway. When extending this class, you must override this constructor or Minecraft won't like it, but there's + * no need to do anything inside it other than call super(). + */ + public EntityIceGiant(World world){ + super(world); + this.setSize(1.4F, 2.9F); + this.experienceValue = 0; + } + + /** + * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when + * extending this class (be sure to call super()) so that AI and other things can be added. + */ + public EntityIceGiant(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world); + this.setSize(1.4F, 2.9F); + this.setPosition(x, y, z); + this.casterReference = new WeakReference(caster); + this.experienceValue = 0; + this.lifetime = lifetime; + } + + @Override + protected void initEntityAI(){ + this.getNavigator().getNodeProcessor().setCanSwim(false); + this.tasks.addTask(1, new EntityAIAttackMelee(this, 1.0D, true)); + this.tasks.addTask(2, new EntityAIMoveTowardsTarget(this, 0.9D, 32.0F)); + //this.tasks.addTask(4, new EntityAIMoveTowardsRestriction(this, 1.0D)); + //this.tasks.addTask(5, new EntityAIWander(this, 0.6D)); + this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F)); + this.tasks.addTask(7, new EntityAILookIdle(this)); + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.getTargetSelector())); + } + + // EntityIronGolem overrides + + @Override protected void updateAITasks(){} // Disables home-checking + @Override public Village getVillage(){ return null; } + @Override public int getHoldRoseTick(){ return 0; } + + // Implementations + + @Override + public void setRevengeTarget(EntityLivingBase entity){ + if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity); + } + + @Override + public void onUpdate(){ + super.onUpdate(); + this.updateDelegate(); + } + + @Override + public void onSpawn(){} + + @Override + public void onDespawn(){ + this.playSound(WizardrySounds.SPELL_FREEZE, 1.0f, 1.0f); + if(this.worldObj.isRemote){ + for(int i=0; i<30; i++){ + float brightness = 0.5f + (rand.nextFloat()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, this.worldObj, this.posX-1 + rand.nextDouble()*2, this.posY+ rand.nextDouble()*3, this.posZ-1 + rand.nextDouble()*2, 0, -0.02, 0, 12 + rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); + } + } + } + + @Override + public void onLivingUpdate(){ + + super.onLivingUpdate(); + + if(this.worldObj.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, this.worldObj, this.posX-1 + rand.nextDouble()*2, this.posY+ rand.nextDouble()*3, this.posZ-1 + rand.nextDouble()*2, 0, -0.02, 0, 40 + rand.nextInt(10)); + } + } + + @Override + public void onSuccessfulAttack(EntityLivingBase target){ + + target.motionY += 0.2; + target.motionX += this.getLookVec().xCoord*0.2; + target.motionZ += this.getLookVec().xCoord*0.2; + + target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 300, 0)); + + this.applyEnchantments(this, target); + + this.playSound(SoundEvents.ENTITY_IRONGOLEM_ATTACK, 1.0F, 1.0F); + } + + @Override + public boolean hasParticleEffect() { + return false; + } + + @Override + protected boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack) { + // In this case, the delegate method determines whether super is called. + // Rather handily, we can make use of Java's short-circuiting method of evaluating OR statements. + return this.interactDelegate(player, hand, stack) || super.processInteract(player, hand, stack); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + // Recommended overrides + + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom onDespawn() method. + @Override protected boolean canDespawn(){ return false; } + + @Override + public boolean canAttackClass(Class entityType){ + // Returns true unless the given entity type is a flying entity. + return !EntityFlying.class.isAssignableFrom(entityType); + } + + @Override + public ITextComponent getDisplayName(){ + if(getCaster() != null){ + return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java new file mode 100644 index 00000000..e7e6b6df --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java @@ -0,0 +1,295 @@ +package electroblob.wizardry.entity.living; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.entity.ai.EntityAILookIdle; +import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction; +import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.monster.EntityBlaze; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +public class EntityIceWraith extends EntityBlazeMinion { + + /** The version from EntityLivingBase is only used in onLivingUpdate, so it can safely be copied. */ + private int jumpTicks; + + public EntityIceWraith(World world){ + super(world); + } + + public EntityIceWraith(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world, x, y, z, caster, lifetime); + this.isImmuneToFire = false; + } + + @Override + protected void initEntityAI(){ + super.initEntityAI(); + this.tasks.taskEntries.clear(); + this.tasks.addTask(4, new AIIceShardAttack(this)); + this.tasks.addTask(5, new EntityAIMoveTowardsRestriction(this, 1.0D)); + this.tasks.addTask(7, new EntityAIWander(this, 1.0D)); + this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); + this.tasks.addTask(8, new EntityAILookIdle(this)); + } + + @Override + protected void spawnParticleEffect() { + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + float brightness = 0.5f + (rand.nextFloat()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX - 0.5d + rand.nextDouble(), this.posY + this.height/2 - 0.5d + rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble(), 0, 0.05f, 0, 20 + rand.nextInt(10), brightness, brightness + 0.1f, 1.0f); + } + } + } + + @Override + public void onLivingUpdate(){ + + if(!this.onGround && this.motionY < 0.0D){ + this.motionY *= 0.6D; + } + + if(this.rand.nextInt(24) == 0){ + this.playSound(WizardrySounds.SPELL_LOOP_WIND, 0.3F + this.rand.nextFloat()/4, this.rand.nextFloat() * 0.7F + 1.4F); + } + + if(this.worldObj.isRemote){ + for(int i = 0; i < 2; ++i){ + this.worldObj.spawnParticle(EnumParticleTypes.CLOUD, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0.0D, 0.0D, 0.0D); + } + } + + // Replaces super call. + this.livingBaseUpdate(); + } + + /** Copied from {@link EntityLivingBase#onLivingUpdate()}. The only change is removal of the updateElytra() call + * since that's irrelevant here. In actual fact, neither EntityMob nor EntityLiving has any code in its version + * of this method that is of use. This isn't exactly ideal, but it's the lesser of two evils since the + * alternative is copying the entire EntityBlaze class and its renderer. All to remove one particle effect... */ + // ... demonstrating why critical methods should delegate any non-critical functionality (like particles) to + // separate protected methods. + private void livingBaseUpdate(){ + + if (this.jumpTicks > 0) + { + --this.jumpTicks; + } + + if (this.newPosRotationIncrements > 0 && !this.canPassengerSteer()) + { + double d0 = this.posX + (this.interpTargetX - this.posX) / (double)this.newPosRotationIncrements; + double d1 = this.posY + (this.interpTargetY - this.posY) / (double)this.newPosRotationIncrements; + double d2 = this.posZ + (this.interpTargetZ - this.posZ) / (double)this.newPosRotationIncrements; + double d3 = MathHelper.wrapDegrees(this.interpTargetYaw - (double)this.rotationYaw); + this.rotationYaw = (float)((double)this.rotationYaw + d3 / (double)this.newPosRotationIncrements); + this.rotationPitch = (float)((double)this.rotationPitch + (this.interpTargetPitch - (double)this.rotationPitch) / (double)this.newPosRotationIncrements); + --this.newPosRotationIncrements; + this.setPosition(d0, d1, d2); + this.setRotation(this.rotationYaw, this.rotationPitch); + } + else if (!this.isServerWorld()) + { + this.motionX *= 0.98D; + this.motionY *= 0.98D; + this.motionZ *= 0.98D; + } + + if (Math.abs(this.motionX) < 0.003D) + { + this.motionX = 0.0D; + } + + if (Math.abs(this.motionY) < 0.003D) + { + this.motionY = 0.0D; + } + + if (Math.abs(this.motionZ) < 0.003D) + { + this.motionZ = 0.0D; + } + + this.worldObj.theProfiler.startSection("ai"); + + if (this.isMovementBlocked()) + { + this.isJumping = false; + this.moveStrafing = 0.0F; + this.moveForward = 0.0F; + this.randomYawVelocity = 0.0F; + } + else if (this.isServerWorld()) + { + this.worldObj.theProfiler.startSection("newAi"); + this.updateEntityActionState(); + this.worldObj.theProfiler.endSection(); + } + + this.worldObj.theProfiler.endSection(); + this.worldObj.theProfiler.startSection("jump"); + + if (this.isJumping) + { + if (this.isInWater()) + { + this.handleJumpWater(); + } + else if (this.isInLava()) + { + this.handleJumpLava(); + } + else if (this.onGround && this.jumpTicks == 0) + { + this.jump(); + this.jumpTicks = 10; + } + } + else + { + this.jumpTicks = 0; + } + + this.worldObj.theProfiler.endSection(); + this.worldObj.theProfiler.startSection("travel"); + this.moveStrafing *= 0.98F; + this.moveForward *= 0.98F; + this.randomYawVelocity *= 0.9F; + this.moveEntityWithHeading(this.moveStrafing, this.moveForward); + this.worldObj.theProfiler.endSection(); + this.worldObj.theProfiler.startSection("push"); + this.collideWithNearbyEntities(); + this.worldObj.theProfiler.endSection(); + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount){ + // Removes the damage from being wet that applies to blazes by checking if the mob is actually drowning. + if(source == DamageSource.drown && (this.getAir() > 0 || this.isPotionActive(MobEffects.WATER_BREATHING))){ + // In this case, the ice wraith is not actually drowning, so cancel the damage. + return false; + }else{ + return super.attackEntityFrom(source, amount); + } + } + + @Override + public boolean isBurning(){ + // Uses the datawatcher on both sides because fire is private to Entity (and I'm not using reflection here). + // TESTME: This should work, but there may be some issues with updating, so if it doesn't work, copy the + // version from Entity and use reflection to access the fire field. + return this.getFlag(0); + } + + /** Copied straight from EntityBlaze.AIFireballAttack, with the only changes being replacement of fireball + * spawning with a one-liner call to WizardryRegistry.iceShard.cast(...) and the removal of redundant local variables. */ + static class AIIceShardAttack extends EntityAIBase { + + private final EntityBlaze blaze; + private int attackStep; + private int attackTime; + + public AIIceShardAttack(EntityBlaze blazeIn) + { + this.blaze = blazeIn; + this.setMutexBits(3); + } + + /** + * Returns whether the EntityAIBase should begin execution. + */ + public boolean shouldExecute() + { + EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); + return entitylivingbase != null && entitylivingbase.isEntityAlive(); + } + + /** + * Execute a one shot task or start executing a continuous task + */ + public void startExecuting() + { + this.attackStep = 0; + } + + /** + * Resets the task + */ + public void resetTask() + { + // This might be called setOnFire, but what it really controls is whether the wraith is in attack mode. + this.blaze.setOnFire(false); + } + + /** + * Updates the task + */ + public void updateTask() + { + --this.attackTime; + EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); + double d0 = this.blaze.getDistanceSqToEntity(entitylivingbase); + + if (d0 < 4.0D) + { + if (this.attackTime <= 0) + { + this.attackTime = 20; + this.blaze.attackEntityAsMob(entitylivingbase); + } + + this.blaze.getMoveHelper().setMoveTo(entitylivingbase.posX, entitylivingbase.posY, entitylivingbase.posZ, 1.0D); + } + else if (d0 < 256.0D) + { + if (this.attackTime <= 0) + { + ++this.attackStep; + + if (this.attackStep == 1) + { + this.attackTime = 60; + this.blaze.setOnFire(true); + } + else if (this.attackStep <= 4) + { + this.attackTime = 6; + } + else + { + this.attackTime = 100; + this.attackStep = 0; + this.blaze.setOnFire(false); + } + + if(this.attackStep > 1){ + // Proof, if it were at all needed, of the elegance and versatility of the spell system. + Spells.ice_shard.cast(this.blaze.worldObj, this.blaze, EnumHand.MAIN_HAND, 0, entitylivingbase, new SpellModifiers()); + } + } + + this.blaze.getLookHelper().setLookPositionWithEntity(entitylivingbase, 10.0F, 10.0F); + } + else + { + this.blaze.getNavigator().clearPathEntity(); + this.blaze.getMoveHelper().setMoveTo(entitylivingbase.posX, entitylivingbase.posY, entitylivingbase.posZ, 1.0D); + } + + super.updateTask(); + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java new file mode 100644 index 00000000..da1cc283 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java @@ -0,0 +1,179 @@ +package electroblob.wizardry.entity.living; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.entity.ai.EntityAILookIdle; +import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction; +import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.monster.EntityBlaze; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class EntityLightningWraith extends EntityBlazeMinion { + + public EntityLightningWraith(World world){ + super(world); + } + + public EntityLightningWraith(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world, x, y, z, caster, lifetime); + this.isImmuneToFire = false; + } + + @Override + protected void initEntityAI(){ + super.initEntityAI(); + this.tasks.taskEntries.clear(); + this.tasks.addTask(4, new AILightningAttack(this)); + this.tasks.addTask(5, new EntityAIMoveTowardsRestriction(this, 1.0D)); + this.tasks.addTask(7, new EntityAIWander(this, 1.0D)); + this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); + this.tasks.addTask(8, new EntityAILookIdle(this)); + } + + @Override + protected void spawnParticleEffect(){ + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + float brightness = 0.3f + (rand.nextFloat()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX - 0.5d + rand.nextDouble(), this.posY + this.height/2 - 0.5d + rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble(), 0, 0.05f, 0, 20 + rand.nextInt(10), brightness, brightness + 0.2f, 1.0f); + } + } + } + + @Override + public void onLivingUpdate(){ + // Fortunately, lightning wraiths don't replace any of blazes' particle effects or the fire sound, they only + // add the sparks, so it's fine to call super here. + if(worldObj.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0, 3); + } + super.onLivingUpdate(); + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount){ + // Removes the damage from being wet that applies to blazes by checking if the mob is actually drowning. + if(source == DamageSource.drown && (this.getAir() > 0 || this.isPotionActive(MobEffects.WATER_BREATHING))){ + // In this case, the lightning wraith is not actually drowning, so cancel the damage. + return false; + }else{ + return super.attackEntityFrom(source, amount); + } + } + + @Override + public boolean isBurning(){ + // Uses the datawatcher on both sides because fire is private to Entity (and I'm not using reflection here). + // TESTME: This should work, but there may be some issues with updating, so if it doesn't work, copy the + // version from Entity and use reflection to access the fire field. + return this.getFlag(0); + } + + /** Copied straight from EntityBlaze.AIFireballAttack, with the only changes being replacement of fireball + * spawning with a one-liner call to WizardryRegistry.arc.cast(...) and the removal of redundant local variables. */ + static class AILightningAttack extends EntityAIBase { + + private final EntityBlaze blaze; + private int attackStep; + private int attackTime; + + public AILightningAttack(EntityBlaze blazeIn) + { + this.blaze = blazeIn; + this.setMutexBits(3); + } + + /** + * Returns whether the EntityAIBase should begin execution. + */ + public boolean shouldExecute() + { + EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); + return entitylivingbase != null && entitylivingbase.isEntityAlive(); + } + + /** + * Execute a one shot task or start executing a continuous task + */ + public void startExecuting() + { + this.attackStep = 0; + } + + /** + * Resets the task + */ + public void resetTask() + { + // This might be called setOnFire, but what it really controls is whether the wraith is in attack mode. + this.blaze.setOnFire(false); + } + + /** + * Updates the task + */ + public void updateTask() + { + --this.attackTime; + EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); + double d0 = this.blaze.getDistanceSqToEntity(entitylivingbase); + + if (d0 < 4.0D) + { + if (this.attackTime <= 0) + { + this.attackTime = 20; + this.blaze.attackEntityAsMob(entitylivingbase); + } + + this.blaze.getMoveHelper().setMoveTo(entitylivingbase.posX, entitylivingbase.posY, entitylivingbase.posZ, 1.0D); + } + else if (d0 < 256.0D) + { + if (this.attackTime <= 0) + { + ++this.attackStep; + + if (this.attackStep == 1) + { + this.attackTime = 60; + this.blaze.setOnFire(true); + } + else if (this.attackStep <= 4) + { + this.attackTime = 6; + } + else + { + this.attackTime = 100; + this.attackStep = 0; + this.blaze.setOnFire(false); + } + + if(this.attackStep > 1){ + // Proof, if it were at all needed, of the elegance and versatility of the spell system. + Spells.arc.cast(this.blaze.worldObj, this.blaze, EnumHand.MAIN_HAND, 0, entitylivingbase, new SpellModifiers()); + } + } + + this.blaze.getLookHelper().setLookPositionWithEntity(entitylivingbase, 10.0F, 10.0F); + } + else + { + this.blaze.getNavigator().clearPathEntity(); + this.blaze.getMoveHelper().setMoveTo(entitylivingbase.posX, entitylivingbase.posY, entitylivingbase.posZ, 1.0D); + } + + super.updateTask(); + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java b/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java new file mode 100644 index 00000000..c6799fcf --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java @@ -0,0 +1,177 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; +import java.util.UUID; + +import javax.annotation.Nullable; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.monster.EntitySlime; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.EnumDifficulty; +import net.minecraft.world.World; + +/** As of Wizardry 1.2, this is now an ISummonedCreature like the rest of them, and it extends EntitySlime. */ +public class EntityMagicSlime extends EntitySlime implements ISummonedCreature { + + // Field implementations + private int lifetime = 200; + private WeakReference casterReference; + private UUID casterUUID; + + // Setter + getter implementations + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID() { return casterUUID; } + @Override public void setCasterUUID(UUID uuid) { this.casterUUID = uuid; } + + public EntityMagicSlime(World world){ + super(world); + this.setSlimeSize(2); // Needs to be called before setting the experience value to 0 + this.experienceValue = 0; + } + + /** + * Creates a new magic slime with the given caster and lifetime, riding the given target. + * @param world The world that the slime is in. + * @param caster The entity that created the slime. + * @param target The slime's victim. The slime will automatically start riding this entity. + * @param lifetime The number of ticks before the slime bursts. + */ + public EntityMagicSlime(World world, EntityLivingBase caster, EntityLivingBase target, int lifetime){ + super(world); + this.setPosition(target.posX, target.posY, target.posZ); + this.startRiding(target); + this.casterReference = new WeakReference(caster); + this.setSlimeSize(2); // Needs to be called before setting the experience value to 0 + this.experienceValue = 0; + this.lifetime = lifetime; + } + + // EntitySlime overrides + + @Override + protected void initEntityAI(){} // Has no AI! + + @Override + protected void dealDamage(EntityLivingBase entity){} // Handles damage itself + + @Override + public void setDead(){ + // Restores behaviour from Entity, replacing slime splitting behaviour. + this.isDead = true; + // Makes sure that the undoing in onUpdate won't undo this. For some reason, EntitySlime sets isDead directly + // to do the peaceful despawning, which seems odd but is actually rather handy! + this.setHealth(0); + // Bursting effect + for(int i=0; i<30; i++){ + double x = this.posX - 0.5 + rand.nextDouble(); + double y = this.posY - 0.5 + rand.nextDouble(); + double z = this.posZ - 0.5 + rand.nextDouble(); + this.worldObj.spawnParticle(EnumParticleTypes.SLIME, x, y, z, (x - this.posX)*2, (y - this.posY)*2, (z - this.posZ)*2); + } + this.playSound(SoundEvents.ENTITY_SLIME_ATTACK, 2.5f, 0.6f); + this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST_FAR, 1.0f, 0.5f); + } + + @Override + public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata){ + // Removes size randomisation + IEntityLivingData data = super.onInitialSpawn(difficulty, livingdata); + this.setSlimeSize(2); + return data; + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount){ + // Immune to suffocation + return source == DamageSource.inWall ? false : super.attackEntityFrom(source, amount); + } + + // Implementations + + @Override + public void setRevengeTarget(EntityLivingBase entity){ + if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity); + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + // Undoes the despawning on peaceful behaviour. I don't think there's anything in super.onUpdate that sets + // isDead other than that, but it's better to do a quick sanity check just to be sure. + if(this.isDead && worldObj.getDifficulty() == EnumDifficulty.PEACEFUL && this.getHealth() > 0) this.isDead = false; + // Bursts instantly rather than doing the falling over animation. + if(this.getHealth() <= 0) this.setDead(); + + this.updateDelegate(); + + // Damages and slows the slime's victim or makes the slime explode if the victim is dead. + if(this.getRidingEntity() != null && this.getRidingEntity() instanceof EntityLivingBase && ((EntityLivingBase)this.getRidingEntity()).getHealth() > 0){ + if(this.ticksExisted % 16 == 1){ + this.getRidingEntity().attackEntityFrom(DamageSource.magic, 1); + ((EntityLivingBase)this.getRidingEntity()).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 20, 2)); + this.playSound(SoundEvents.ENTITY_SLIME_ATTACK, 1.0f, 1.0f); + this.squishAmount = 0.5F; + } + }else{ + this.setDead(); + } + } + + @Override + public void onSpawn(){} + + @Override + public void onDespawn(){} + + @Override + public boolean hasParticleEffect() { + return false; + } + + @Override + protected boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack) { + // In this case, the delegate method determines whether super is called. + // Rather handily, we can make use of Java's short-circuiting method of evaluating OR statements. + return this.interactDelegate(player, hand, stack) || super.processInteract(player, hand, stack); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + // Recommended overrides + + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom onDespawn() method. + @Override protected boolean canDespawn(){ return false; } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java new file mode 100644 index 00000000..5d72f26e --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java @@ -0,0 +1,189 @@ +package electroblob.wizardry.entity.living; + +import java.util.Collections; +import java.util.List; + +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAILookIdle; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaster { + + private double AISpeed = 0.5; + + // Can attack for 7 seconds, then must cool down for 3. + private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 60, 140); + + private Spell continuousSpell; + + private static final List attack = Collections.singletonList(Spells.flame_ray); + + public EntityPhoenix(World world){ + super(world); + } + + public EntityPhoenix(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world, x, y, z, caster, lifetime); + this.isImmuneToFire = true; + this.height = 2.0f; + // For some reason this can't be in initEntityAI + this.tasks.addTask(1, this.spellAttackAI); + } + + @Override + protected void initEntityAI(){ + + this.tasks.addTask(0, new EntityAIWatchClosest(this, EntityLivingBase.class, 0)); + //this.tasks.addTask(2, new EntityAIWander(this, AISpeed)); + this.tasks.addTask(3, new EntityAILookIdle(this)); + //this.targetTasks.addTask(0, new EntityAIMoveTowardsTarget(this, 1, 10)); + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.getTargetSelector())); + + this.setAIMoveSpeed((float)AISpeed); + } + + @Override + public List getSpells(){ + return attack; + } + + @Override + public SpellModifiers getModifiers(){ + return new SpellModifiers(); + } + + @Override + public Spell getContinuousSpell(){ + return continuousSpell; + } + + @Override + public void setContinuousSpell(Spell spell){ + continuousSpell = spell; + } + + @Override + public boolean hasRangedAttack() { + return true; + } + + @Override + // Makes the flames come from the phoenix's head rather than its body + public float getEyeHeight(){ + return 2.1f; + } + + @Override + protected void applyEntityAttributes(){ + super.applyEntityAttributes(); + this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(6.0D); + this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(30.0D); + this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(30.0D); + } + + @Override + protected SoundEvent getAmbientSound(){ + return SoundEvents.ENTITY_BLAZE_AMBIENT; + } + + @Override + protected SoundEvent getHurtSound(){ + return SoundEvents.ENTITY_BLAZE_HURT; + } + + @Override + protected SoundEvent getDeathSound(){ + return SoundEvents.ENTITY_BLAZE_DEATH; + } + + @Override + @SideOnly(Side.CLIENT) + public int getBrightnessForRender(float par1){ + return 15728880; + } + + @Override + public float getBrightness(float par1){ + return 1.0F; + } + + @Override + public void onSpawn(){ + this.spawnParticleEffect(); + } + + @Override + public void onDespawn(){ + this.spawnParticleEffect(); + } + + private void spawnParticleEffect(){ + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + this.worldObj.spawnParticle(EnumParticleTypes.FLAME, this.posX + this.rand.nextFloat(), this.posY + 1 + this.rand.nextFloat(), this.posZ + this.rand.nextFloat(), 0, 0, 0); + } + } + } + + @Override + public void onLivingUpdate(){ + + // Makes the phoenix hover. + int floorLevel = WizardryUtilities.getNearestFloorLevel(worldObj, new BlockPos(this), 4); + + if(this.posY - floorLevel > 3){ + this.motionY = -0.1; + }else if(this.posY - floorLevel < 2){ + this.motionY = 0.1; + }else{ + this.motionY = 0.0; + } + + // Living sound + if(this.rand.nextInt(24) == 0){ + this.playSound(SoundEvents.BLOCK_FIRE_AMBIENT, 1.0F + this.rand.nextFloat(), this.rand.nextFloat() * 0.7F + 0.3F); + } + + // Flapping sound effect + if(this.ticksExisted % 22 == 0){ + this.playSound(SoundEvents.ENTITY_ENDERDRAGON_FLAP, 1.0F, 1.0f); + } + + for(int i=0; i<2; i++){ + this.worldObj.spawnParticle(EnumParticleTypes.FLAME, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.height/2 + this.rand.nextDouble() * (double)this.height/2, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0.0D, -0.1D, 0.0D); + } + + // Adding this allows the phoenix to attack despite being in the air. However, for some strange reason + // it will only attack when within about 3 blocks of the ground. Any higher and it just sits there, not even + // attempting to find targets. + + this.onGround = true; + + super.onLivingUpdate(); + } + + @Override + public void fall(float distance, float damageMultiplier){} // Immune to fall damage + + @Override + public boolean isBurning() + { + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java new file mode 100644 index 00000000..000ba391 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java @@ -0,0 +1,165 @@ +package electroblob.wizardry.entity.living; + +import java.util.Collections; +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.EntityAIAttackMelee; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAILookIdle; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.SoundEvent; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class EntityShadowWraith extends EntitySummonedCreature implements ISpellCaster { + + // TODO: This currently doesn't fly like it used to. Should it, or does it not matter? + + private double AISpeed = 1.0; + + private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 30, 0); + + private static final List attack = Collections.singletonList(Spells.darkness_orb); + + public EntityShadowWraith(World world){ + super(world); + } + + public EntityShadowWraith(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world, x, y, z, caster, lifetime); + // For some reason this can't be in initEntityAI + this.tasks.addTask(0, this.spellAttackAI); + } + + @Override + protected void initEntityAI(){ + + this.tasks.addTask(1, new EntityAIAttackMelee(this, AISpeed, false)); + this.tasks.addTask(2, new EntityAIWander(this, AISpeed)); + this.tasks.addTask(3, new EntityAILookIdle(this)); + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.getTargetSelector())); + + this.setAIMoveSpeed((float)AISpeed); + } + + @Override + public boolean hasRangedAttack() { + return true; + } + + @Override + public List getSpells(){ + return attack; + } + + @Override + public SpellModifiers getModifiers(){ + return new SpellModifiers(); + } + + @Override + public Spell getContinuousSpell(){ + return Spells.none; + } + + @Override + public void setContinuousSpell(Spell spell){ + // Doesn't use continuous spells. + } + + @Override + protected void applyEntityAttributes(){ + super.applyEntityAttributes(); + this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(6.0D); + this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(AISpeed); + this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(30.0D); + this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(16.0D); + } + + @Override + public boolean isPotionApplicable(PotionEffect potion){ + return potion.getPotion() == MobEffects.WITHER ? false : super.isPotionApplicable(potion); + } + + @Override + protected SoundEvent getAmbientSound(){ + return SoundEvents.ENTITY_BLAZE_AMBIENT; + } + + @Override + protected SoundEvent getHurtSound(){ + return SoundEvents.ENTITY_BLAZE_HURT; + } + + @Override + protected SoundEvent getDeathSound(){ + return SoundEvents.ENTITY_BLAZE_DEATH; + } + + @Override + @SideOnly(Side.CLIENT) + public int getBrightnessForRender(float partialTicks){ + return 15728880; + } + + @Override + public float getBrightness(float partialTicks){ + return 1.0F; + } + + @Override + public void onSpawn(){ + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + float brightness = rand.nextFloat()*0.4f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX - 0.5d + rand.nextDouble(), this.posY + this.height/2 - 0.5d + rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble(), 0, 0.05f, 0, 20 + rand.nextInt(10), brightness, 0.0f, brightness); + } + } + } + + @Override + public void onLivingUpdate(){ + + if(this.rand.nextInt(24) == 0){ + this.playSound(SoundEvents.BLOCK_PORTAL_AMBIENT, 1.0F + this.rand.nextFloat(), this.rand.nextFloat() * 0.7F + 0.3F); + } + + // Slow fall + if(!this.onGround && this.motionY < 0.0D){ + this.motionY *= 0.6D; + } + + if(worldObj.isRemote){ + for(int i=0; i<2; i++){ + worldObj.spawnParticle(EnumParticleTypes.PORTAL, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0); + worldObj.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0); + float brightness = rand.nextFloat()*0.2f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0.05f, 0, 20 + rand.nextInt(10), brightness, 0.0f, brightness); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); + } + } + + super.onLivingUpdate(); + } + + @Override + public void fall(float distance, float damageMultiplier){ + // Immune to fall damage. + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java new file mode 100644 index 00000000..2a8f237e --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java @@ -0,0 +1,183 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; +import java.util.UUID; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.EntityFlying; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIAttackMelee; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.ai.EntityAISwimming; +import net.minecraft.entity.monster.EntitySilverfish; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class EntitySilverfishMinion extends EntitySilverfish implements ISummonedCreature { + + // Field implementations + private int lifetime = 600; + private WeakReference casterReference; + private UUID casterUUID; + + // Setter + getter implementations + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID() { return casterUUID; } + @Override public void setCasterUUID(UUID uuid) { this.casterUUID = uuid; } + + /** + * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't + * matter because the client side entity immediately gets the lifetime value copied over to it by this class + * anyway. When extending this class, you must override this constructor or Minecraft won't like it, but there's + * no need to do anything inside it other than call super(). + */ + public EntitySilverfishMinion(World world){ + super(world); + this.experienceValue = 0; + } + + /** + * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when + * extending this class (be sure to call super()) so that AI and other things can be added. + */ + public EntitySilverfishMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world); + this.setPosition(x, y, z); + this.casterReference = new WeakReference(caster); + this.experienceValue = 0; + this.lifetime = lifetime; + } + + // EntitySilverfish overrides + @Override + protected void initEntityAI() + { + // Super not called because we don't want AISummonSilverfish or AIHideInStone + this.tasks.addTask(1, new EntityAISwimming(this)); + this.tasks.addTask(4, new EntityAIAttackMelee(this, 1.0D, false)); + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.getTargetSelector())); + } + + // Implementations + + @Override + public void setRevengeTarget(EntityLivingBase entity){ + if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity); + } + + @Override + public void onUpdate(){ + super.onUpdate(); + this.updateDelegate(); + } + + @Override + public void onSpawn(){ + this.spawnParticleEffect(); + } + + @Override + public void onDespawn(){ + this.spawnParticleEffect(); + } + + private void spawnParticleEffect(){ + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + this.rand.nextFloat(), this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat(), 0.0d, 0.0d, 0.0d, 0, 0.3f, 0.3f, 0.3f); + } + } + } + + @Override + public void onSuccessfulAttack(EntityLivingBase target){ + if(!target.isEntityAlive()){ + this.onKillEntity(target); + } + } + + @Override + public void onKillEntity(EntityLivingBase victim) { + // If the silverfish has a summoner, this is actually called from Wizardry's event handler rather than by + // Minecraft itself, because the damagesource being changed causes it not to get called. + if(!this.worldObj.isRemote){ + // Summons 1-4 more silverfish + int alliesToSummon = rand.nextInt(4) + 1; + + for(int i=0; i entityType){ + // Returns true unless the given entity type is a flying entity. + return !EntityFlying.class.isAssignableFrom(entityType); + } + + @Override + public ITextComponent getDisplayName(){ + if(getCaster() != null){ + return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java new file mode 100644 index 00000000..e62435f3 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java @@ -0,0 +1,216 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; +import java.util.Calendar; +import java.util.UUID; + +import javax.annotation.Nullable; + +import electroblob.wizardry.Wizardry; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.monster.EntitySkeleton; +import net.minecraft.entity.monster.SkeletonType; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.init.MobEffects; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.World; + +public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCreature { + + // Field implementations + private int lifetime = 600; + private WeakReference casterReference; + private UUID casterUUID; + + // Setter + getter implementations + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID() { return casterUUID; } + @Override public void setCasterUUID(UUID uuid) { this.casterUUID = uuid; } + + /** + * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't + * matter because the client side entity immediately gets the lifetime value copied over to it by this class + * anyway. When extending this class, you must override this constructor or Minecraft won't like it, but there's + * no need to do anything inside it other than call super(). + */ + public EntitySkeletonMinion(World world){ + super(world); + this.experienceValue = 0; + } + + /** + * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when + * extending this class (be sure to call super()) so that AI and other things can be added. + */ + public EntitySkeletonMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world); + this.setPosition(x, y, z); + this.casterReference = new WeakReference(caster); + this.experienceValue = 0; + this.lifetime = lifetime; + } + + // EntitySkeleton overrides + + // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its + // targeting system with one that targets hostile mobs and takes the ADS into account. + @Override + protected void initEntityAI() + { + super.initEntityAI(); + this.targetTasks.taskEntries.clear(); + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.getTargetSelector())); + } + + // Shouldn't have randomised armour, but does still need a bow! + @Override + protected void setEquipmentBasedOnDifficulty(DifficultyInstance difficulty) { + this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); + } + + // Where the skeleton minion is summoned does not affect its type. + @Override + public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata) + { + // Can't call super, so the code from the next level up (EntityLiving) had to be copied as well. + this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).applyModifier(new AttributeModifier("Random spawn bonus", this.rand.nextGaussian() * 0.05D, 1)); + + if (this.rand.nextFloat() < 0.05F) + { + this.setLeftHanded(true); + } + else + { + this.setLeftHanded(false); + } + + // Halloween pumpkin heads! Why not? + if (this.getItemStackFromSlot(EntityEquipmentSlot.HEAD) == null) + { + Calendar calendar = this.worldObj.getCurrentDate(); + + if (calendar.get(2) + 1 == 10 && calendar.get(5) == 31 && this.rand.nextFloat() < 0.25F) + { + this.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(this.rand.nextFloat() < 0.1F ? Blocks.LIT_PUMPKIN : Blocks.PUMPKIN)); + this.inventoryArmorDropChances[EntityEquipmentSlot.HEAD.getIndex()] = 0.0F; + } + } + + return livingdata; + } + + // Implementations + + @Override + public void setRevengeTarget(EntityLivingBase entity){ + if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity); + } + + @Override + public void onUpdate(){ + super.onUpdate(); + this.updateDelegate(); + } + + @Override + public void onSpawn(){ + this.spawnParticleEffect(); + } + + @Override + public void onDespawn(){ + this.spawnParticleEffect(); + } + + private void spawnParticleEffect(){ + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + this.worldObj.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + this.rand.nextFloat(), this.posY + 1 + this.rand.nextFloat(), this.posZ + this.rand.nextFloat(), 0, 0, 0); + } + } + } + + @Override + public boolean hasParticleEffect() { + return true; + } + + @Override + public void onSuccessfulAttack(EntityLivingBase target) { + if(this.getSkeletonType() == SkeletonType.WITHER){ + target.addPotionEffect(new PotionEffect(MobEffects.WITHER, 200)); + } + } + + @Override + protected boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack) { + // In this case, the delegate method determines whether super is called. + // Rather handily, we can make use of Java's 'stop as soon as you find true' method of evaluating OR statements. + return this.interactDelegate(player, hand, stack) || super.processInteract(player, hand, stack); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + // Recommended overrides + + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. + @Override protected boolean canDespawn(){ return false; } + + @Override + public boolean canAttackClass(Class entityType){ + return true; + } + + @Override + public ITextComponent getDisplayName(){ + if(getCaster() != null){ + return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java new file mode 100644 index 00000000..f5714361 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java @@ -0,0 +1,207 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; +import java.util.UUID; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.EntityFlying; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.monster.EntityCaveSpider; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.EnumDifficulty; +import net.minecraft.world.World; + +public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCreature { + + // Field implementations + private int lifetime = 600; + private WeakReference casterReference; + private UUID casterUUID; + + // Setter + getter implementations + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID() { return casterUUID; } + @Override public void setCasterUUID(UUID uuid) { this.casterUUID = uuid; } + + /** + * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't + * matter because the client side entity immediately gets the lifetime value copied over to it by this class + * anyway. When extending this class, you must override this constructor or Minecraft won't like it, but there's + * no need to do anything inside it other than call super(). + */ + public EntitySpiderMinion(World world){ + super(world); + this.experienceValue = 0; + } + + /** + * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when + * extending this class (be sure to call super()) so that AI and other things can be added. + */ + public EntitySpiderMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world); + this.setPosition(x, y, z); + this.casterReference = new WeakReference(caster); + this.experienceValue = 0; + this.lifetime = lifetime; + } + + // EntitySpider overrides + + // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its + // targeting system with one that targets hostile mobs and takes the ADS into account. + @Override + protected void initEntityAI() + { + super.initEntityAI(); + this.targetTasks.taskEntries.clear(); + // Spiders use a custom AI type specific to spiders which I can't access, but it's just an extension of + // EntityAINearestAttackableTarget which takes daylight into account. Since I want spider minions to attack + // regardless of daylight, I can just use EntityAINearestAttackableTarget. + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.getTargetSelector())); + } + + // No spider jockeys! + @Override + public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, IEntityLivingData livingdata) { + + // Can't call super, so the code from the next level up (EntityLiving) had to be copied as well. + this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).applyModifier(new AttributeModifier("Random spawn bonus", this.rand.nextGaussian() * 0.05D, 1)); + + if (this.rand.nextFloat() < 0.05F) + { + this.setLeftHanded(true); + } + else + { + this.setLeftHanded(false); + } + + // Don't need anything from EntitySpider, since neither spider jockeys nor group data is relevant. + return livingdata; + } + + // Implementations + + @Override + public void setRevengeTarget(EntityLivingBase entity){ + if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity); + } + + @Override + public void onUpdate(){ + super.onUpdate(); + this.updateDelegate(); + } + + @Override + public void onSpawn(){ + this.spawnParticleEffect(); + } + + @Override + public void onDespawn(){ + this.spawnParticleEffect(); + } + + private void spawnParticleEffect(){ + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + this.rand.nextFloat(), this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat(), 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.2f, 0.0f); + } + } + } + + @Override + public boolean hasParticleEffect() { + return true; + } + + @Override + public void onSuccessfulAttack(EntityLivingBase target){ + + int seconds = 0; + + if(this.worldObj.getDifficulty() == EnumDifficulty.NORMAL){ + seconds = 7; + }else if(this.worldObj.getDifficulty() == EnumDifficulty.HARD){ + seconds = 15; + } + + if(seconds > 0){ + target.addPotionEffect(new PotionEffect(MobEffects.POISON, seconds * 20, 0)); + } + } + + @Override + protected boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack) { + // In this case, the delegate method determines whether super is called. + // Rather handily, we can make use of Java's 'stop as soon as you find true' method of evaluating OR statements. + return this.interactDelegate(player, hand, stack) || super.processInteract(player, hand, stack); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + // Recommended overrides + + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. + @Override protected boolean canDespawn(){ return false; } + + @Override + public boolean canAttackClass(Class entityType){ + // Returns true unless the given entity type is a flying entity. + return !EntityFlying.class.isAssignableFrom(entityType); + } + + @Override + public ITextComponent getDisplayName(){ + if(getCaster() != null){ + return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java new file mode 100644 index 00000000..47be717e --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java @@ -0,0 +1,203 @@ +package electroblob.wizardry.entity.living; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.passive.EntityAnimal; +import net.minecraft.entity.passive.EntityHorse; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumHand; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.translation.I18n; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.World; + +/** Does not implement ISummonedCreature because it has different despawning rules and because EntityHorse already + * has an owner system. */ +@SuppressWarnings("deprecation") // It's what Entity does, so... +public class EntitySpiritHorse extends EntityHorse { + + private int idleTimer = 0; + + public EntitySpiritHorse(World par1World) + { + super(par1World); + } + + @Override + public String getName() + { + if (this.hasCustomName()) + { + return this.getCustomNameTag(); + } + else + { + return I18n.translateToLocal("entity.wizardry.Spirit Horse.name"); + } + } + + @Override + public boolean isChested() + { + return false; + } + + @Override + public int getTotalArmorValue() + { + return 0; + } + + @Override + protected int getExperiencePoints(EntityPlayer p_70693_1_){ + return 0; + } + + @Override + protected Item getDropItem(){ + + return null; + } + + @Override + protected void dropFewItems(boolean par1, int par2){} + + @Override + protected void applyEntityAttributes() + { + super.applyEntityAttributes(); + this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(24.0D); + } + + @Override + public void openGUI(EntityPlayer p_110199_1_){} + + @Override + public boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack){ + + ItemStack itemstack = player.inventory.getCurrentItem(); + + // Allows the owner (but not other players) to dispel the spirit horse using a wand (shift-clicking, because clicking mounts the horse in this case). + if(itemstack != null && itemstack.getItem() instanceof ItemWand && this.getOwner() == player && player.isSneaking()){ + // Prevents accidental double clicking. + if(this.ticksExisted > 20){ + for(int i=0;i<15;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX - this.width/2 + this.rand.nextFloat()*width, this.posY + this.height*this.rand.nextFloat() + 0.2f, this.posZ - this.width/2 + this.rand.nextFloat()*width, 0, 0, 0, 48 + this.rand.nextInt(12), 0.8f, 0.8f, 1.0f); + } + this.setDead(); + if(WizardData.get(player) != null){ + WizardData.get(player).hasSpiritHorse = false; + } + this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); + // This is necessary to prevent the wand's spell being cast when performing this action. + return true; + } + return false; + } + + return super.processInteract(player, hand, itemstack); + } + + @Override + public void onDeath(DamageSource par1DamageSource){ + + super.onDeath(par1DamageSource); + + // Allows player to summon another spirit horse once this one has died. + if(this.getOwner() instanceof EntityPlayer && WizardData.get((EntityPlayer)this.getOwner()) != null){ + WizardData.get((EntityPlayer)this.getOwner()).hasSpiritHorse = false; + } + } + + // I wrote this one! + private EntityLivingBase getOwner(){ + + // I think the DataManager stores any objects, so it now stores the UUID instead of its string representation. + Entity owner = WizardryUtilities.getEntityByUUID(worldObj, this.getOwnerUniqueId()); + + if(owner instanceof EntityLivingBase){ + return (EntityLivingBase)owner; + }else{ + return null; + } + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + // Adds a dust particle effect + if(this.worldObj.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, worldObj, this.posX - this.width/2 + this.rand.nextFloat()*width, this.posY + this.height*this.rand.nextFloat() + 0.2f, this.posZ - this.width/2 + this.rand.nextFloat()*width, 0, 0, 0, 0, 0.8f, 0.8f, 1.0f); + } + + // Spirit horse disappears a short time after being dismounted. + if(!this.isBeingRidden()){ + this.idleTimer++; + }else if(this.idleTimer > 0){ + this.idleTimer = 0; + } + + if(this.idleTimer > 200){ + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX - this.width/2 + this.rand.nextFloat()*width, this.posY + this.height*this.rand.nextFloat() + 0.2f, this.posZ - this.width/2 + this.rand.nextFloat()*width, 0, 0, 0, 48 + this.rand.nextInt(12), 0.8f, 0.8f, 1.0f); + } + } + this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); + // Allows player to summon another spirit horse once this one has disappeared. + if(this.getOwner() instanceof EntityPlayer && WizardData.get((EntityPlayer)this.getOwner()) != null){ + WizardData.get((EntityPlayer)this.getOwner()).hasSpiritHorse = false; + } + this.setDead(); + } + } + + @Override + public boolean canMateWith(EntityAnimal par1EntityAnimal){ + return false; + } + + @Override + public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, IEntityLivingData data){ + + // Adds Particles on spawn. Due to client/server differences this cannot be done in the item. + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX - this.width/2 + this.rand.nextFloat()*width, this.posY + this.height*this.rand.nextFloat() + 0.2f, this.posZ - this.width/2 + this.rand.nextFloat()*width, 0, 0, 0, 48 + this.rand.nextInt(12), 0.8f, 0.8f, 1.0f); + } + } + + return super.onInitialSpawn(difficulty, data); + } + + @Override + public ITextComponent getDisplayName(){ + if(getOwner() != null){ + return new TextComponentTranslation(ISummonedCreature.NAMEPLATE_TRANSLATION_KEY, getOwner().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.showSummonedCreatureNames && getOwner() != null; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java new file mode 100644 index 00000000..6de76c7b --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java @@ -0,0 +1,157 @@ +package electroblob.wizardry.entity.living; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.EntityAgeable; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.ai.EntityAIAttackMelee; +import net.minecraft.entity.ai.EntityAIFollowOwner; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAILeapAtTarget; +import net.minecraft.entity.ai.EntityAILookIdle; +import net.minecraft.entity.ai.EntityAIOwnerHurtByTarget; +import net.minecraft.entity.ai.EntityAIOwnerHurtTarget; +import net.minecraft.entity.ai.EntityAISit; +import net.minecraft.entity.ai.EntityAISwimming; +import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.passive.EntityWolf; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumHand; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.World; + +/** Does not implement ISummonedCreature because it has different despawning rules and because EntityWolf already + * has an owner system. */ +public class EntitySpiritWolf extends EntityWolf { + + public EntitySpiritWolf(World par1World){ + + super(par1World); + this.experienceValue = 0; + } + + @Override + protected void initEntityAI(){ + + this.aiSit = new EntityAISit(this); + this.tasks.addTask(1, new EntityAISwimming(this)); + this.tasks.addTask(2, this.aiSit); + this.tasks.addTask(3, new EntityAILeapAtTarget(this, 0.4F)); + this.tasks.addTask(4, new EntityAIAttackMelee(this, 1.0D, true)); + this.tasks.addTask(5, new EntityAIFollowOwner(this, 1.0D, 10.0F, 2.0F)); + this.tasks.addTask(7, new EntityAIWander(this, 1.0D)); + this.tasks.addTask(9, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); + this.tasks.addTask(9, new EntityAILookIdle(this)); + this.targetTasks.addTask(1, new EntityAIOwnerHurtByTarget(this)); + this.targetTasks.addTask(2, new EntityAIOwnerHurtTarget(this)); + this.targetTasks.addTask(3, new EntityAIHurtByTarget(this, true, new Class[0])); + } + + @Override + public void onDeath(DamageSource source){ + + // Allows player to summon another spirit wolf once this one has died. + // NOTE: This has been known to work incorrectly. + if(this.getOwner() instanceof EntityPlayer && WizardData.get((EntityPlayer)this.getOwner()) != null){ + WizardData.get((EntityPlayer)this.getOwner()).hasSpiritWolf = false; + } + + super.onDeath(source); + } + + @Override + protected int getExperiencePoints(EntityPlayer p_70693_1_){ + return 0; + } + + @Override + public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, IEntityLivingData livingdata) { + + // Adds Particles on spawn. Due to client/server differences this cannot be done in the item. + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, this.posX - this.width/2 + this.rand.nextFloat()*width, this.posY + this.height*this.rand.nextFloat() + 0.2f, this.posZ - this.width/2 + this.rand.nextFloat()*width, 0, 0, 0, 48 + this.rand.nextInt(12), 0.8f, 0.8f, 1.0f); + } + } + + return livingdata; + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + // Adds a dust particle effect + if(this.worldObj.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, worldObj, this.posX - this.width/2 + this.rand.nextFloat()*width, this.posY + this.height*this.rand.nextFloat() + 0.2f, this.posZ - this.width/2 + this.rand.nextFloat()*width, 0, 0, 0, 0, 0.8f, 0.8f, 1.0f); + } + } + + @Override + public boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack) { + + if (this.isTamed()) + { + if (stack != null){ + + // Allows the owner (but not other players) to dispel the spirit wolf using a wand. + if(stack != null && stack.getItem() instanceof ItemWand && this.getOwner() == player && player.isSneaking()){ + // Prevents accidental double clicking. + if(this.ticksExisted > 20){ + for(int i=0;i<10;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX - this.width/2 + this.rand.nextFloat()*width, this.posY + this.height*this.rand.nextFloat() + 0.2f, this.posZ - this.width/2 + this.rand.nextFloat()*width, 0, 0, 0, 48 + this.rand.nextInt(12), 0.8f, 0.8f, 1.0f); + } + this.setDead(); + if(WizardData.get(player) != null){ + WizardData.get(player).hasSpiritWolf = false; + } + this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); + // This is necessary to prevent the wand's spell being cast when performing this action. + return true; + } + } + } + } + + return super.processInteract(player, hand, stack); + } + + @Override + public EntityWolf createChild(EntityAgeable par1EntityAgeable) + { + return null; + } + + @Override + protected Item getDropItem() + { + return null; + } + + @Override + public ITextComponent getDisplayName(){ + if(getOwner() != null){ + return new TextComponentTranslation(ISummonedCreature.NAMEPLATE_TRANSLATION_KEY, getOwner().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.showSummonedCreatureNames && getOwner() != null; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java new file mode 100644 index 00000000..204d95a0 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java @@ -0,0 +1,160 @@ +package electroblob.wizardry.entity.living; + +import java.util.Collections; +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.EntityAIAttackMelee; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAILookIdle; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.entity.effect.EntityLightningBolt; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.SoundEvent; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class EntityStormElemental extends EntitySummonedCreature implements ISpellCaster { + + private double AISpeed = 1.0; + + private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 30, 0); + + private static final List attack = Collections.singletonList(Spells.lightning_disc); + + public EntityStormElemental(World world){ + super(world); + } + + public EntityStormElemental(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world, x, y, z, caster, lifetime); + // For some reason this can't be in initEntityAI + this.tasks.addTask(0, this.spellAttackAI); + } + + @Override + protected void initEntityAI(){ + + this.tasks.addTask(1, new EntityAIAttackMelee(this, AISpeed, false)); + this.tasks.addTask(2, new EntityAIWander(this, AISpeed)); + this.tasks.addTask(3, new EntityAILookIdle(this)); + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.getTargetSelector())); + + this.setAIMoveSpeed((float)AISpeed); + } + + @Override + public boolean hasRangedAttack() { + return true; + } + + @Override + public List getSpells(){ + return attack; + } + + @Override + public SpellModifiers getModifiers(){ + return new SpellModifiers(); + } + + @Override + public Spell getContinuousSpell(){ + return Spells.none; + } + + @Override + public void setContinuousSpell(Spell spell){ + // Doesn't use continuous spells. + } + + @Override + protected void applyEntityAttributes(){ + super.applyEntityAttributes(); + this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(6.0D); + this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(AISpeed); + this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(30.0D); + this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(16.0D); + } + + @Override + protected SoundEvent getAmbientSound(){ + return SoundEvents.ENTITY_BLAZE_AMBIENT; + } + + @Override + protected SoundEvent getHurtSound(){ + return SoundEvents.ENTITY_BLAZE_HURT; + } + + @Override + protected SoundEvent getDeathSound(){ + return SoundEvents.ENTITY_BLAZE_DEATH; + } + + @Override + @SideOnly(Side.CLIENT) + public int getBrightnessForRender(float partialTicks){ + return 15728880; + } + + @Override + public float getBrightness(float partialTicks){ + return 1.0F; + } + + @Override + public void onLivingUpdate(){ + + if(this.ticksExisted % 120 == 1){ + this.playSound(WizardrySounds.SPELL_LOOP_WIND, 1.0f, 1.0f); + } + + if (this.rand.nextInt(24) == 0){ + this.playSound(SoundEvents.ENTITY_BLAZE_BURN, 1.0F + this.rand.nextFloat(), this.rand.nextFloat() * 0.7F + 0.3F); + } + + // Slow fall + if(!this.onGround && this.motionY < 0.0D){ + this.motionY *= 0.6D; + } + + if(worldObj.isRemote){ + + for(int i=0; i<2; ++i){ + worldObj.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0.0d, 0.0d, 0.0d, 0, 0, 0, 0); + } + + for(int i=0; i<10; i++){ + float brightness = rand.nextFloat()*0.2f; + double dy = this.rand.nextDouble() * (double)this.height; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE_ROTATING, worldObj, this.posX, this.posY + dy, this.posZ, 0, 0, 0, 20 + rand.nextInt(10), 0, brightness, brightness, false, 0.2f + 0.5f*dy); + } + } + + super.onLivingUpdate(); + } + + @Override + public void fall(float distance, float damageMultiplier){ + // Immune to fall damage. + } + + @Override + public void onStruckByLightning(EntityLightningBolt lightning){ + // Immune to lightning. + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java new file mode 100644 index 00000000..9ed6d48f --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java @@ -0,0 +1,144 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; +import java.util.UUID; + +import electroblob.wizardry.Wizardry; +import net.minecraft.entity.EntityCreature; +import net.minecraft.entity.EntityFlying; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +/** Abstract base implementation of {@link ISummonedCreature} which is the superclass to all custom summoned entities + * (i.e. entities that don't extend vanilla/mod creatures). Also serves as an example of how to correctly implement + * the above interface, and includes some non-critical method overrides which should be used for best results (xp, drops, + * and such like). Not to be confused with the old version of EntitySummonedCreature; that system has been replaced. + * @since Wizardry 1.2 + * @author Electroblob */ +public abstract class EntitySummonedCreature extends EntityCreature implements ISummonedCreature { + + // Field implementations + private int lifetime = 600; + private WeakReference casterReference; + private UUID casterUUID; + + // Setter + getter implementations + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID() { return casterUUID; } + @Override public void setCasterUUID(UUID uuid) { this.casterUUID = uuid; } + + /** + * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't + * matter because the client side entity immediately gets the lifetime value copied over to it by this class + * anyway. When extending this class, you must override this constructor or Minecraft won't like it, but there's + * no need to do anything inside it other than call super(). + */ + public EntitySummonedCreature(World world){ + super(world); + this.experienceValue = 0; + } + + /** + * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when + * extending this class (be sure to call super()) so that AI and other things can be added. + */ + public EntitySummonedCreature(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world); + this.setPosition(x, y, z); + this.casterReference = new WeakReference(caster); + this.experienceValue = 0; + this.lifetime = lifetime; + } + + // Implementations + + @Override + public void setRevengeTarget(EntityLivingBase entity){ + if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity); + } + + @Override + public void onUpdate(){ + super.onUpdate(); + this.updateDelegate(); + } + + @Override + public void onSpawn(){} + + @Override + public void onDespawn(){} + + @Override + public boolean hasParticleEffect() { + return false; + } + + @Override + protected boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack) { + // In this case, the delegate method determines whether super is called. + // Rather handily, we can make use of Java's short-circuiting method of evaluating OR statements. + return this.interactDelegate(player, hand, stack) || super.processInteract(player, hand, stack); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + // Recommended overrides + + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom onDespawn() method. + @Override protected boolean canDespawn(){ return false; } + + @Override + public boolean canAttackClass(Class entityType){ + // Returns true unless the given entity type is a flying entity and this entity only has melee attacks. + return !EntityFlying.class.isAssignableFrom(entityType) || this.hasRangedAttack(); + } + + // TODO: Backport the following two methods to 1.7.10. + @Override + public ITextComponent getDisplayName(){ + if(getCaster() != null){ + return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + } + + // Specific to EntitySummonedCreature, remove if copying + + /** Whether this summoned creature has a ranged attack. Used to test whether it should attack flying creatures. */ + public abstract boolean hasRangedAttack(); +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java new file mode 100644 index 00000000..d2a419c3 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -0,0 +1,803 @@ +package electroblob.wizardry.entity.living; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Random; +import java.util.Set; + +import com.google.common.base.Predicate; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WandHelper; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityAgeable; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAILookAtTradePlayer; +import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.ai.EntityAIOpenDoor; +import net.minecraft.entity.ai.EntityAIRestrictOpenDoor; +import net.minecraft.entity.ai.EntityAISwimming; +import net.minecraft.entity.ai.EntityAITradePlayer; +import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.ai.EntityAIWatchClosest2; +import net.minecraft.entity.effect.EntityLightningBolt; +import net.minecraft.entity.monster.IMob; +import net.minecraft.entity.passive.EntityVillager; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagInt; +import net.minecraft.nbt.NBTTagLong; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.village.MerchantRecipe; +import net.minecraft.village.MerchantRecipeList; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants.NBT; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import net.minecraftforge.fml.common.registry.VillagerRegistry.VillagerProfession; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.oredict.OreDictionary; + +public class EntityWizard extends EntityVillager implements ISpellCaster, IEntityAdditionalSpawnData { + + /* + * After much debugging, the error in the compiled mod (outside of eclipse) was traced back to this class, + * specifically the methods copied in from EntityVillager when I changed this class to extend it. This figures, + * since I had 1.2.1 working just fine before I did that, and it was the only thing I changed. Apparently, + * methods and fields with obfuscated names like func_129090_a can cause problems when compiled. One of the + * ones here was renamed and the other deleted since it was never called. Watch out for this in future (unless, + * of course, they are overriding something, in which case it should be fine). + */ + + // Extending EntityVillager turned out to be a pretty neat thing to do, since now zombies will attack wizards + + private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell(this, 0.5D, 14.0F, 30, 50); + + public int textureIndex = 0; + + /** The entity selector passed into the new AI methods. */ + protected Predicate targetSelector; + + /** Copy of EntityVillager's buyingList, renamed to avoid confusion. */ + private MerchantRecipeList trades; + private int timeUntilReset; + + /** addDefaultEquipmentAndRecipies is called if this is true */ + private boolean updateRecipes; + + /** Data parameter for the cooldown time for wizards healing themselves. */ + private static final DataParameter HEAL_COOLDOWN = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT); + /** Data parameter for the wizard's element. */ + private static final DataParameter ELEMENT = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT); + + // Field implementations + private List spells = new ArrayList(4); + private Spell continuousSpell; + + /** A set of the positions of the blocks that are part of this wizard's tower. */ + private Set towerBlocks; + + public EntityWizard(World world){ + super(world); + this.detachHome(); + // For some reason this can't be in initEntityAI + this.tasks.addTask(3, this.spellCastingAI); + } + + @Override + protected void entityInit(){ + super.entityInit(); + this.dataManager.register(HEAL_COOLDOWN, -1); + this.dataManager.register(ELEMENT, 0); + } + + @Override + protected void initEntityAI(){ + + this.tasks.addTask(0, new EntityAISwimming(this)); + this.tasks.addTask(1, new EntityAITradePlayer(this)); + this.tasks.addTask(1, new EntityAILookAtTradePlayer(this)); + this.tasks.addTask(4, new EntityAIRestrictOpenDoor(this)); + this.tasks.addTask(5, new EntityAIOpenDoor(this, true)); + this.tasks.addTask(6, new EntityAIMoveTowardsRestriction(this, 0.6D)); + this.tasks.addTask(7, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F)); + this.tasks.addTask(7, new EntityAIWatchClosest2(this, EntityWizard.class, 5.0F, 0.02F)); + this.tasks.addTask(7, new EntityAIWander(this, 0.6D)); + this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F)); + + this.targetSelector = new Predicate(){ + + public boolean apply(Entity entity){ + + // If the target is valid and not invisible... + if(entity != null && !entity.isInvisible() && WizardryUtilities.isValidTarget(EntityWizard.this, entity)){ + + //... and is a mob, a summoned creature ... + if((entity instanceof IMob || entity instanceof ISummonedCreature + // ... or in the whitelist ... + || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist).contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))) + // ... and isn't in the blacklist ... + && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist).contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))){ + // ... it can be attacked. + return true; + } + } + + return false; + } + }; + + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); + // By default, wizards don't attack players unless the player has attacked them. + this.targetTasks.addTask(0, new EntityAINearestAttackableTarget(this, EntityLiving.class, 0, false, true, this.targetSelector)); + } + + @Override + protected void applyEntityAttributes(){ + super.applyEntityAttributes(); + this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.5); + } + + private int getHealCooldown(){ + return this.dataManager.get(HEAL_COOLDOWN); + } + + private void setHealCooldown(int cooldown){ + this.dataManager.set(HEAL_COOLDOWN, cooldown); + } + + public Element getElement(){ + return Element.values()[this.dataManager.get(ELEMENT)]; + } + + public void setElement(Element element){ + this.dataManager.set(ELEMENT, element.ordinal()); + } + + @Override + public List getSpells(){ + return this.spells; + } + + @Override + public SpellModifiers getModifiers(){ + return new SpellModifiers(); + } + + @Override + public void setContinuousSpell(Spell spell){ + this.continuousSpell = spell; + } + + @Override + public Spell getContinuousSpell(){ + return this.continuousSpell; + } + + @Override + public void onLivingUpdate(){ + + super.onLivingUpdate(); + + // Still better to store this to a local variable as it's almost certainly more efficient. + int healCooldown = this.getHealCooldown(); + + // This is now done slightly differently because isPotionActive doesn't work on client here, meaning that when + // affected with arcane jammer and healCooldown == 0, whilst the wizard didn't actually heal or play the sound, + // the particles still spawned, and since healCooldown wasn't reset they spawned every tick until the arcane + // jammer wore off. + if(healCooldown == 0 && this.getHealth() < this.getMaxHealth() && this.getHealth() > 0 && !this.isPotionActive(WizardryPotions.arcane_jammer)){ + + // Healer wizards use greater heal. + this.heal(this.getElement() == Element.HEALING ? 8 : 4); + this.setHealCooldown(-1); + + // deathTime == 0 checks the wizard isn't currently dying + }else if(healCooldown == -1 && this.deathTime == 0){ + + // Heal particles + if(worldObj.isRemote){ + for(int i=0; i<10; i++){ + double d0 = (double)((float)this.posX + rand.nextFloat()*2 - 1.0F); + // Apparently the client side spawns the particles 1 block higher than it should... hence the - 0.5F. + double d1 = (double)((float)this.posY - 0.5F + rand.nextFloat()); + double d2 = (double)((float)this.posZ + rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, d0, d1, d2, 0, 0.1F, 0, 48 + rand.nextInt(12), 1.0f, 1.0f, 0.3f); + } + }else{ + if(this.getHealth() < 10){ + // Wizard heals himself more often if he has low health + this.setHealCooldown(150); + }else{ + this.setHealCooldown(400); + } + + this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); + } + } + + if(healCooldown > 0){ + this.setHealCooldown(healCooldown-1); + } + } + + @Override + protected void updateAITasks(){ + + if(!this.isTrading() && this.timeUntilReset > 0){ + + --this.timeUntilReset; + + if(this.timeUntilReset <= 0){ + + if(this.updateRecipes){ + + for(MerchantRecipe merchantrecipe : this.trades){ + + if(merchantrecipe.isRecipeDisabled()){ + // Increases the number of allowed uses of a disabled recipe by a random number. + merchantrecipe.increaseMaxTradeUses(this.rand.nextInt(6) + this.rand.nextInt(6) + 2); + } + } + + if(this.trades.size() < 12){ + this.addRandomRecipes(1); + } + + this.updateRecipes = false; + } + + this.addPotionEffect(new PotionEffect(MobEffects.REGENERATION, 200, 0)); + } + } + + // Super call removed because EntityVillager's version does things I don't want and the next one up is + // in EntityLivingBase and does nothing. + } + + @Override + public boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack) { + + // Debugging + //player.addChatComponentMessage(new TextComponentTranslation("wizard.debug", Spell.get(spells[1]).getDisplayName(), Spell.get(spells[2]).getDisplayName(), Spell.get(spells[3]).getDisplayName())); + + // When right-clicked with a spell book in creative, sets one of the spells to that spell + if(player.capabilities.isCreativeMode && stack != null && stack.getItem() instanceof ItemSpellBook){ + if(this.spells.size() >= 4 && Spell.get(stack.getItemDamage()).canBeCastByNPCs()){ + this.spells.set(rand.nextInt(3)+1, Spell.get(stack.getItemDamage())); + return true; + } + } + + // Won't trade with a player that has attacked them. + if (this.isEntityAlive() && !this.isTrading() && !this.isChild() && !player.isSneaking() && this.getAttackTarget() != player) + { + if (!this.worldObj.isRemote) + { + this.setCustomer(player); + player.displayVillagerTradeGui(this); + //player.displayGUIMerchant(this, this.getElement().getWizardName()); + } + + return true; + } + else + { + return false; + } + } + + @Override + public ITextComponent getDisplayName() { + return this.getElement().getWizardName(); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbt){ + + super.writeEntityToNBT(nbt); + + if (this.trades != null){ + nbt.setTag("trades", this.trades.getRecipiesAsTags()); + } + + nbt.setInteger("element", this.getElement().ordinal()); + nbt.setInteger("skin", this.textureIndex); + nbt.setTag("spells", WizardryUtilities.listToNBT(spells, spell -> new NBTTagInt(spell.id()))); + + if(this.towerBlocks != null && this.towerBlocks.size() > 0){ + nbt.setTag("towerBlocks", WizardryUtilities.listToNBT(this.towerBlocks, pos -> new NBTTagLong(pos.toLong()))); + } + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbt){ + + super.readEntityFromNBT(nbt); + + if(nbt.hasKey("trades")){ + NBTTagCompound nbttagcompound1 = nbt.getCompoundTag("trades"); + this.trades = new MerchantRecipeList(nbttagcompound1); + } + + this.setElement(Element.values()[nbt.getInteger("element")]); + this.textureIndex = nbt.getInteger("skin"); + this.spells = (List) WizardryUtilities.NBTToList(nbt.getTagList("spells", NBT.TAG_INT), + (NBTTagInt tag) -> Spell.get(tag.getInt())); + + this.towerBlocks = new HashSet(WizardryUtilities.NBTToList(nbt.getTagList("towerBlocks", + NBT.TAG_LONG), (NBTTagLong tag) -> BlockPos.fromLong(tag.getLong()))); + } + + @Override + protected boolean canDespawn(){ + return false; + } + + @Override + public boolean isTrading() + { + return this.getCustomer() != null; + } + + @Override + public void useRecipe(MerchantRecipe merchantrecipe){ + + merchantrecipe.incrementToolUses(); + this.livingSoundTime = -this.getTalkInterval(); + this.playSound(SoundEvents.ENTITY_VILLAGER_YES, this.getSoundVolume(), this.getSoundPitch()); + + // Achievements + if (this.getCustomer() != null) + { + this.getCustomer().addStat(WizardryAchievements.wizard_trade); + + if(merchantrecipe.getItemToSell().getItem() instanceof ItemSpellBook + && Spell.get(merchantrecipe.getItemToSell().getItemDamage()).tier == Tier.MASTER){ + this.getCustomer().addStat(WizardryAchievements.buy_master_spell); + } + } + + // Changed to a 4 in 5 chance of unlocking a new recipe. + if(this.rand.nextInt(5) > 0){ + this.timeUntilReset = 40; + this.updateRecipes = true; + + if (this.getCustomer() != null) + { + this.getCustomer().getName(); + } + else + { + } + } + } + + // This is called from the gui in order to display the recipes (no surprise there), and this is actually where + // the initialisation is done, i.e. the trades don't actually exist until some player goes to trade with the + // villager, at which point the first is added. + @Override + public MerchantRecipeList getRecipes(EntityPlayer par1EntityPlayer){ + + if(this.trades == null){ + + this.trades = new MerchantRecipeList(); + + // All wizards will buy spell books + ItemStack anySpellBook = new ItemStack(WizardryItems.spell_book, 1, OreDictionary.WILDCARD_VALUE); + ItemStack crystalStack = new ItemStack(WizardryItems.magic_crystal, 5); + + // NOTE: For wizardry 1.2, increase the number of uses of this trade. The default is 7, for reference. + this.trades.add(new MerchantRecipe(anySpellBook, crystalStack)); + + this.addRandomRecipes(3); + } + + return this.trades; + } + + /** + * This is called once on initialisation and then once each time the wizard gains new trades (the particle thingy). + */ + private void addRandomRecipes(int numberOfItemsToAdd){ + + MerchantRecipeList merchantrecipelist; + merchantrecipelist = new MerchantRecipeList(); + + for(int i=0; i spells = Spell.getSpells(new Spell.TierElementFilter(tier, null)); + // All enabled spells of the given tier that match this wizard's element + List specialismSpells = Spell.getSpells(new Spell.TierElementFilter(tier, this.getElement())); + + // This code is sooooooo much neater with the new filter system! + switch(tier){ + + case BASIC: + randomiser = rand.nextInt(5); + if(randomiser < 4 && !spells.isEmpty()){ + if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){ + // This means it is more likely for spell books sold to be of the same element as the wizard if the wizard has an element. + return new ItemStack(WizardryItems.spell_book, 1, specialismSpells.get(rand.nextInt(specialismSpells.size())).id()); + }else{ + return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).id()); + } + }else{ + if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ + // This means it is more likely for wands sold to be of the same element as the wizard if the wizard has an element. + return new ItemStack(WizardryUtilities.getWand(tier, this.getElement())); + }else{ + return new ItemStack(WizardryUtilities.getWand(tier, Element.values()[rand.nextInt(Element.values().length)])); + } + } + + case APPRENTICE: + randomiser = rand.nextInt(Wizardry.settings.discoveryMode ? 12 : 10); + if(randomiser < 5 && !spells.isEmpty()){ + if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){ + // This means it is more likely for spell books sold to be of the same element as the wizard if the wizard has an element. + return new ItemStack(WizardryItems.spell_book, 1, specialismSpells.get(rand.nextInt(specialismSpells.size())).id()); + }else{ + return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).id()); + } + }else if(randomiser < 6){ + if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ + // This means it is more likely for wands sold to be of the same element as the wizard if the wizard has an element. + return new ItemStack(WizardryUtilities.getWand(tier, this.getElement())); + }else{ + return new ItemStack(WizardryUtilities.getWand(tier, Element.values()[rand.nextInt(Element.values().length)])); + } + }else if(randomiser < 8){ + return new ItemStack(WizardryItems.arcane_tome, 1, 1); + }else if(randomiser < 10){ + EntityEquipmentSlot slot = WizardryUtilities.ARMOUR_SLOTS[rand.nextInt(WizardryUtilities.ARMOUR_SLOTS.length)]; + if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ + // This means it is more likely for armour sold to be of the same element as the wizard if the wizard has an element. + return new ItemStack(WizardryUtilities.getArmour(this.getElement(), slot)); + }else{ + return new ItemStack(WizardryUtilities.getArmour(Element.values()[rand.nextInt(Element.values().length)], slot)); + } + }else{ + // Don't need to check for discovery mode here since it is done above + return new ItemStack(WizardryItems.identification_scroll); + } + + case ADVANCED: + randomiser = rand.nextInt(12); + if(randomiser < 5 && !spells.isEmpty()){ + if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){ + // This means it is more likely for spell books sold to be of the same element as the wizard if the wizard has an element. + return new ItemStack(WizardryItems.spell_book, 1, specialismSpells.get(rand.nextInt(specialismSpells.size())).id()); + }else{ + return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).id()); + } + }else if(randomiser < 6){ + if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ + // This means it is more likely for wands sold to be of the same element as the wizard if the wizard has an element. + return new ItemStack(WizardryUtilities.getWand(tier, this.getElement())); + }else{ + return new ItemStack(WizardryUtilities.getWand(tier, Element.values()[rand.nextInt(Element.values().length)])); + } + }else if(randomiser < 8){ + return new ItemStack(WizardryItems.arcane_tome, 1, 2); + }else{ + List upgrades = new ArrayList(WandHelper.getSpecialUpgrades()); + randomiser = rand.nextInt(upgrades.size()); + return new ItemStack(upgrades.get(randomiser)); + } + + case MASTER: + // If a regular wizard rolls a master trade, it can only be a simple master wand or a tome of arcana + randomiser = this.getElement() != Element.MAGIC ? rand.nextInt(8) : 5 + rand.nextInt(3); + + if(randomiser < 5 && this.getElement() != Element.MAGIC && !specialismSpells.isEmpty()){ + // Master spells can only be sold by a specialist in that element. + return new ItemStack(WizardryItems.spell_book, 1, specialismSpells.get(rand.nextInt(specialismSpells.size())).id()); + + }else if(randomiser < 6){ + if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ + // Master elemental wands can only be sold by a specialist in that element. + return new ItemStack(WizardryUtilities.getWand(tier, this.getElement())); + }else{ + return new ItemStack(WizardryItems.master_wand); + } + }else{ + return new ItemStack(WizardryItems.arcane_tome, 1, 3); + } + } + + return new ItemStack(Blocks.STONE); + } + + @Override + public void setProfession(VillagerProfession prof) { + // Disables Forge's stuff. + } + + @Override + public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, IEntityLivingData livingdata){ + + livingdata = super.onInitialSpawn(difficulty, livingdata); + + textureIndex = this.rand.nextInt(6); + + if(rand.nextBoolean()){ + this.setElement(Element.values()[rand.nextInt(Element.values().length - 1) + 1]); + }else{ + this.setElement(Element.MAGIC); + } + + Element element = this.getElement(); + + // Adds armour. + for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ + this.setItemStackToSlot(slot, new ItemStack(WizardryUtilities.getArmour(element, slot))); + } + + // Default chance is 0.085f, for reference. + for(EntityEquipmentSlot slot : EntityEquipmentSlot.values()) this.setDropChance(slot, 0.0f); + + // All wizards know magic missile, even if it is disabled. + spells.add(Spells.magic_missile); + + Tier maxTier = populateSpells(spells, element, 3, rand); + + // Now done after the spells so it can take the tier into account. + this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(WizardryUtilities.getWand(maxTier, element))); + + return livingdata; + } + + /** + * Adds n random spells to the given list. The spells will be of the given element if possible. Extracted as a + * separate function since it was the same in both EntityWizard and EntityEvilWizard. + * @param spells The spell list to be populated. + * @param e The element that the spells should belong to, or {@link Element#MAGIC} for a random element each time. + * @param n The number of spells to add. + * @param random A random number generator to use. + * @return The tier of the highest-tier spell that was added to the list. + */ + static Tier populateSpells(List spells, Element e, int n, Random random){ + + // This is the tier of the highest tier spell added. + Tier maxTier = Tier.BASIC; + + List npcSpells = Spell.getSpells(Spell.npcSpells); + + for(int i=0; i<3; i++){ + + Tier tier; + // If the wizard has no element, it picks a random one each time. + Element element = e == Element.MAGIC ? Element.values()[random.nextInt(Element.values().length)] : e; + + int randomiser = random.nextInt(20); + + // Uses its own special weighting + if(randomiser < 10){ + tier = Tier.BASIC; + }else if(randomiser < 16){ + tier = Tier.APPRENTICE; + }else{ + tier = Tier.ADVANCED; + } + + if(tier.ordinal() > maxTier.ordinal()) maxTier = tier; + + // Finds all the spells of the chosen tier and element + List list = Spell.getSpells(new Spell.TierElementFilter(tier, element)); + // Keeps only spells which can be cast by NPCs + list.retainAll(npcSpells); + // Removes spells that the wizard already has + list.removeAll(spells); + + // Ensures the tier chosen actually has spells in it. (isEmpty() is exactly the same as size() == 0) + if(list.isEmpty()){ + // If there are no spells applicable, tier and element restrictions are removed to give maximum + // possibility of there being an applicable spell. + list = npcSpells; + // Removes spells that the wizard already has + list.removeAll(spells); + } + + // If the list is still empty now, there must be less than 3 enabled spells that can be cast by wizards + // (excluding magic missile). In this case, having empty slots seems reasonable. + if(!list.isEmpty()) spells.add(list.get(random.nextInt(list.size()))); + + } + + return maxTier; + } + + @Override + public void writeSpawnData(ByteBuf data){ + data.writeInt(textureIndex); + } + + @Override + public void readSpawnData(ByteBuf data){ + textureIndex = data.readInt(); + } + + @Override + public boolean attackEntityFrom(DamageSource source, float damage){ + + if(source.getEntity() instanceof EntityPlayer){ + ((EntityPlayer)source.getEntity()).addStat(WizardryAchievements.anger_wizard); + } + + return super.attackEntityFrom(source, damage); + } + + /** + * Sets the list of blocks that are part of this wizard's tower. If a player breaks any of these blocks, the wizard + * will get angry and attack them. + * @param blocks A Set of BlockPos objects representing the blocks in the tower. + */ + public void setTowerBlocks(Set blocks){ + this.towerBlocks = blocks; + } + + /** + * Tests whether the block at the given coordinates is part of this wizard's tower. + * @param x + * @param y + * @param z + * @return + */ + public boolean isBlockPartOfTower(BlockPos pos){ + if(this.towerBlocks == null) return false; + // Uses .equals() rather than == so this will work fine. + return this.towerBlocks.contains(pos); + } + + // EntityVillager overrides (that don't add features) + + @Override public boolean isMating(){ return false; } + @Override public void setMating(boolean p_70947_1_){} + @Override public void setPlaying(boolean p_70939_1_){} + @Override public boolean isPlaying(){ return false; } + @Override public void setLookingForHome(){} + // Doesn't say it, but this is in fact nullable. + @Override public EntityVillager createChild(EntityAgeable par1EntityAgeable){ return null; } + @SideOnly(Side.CLIENT) + @Override public void setRecipes(MerchantRecipeList par1MerchantRecipeList){} + @Override + public void onStruckByLightning(EntityLightningBolt lightningBolt){ + // Restores the normal behaviour, replacing EntityVillager's witch conversion. + this.attackEntityFrom(DamageSource.lightningBolt, 5.0F); + // Entity's version does something strange with the private fire variable, but since I don't have access this + // will probably be fine. + this.setFire(8); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java new file mode 100644 index 00000000..c1ac3a7a --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java @@ -0,0 +1,175 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; +import java.util.UUID; + +import electroblob.wizardry.Wizardry; +import net.minecraft.entity.EntityFlying; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAIMoveThroughVillage; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.monster.EntityZombie; +import net.minecraft.entity.monster.ZombieType; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.World; + +public class EntityZombieMinion extends EntityZombie implements ISummonedCreature { + + // Field implementations + private int lifetime = 600; + private WeakReference casterReference; + private UUID casterUUID; + + // Setter + getter implementations + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID() { return casterUUID; } + @Override public void setCasterUUID(UUID uuid) { this.casterUUID = uuid; } + + /** + * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't + * matter because the client side entity immediately gets the lifetime value copied over to it by this class + * anyway. When extending this class, you must override this constructor or Minecraft won't like it, but there's + * no need to do anything inside it other than call super(). + */ + public EntityZombieMinion(World world){ + super(world); + this.experienceValue = 0; + } + + /** + * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when + * extending this class (be sure to call super()) so that AI and other things can be added. + */ + public EntityZombieMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ + super(world); + this.setPosition(x, y, z); + this.casterReference = new WeakReference(caster); + this.experienceValue = 0; + this.lifetime = lifetime; + } + + // EntityZombie overrides (EntityZombie is a long class so there are lots of these) + + @Override + protected void applyEntityAI() + { + this.tasks.addTask(6, new EntityAIMoveThroughVillage(this, 1.0D, false)); + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + 0, false, true, this.getTargetSelector())); + } + + @Override public boolean isChild(){ return false; } + @Override public void setChild(boolean childZombie){} + @Override public ZombieType getZombieType(){ return ZombieType.NORMAL; } + @Override public boolean isVillager(){ return false; } + @Override public net.minecraftforge.fml.common.registry.VillagerRegistry.VillagerProfession getVillagerTypeForge(){ return null; } + @Override protected void setEquipmentBasedOnDifficulty(DifficultyInstance difficulty){} // They don't have equipment! + @Override public void onKillEntity(EntityLivingBase entityLivingIn){} // Turns villagers to zombies in EntityZombie + @Override protected void startConversion(int ticks){} + @Override public boolean isConverting(){ return false; } + @Override protected void convertToVillager(){} + @Override protected int getConversionTimeBoost(){ return 0; } + @Override public void setChildSize(boolean isChild){} + + // Implementations + + @Override + public void setRevengeTarget(EntityLivingBase entity){ + if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity); + } + + @Override + public void onUpdate(){ + super.onUpdate(); + this.updateDelegate(); + } + + @Override + public void onSpawn(){ + this.spawnParticleEffect(); + } + + @Override + public void onDespawn(){ + this.spawnParticleEffect(); + } + + private void spawnParticleEffect(){ + if(this.worldObj.isRemote){ + for(int i=0;i<15;i++){ + this.worldObj.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + this.rand.nextFloat(), this.posY + 1 + this.rand.nextFloat(), this.posZ + this.rand.nextFloat(), 0, 0, 0); + } + } + } + + @Override + public boolean hasParticleEffect() { + return true; + } + + @Override + public boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack) { + // In this case, the delegate method determines whether super is called. + // Rather handily, we can make use of Java's 'stop as soon as you find true' method of evaluating OR statements. + return this.interactDelegate(player, hand, stack) || super.processInteract(player, hand, stack); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + // Recommended overrides + + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. + @Override protected boolean canDespawn(){ return false; } + + @Override + public boolean canAttackClass(Class entityType){ + // Returns true unless the given entity type is a flying entity. + return !EntityFlying.class.isAssignableFrom(entityType); + } + + @Override + public ITextComponent getDisplayName(){ + if(getCaster() != null){ + return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/living/IIntelligentSpellCaster.java b/src/main/java/electroblob/wizardry/entity/living/IIntelligentSpellCaster.java new file mode 100644 index 00000000..1bcb7c86 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/IIntelligentSpellCaster.java @@ -0,0 +1,20 @@ +package electroblob.wizardry.entity.living; + +import java.util.List; + +import electroblob.wizardry.spell.Spell; + +/** [NYI] Interface for entities that can select between spells based on their current circumstances, to be used in + * conjunction with {@link EntityAISelectSpell}. */ +public interface IIntelligentSpellCaster extends ISpellCaster { + + /** Called from {@link EntityAISelectSpell} to set the spells that the entity can use in its current situation. + * Implementors should assign the given list to some internal field and retrieve it when {@link #getSpells()} is + * called. */ + public void setCurrentSpells(List spells); + + /** Returns a list of spells that this entity 'knows'. The entity's current spell will be selected from this list + * based on the current situation: whether it is attacking, its health, etc. Most likely, you will want to return a + * constant list, but it may change for some reason - perhaps if the entity 'learns' a new spell. */ + public List getKnownSpells(); +} diff --git a/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java b/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java new file mode 100644 index 00000000..ce2733df --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java @@ -0,0 +1,61 @@ +package electroblob.wizardry.entity.living; + +import java.util.List; + +import javax.annotation.Nonnull; + +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; + +/** Interface for entities that can cast spells. Mainly intended for use by wizard-type entities, but can be + * implemented by any subclass of EntityLiving. Designed to be as flexible as possible - ranging from the simplest + * use of giving an entity a specific spell as an attack, to a complex AI which selects different spell types + * depending on the situation. The only restriction is that the spells must be castable by NPCs. + *

    + * This is intended for entities that use {@link EntityAIAttackSpell}. If so, all the spell casting code (including + * packets) is handled by that class, and all the implementor needs to do is decide which spell(s) to select. + *

    + * This class also allows Wizardry to do all the syncing necessary for continuous spell casting. All the implementor + * needs to do is store the actual fields involved. + */ +/* Perhaps this should be a capability? Though I can't help thinking they're mainly for attaching data to vanilla + * classes, rather than custom ones. For now, the main purpose of this is to centralise code within wizardry itself, + * and I may as well make it an API feature - but I'm not writing a capability unless someone sees a reason to attach + * it to a class they don't own, and I don't see that happening anytime soon. */ +// For even more fun, combine this with an ISummonedCreature and have skeletons that can cast spells! +public interface ISpellCaster { + + /** + * Called each time the entity attacks to get the spells that can be cast. For simple implementations, just + * return a list of size one containing the spell that the entity uses as an attack, perhaps performing some + * simple logic within this method. For more intelligent implementations based on spell types, consider using + * {@link IIntelligentSpellCaster} instead. + * @return A list of {@link Spell} instances. A random spell from this list will be cast when the entity attacks. + * The list will not be modified by the AI class and can therefore be an immutable list. The spells in the list + * must be castable by NPCs (i.e. {@link Spell#canBeCastByNPCs()} returns true). + */ + @Nonnull + public List getSpells(); + + /** + * Called each time the entity attacks to get the modifiers to apply to the spell. + * @return A {@link SpellModifiers} object representing the modifiers to apply to the spell. If no modifiers are required, + * pass in an empty {@code SpellModifiers} object. + */ + @Nonnull + public SpellModifiers getModifiers(); + + /** Returns the continuous spell that is currently being cast, or the None spell if there is none. Implementors should simply + * store this as a private field and return it here. Will be synced by the AI class, but whether it is saved to NBT + * is up to you. If the implementing class does not deal with continuous spells, just return {@link Spells#none}. If the + * implementing class only ever uses one continuous spell, do not just return that spell; the field must still + * be stored. */ + @Nonnull + public Spell getContinuousSpell(); + + /** Sets the continuous spell that is currently being cast, or the None spell if there is none. Implementors should simply + * store this as a private field and assign it here. Will be synced by the AI class, but whether it is saved to NBT + * is up to you. If the implementing class does not deal with continuous spells, leave this method blank. */ + public void setContinuousSpell(Spell spell); +} diff --git a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java new file mode 100644 index 00000000..cc5a3a35 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java @@ -0,0 +1,278 @@ +package electroblob.wizardry.entity.living; + +import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.Locale; +import java.util.UUID; + +import javax.annotation.Nullable; + +import com.google.common.base.Predicate; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.WizardryEventHandler; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.IMob; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumHand; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; + +/** Interface for all summoned creatures. The code for summoned creatures has been overhauled in Wizardry 1.2, and this + * interface allows summoned creatures to extend vanilla (or indeed modded) entity classes, so EntitySummonedZombie + * now extends EntityZombie, for example. This change has two major benefits: + *

    + * - There is no longer any need for separate render classes, because summoned creatures are now instances of vanilla + * types. You don't even need to assign a render class because the supertype should already be assigned the correct one.
    + * - Summoned creature classes are now much more robust when it comes to changes between Minecraft versions, since none + * of the vanilla code needs to be copied. + *

    + * Summoned creatures that do not emulate vanilla entities do not directly implement this interface. Instead, they + * should extend the abstract base implementation, {@link EntitySummonedCreature}. + *

    + * All damage dealt by ISummonedCreature instances is redirected via {@link WizardryEventHandler#onLivingAttackEvent( + * net.minecraftforge.event.entity.living.LivingAttackEvent) WizardryEventHandler.onLivingAttackEvent(LivingAttackEvent)} + * and replaced by an instance of {@link electroblob.wizardry.util.IElementalDamage IElementalDamage} with the summoner + * of that creature as the source rather than the creature itself. This means that kills by summoned creatures register + * as player kills, dropping xp and rare loot. + *

    + * Though this system is a lot better than the previous system, it is not a perfect solution. The old + * EntitySummonedCreature class overrode some methods from Entity in order to add shared functionality, but this cannot + * be done with an interface. To get around this problem, this interface contains 5 delegate methods that do the same + * things, with the aim of centralising as much code as possible, even though it is not automatically applied. + * Implementing classes must override the corresponding methods from Entity, and within them, call the appropriate + * delegate method in this interface. It is impossible to enforce this condition, but the summoned creature will not + * work properly unless it is adhered to. The position of the delegate method call is unimportant, but by convention + * it is usually at the start of the calling method, which avoids it being unintentionally skipped by a return statement. + *

    + * It is recommended that when implementing this interface, you begin by copying {@link EntitySummonedCreature} to ensure + * all the relevant methods are duplicated. You can then change the superclass, override any additional methods and add + * functionality to any that are already overridden. You will always want to override the AI methods at the very least. + *

    + * Due to the limitations of interfaces, some methods that really ought to be protected are public. These are clearly + * marked as 'Internal, DO NOT CALL'. Don't call them, only implement them. + * @since Wizardry 1.2 + * @author Electroblob */ +/* + * Quite honestly, this is not what default methods are really for. However, this is modding, and in modding some + * sacrifices have to be made when it comes to Java style - because adding on to a pre-existing program is not a + * good way of doing this sort of thing anyway, but we have no choice about that! + */ +public interface ISummonedCreature extends IEntityAdditionalSpawnData { + + // Remember that ALL fields are static and final in interfaces, even if they don't explicitly state that. + String NAMEPLATE_TRANSLATION_KEY = "entity.wizardry.summonedcreature.nameplate"; + + // Setters and getters. The subclass fields that these access should be private. + + /** Sets the lifetime of the summoned creature in ticks. */ + void setLifetime(int ticks); + + /** Returns the lifetime of the summoned creature in ticks. Allows primarily for duration multiplier support, but + * also for example the skeleton legion spell which lasts for 60 seconds instead of the usual 30. Syncing and saving + * is done automatically. As of Wizardry 1.2, despawning is handled in ISummonedCreature; see + * {@link ISummonedCreature#onDespawn()} for details. */ + int getLifetime(); + + /** Sets the WeakReference object which refers to the owner of this summoned creature. Internal, don't call + * unless you know what you are doing. */ + void setCasterReference(WeakReference reference); + + /** Returns a WeakReference object which refers to the owner of this summoned creature. Subclasses should store this + * as a private field. This may be null; as such it is preferable to use {@link ISummonedCreature#getCaster()} to get + * the caster object itself. */ + @Nullable + WeakReference getCasterReference(); + + /** Internal, DO NOT CALL. */ + void setCasterUUID(UUID uuid); + /** Internal, DO NOT CALL. This is for loading purposes only and is not usually synchronised. */ + UUID getCasterUUID(); + + /** Returns the EntityLivingBase that summoned this creature, or null if it no longer exists. Cases where the + * entity may no longer exist are: entity died or was deleted, mob despawned, player logged out, entity teleported + * to another dimension, or this creature simply had no caster in the first place. This is the correct method + * to use to get the owner of this summoned creature. */ + @Nullable + default EntityLivingBase getCaster(){ + return getCasterReference() == null ? null : getCasterReference().get(); + } + + // Miscellaneous + + /** + * Called by the server when constructing the spawn packet. + * Data should be added to the provided stream. + * Implementors must call super when overriding. + * + * @param buffer The packet data stream + */ + @Override + default void writeSpawnData(ByteBuf buffer) { + buffer.writeInt(getCaster() != null ? getCaster().getEntityId() : -1); + buffer.writeInt(getLifetime()); + } + + /** + * Called by the client when it receives a Entity spawn packet. + * Data should be read out of the stream in the same way as it was written. + * Implementors must call super when overriding. + * + * @param additionalData The packet data stream + */ + @Override + default void readSpawnData(ByteBuf buffer) { + int id = buffer.readInt(); + // We're on the client side here, so we can safely use Minecraft.getMinecraft().theWorld via proxies. + if(id > -1) setCasterReference(new WeakReference((EntityLivingBase)Wizardry.proxy.getTheWorld().getEntityByID(id))); + setLifetime(buffer.readInt()); + } + + /** + * Shorthand for {@link WizardryUtilities#isValidTarget(Entity, Entity)}, with the owner of this creature as the + * attacker. Also allows implementors to override it if they wish to do so. + */ + default boolean isValidTarget(Entity target){ + return WizardryUtilities.isValidTarget(this.getCaster(), target); + } + + /** Returns a entity selector to be passed into AI methods. Normally, this should not be overridden, but it is + * possible for implementors to override this in order to do something special when selecting a target. */ + default Predicate getTargetSelector(){ + + return new Predicate(){ + + public boolean apply(Entity entity){ + // TODO: Backport invisibility check (also in wizards) + // If the target is valid and not invisible... + if(!entity.isInvisible() && isValidTarget(entity)){ + + //... and is a player, they can be attacked, since players can't be in the whitelist or the blacklist. + if(entity instanceof EntityPlayer) return true; + + //... and is a mob, a summoned creature, a wizard ... + if((entity instanceof IMob || entity instanceof ISummonedCreature || (entity instanceof EntityWizard && !(getCaster() instanceof EntityWizard)) + // ... or in the whitelist ... + || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist).contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))) + // ... and isn't in the blacklist ... + && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist).contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))){ + // ... it can be attacked. + return true; + } + } + + return false; + } + }; + } + + /** + * Called when this creature has existed for 1 tick, effectively when it has just been spawned. Normally used + * to add particles, sounds, etc. + */ + void onSpawn(); + + /** + * Called when this summoned creature vanishes. Normally used to add particles, sounds, etc. + */ + void onDespawn(); + + /** Whether this creature should spawn a subtle black swirl particle effect while alive. */ + boolean hasParticleEffect(); + + /** Called from the event handler after the damage change is applied. Does nothing by default, but can be overridden + * to do something when a successful attack is made. This was added because the event-based damage source system + * can cause parts of attackEntityAsMob not to fire, since attackEntityFrom is intercepted and canceled. + *

    + * Usage examples: {@link EntitySliverfishMinion} uses this to summon more silverfish if the target is killed, + * {@link EntitySkeletonMinion} and {@link EntitySpiderMinion} use this to add potion effects to the target. */ + default void onSuccessfulAttack(EntityLivingBase target){}; + + // Delegates + + /** Implementors should call this from writeEntityToNBT. Can be overridden as long as super is called, but there's + * very little point in doing that since anything extra could just be added to writeEntityToNBT anyway. */ + default void writeNBTDelegate(NBTTagCompound tagcompound){ + if(this.getCaster() != null){ + tagcompound.setUniqueId("casterUUID", this.getCaster().getUniqueID()); + } + tagcompound.setInteger("lifetime", getLifetime()); + } + + /** Implementors should call this from readEntityFromNBT. Can be overridden as long as super is called, but there's + * very little point in doing that since anything extra could just be added to readEntityFromNBT anyway. */ + default void readNBTDelegate(NBTTagCompound tagcompound){ + this.setCasterUUID(tagcompound.getUniqueId("casterUUID")); + this.setLifetime(tagcompound.getInteger("lifetime")); + } + + /** Implementors should call this from setRevengeTarget, and call super.setRevengeTarget if and only if this method + * returns true. */ + default boolean shouldRevengeTarget(EntityLivingBase entity){ + // Allows the config to prevent minions from revenge-targeting their owners. + return entity != this.getCaster() || Wizardry.settings.minionRevengeTargeting; + } + + /** Implementors should call this from onUpdate. Can be overridden as long as super is called, but there's + * very little point in doing that since anything extra could just be added to onUpdate anyway. */ + default void updateDelegate(){ + + if(!(this instanceof Entity)) throw new ClassCastException("Implementations of ISummonedCreature must extend Entity!"); + + Entity thisEntity = ((Entity)this); + + if(this.getCaster() == null && this.getCasterUUID() != null){ + Entity entity = WizardryUtilities.getEntityByUUID(thisEntity.worldObj, getCasterUUID()); + if(entity instanceof EntityLivingBase){ + this.setCasterReference(new WeakReference((EntityLivingBase)entity)); + } + } + + if(thisEntity.ticksExisted == 1){ + this.onSpawn(); + } + + if(thisEntity.ticksExisted > this.getLifetime() && this.getLifetime() != -1){ + this.onDespawn(); + thisEntity.setDead(); + } + + if(this.hasParticleEffect() && thisEntity.worldObj.isRemote && thisEntity.worldObj.rand.nextInt(8) == 0) + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, thisEntity.worldObj, thisEntity.posX, thisEntity.posY + thisEntity.worldObj.rand.nextDouble()*1.5, thisEntity.posZ, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); + + } + + /** Implementors should call this from processInteract, and call super.processInteract if and only if this method + * returns false. */ + default boolean interactDelegate(EntityPlayer player, EnumHand hand, ItemStack stack) { + + WizardData properties = WizardData.get(player); + // Selects one of the player's minions. + if(player.isSneaking() && stack != null && stack.getItem() instanceof ItemWand){ + + if(!player.worldObj.isRemote && properties != null && this.getCaster() == player){ + + if(properties.selectedMinion != null && properties.selectedMinion.get() == this){ + // Deselects the selected minion if right-clicked again + properties.selectedMinion = null; + }else{ + // Selects this minion + properties.selectedMinion = new WeakReference(this); + } + properties.sync(); + } + return true; + } + + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityBomb.java new file mode 100644 index 00000000..f383ca21 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityBomb.java @@ -0,0 +1,59 @@ +package electroblob.wizardry.entity.projectile; + +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; + +/** + * Same as {@link EntityMagicProjectile}, but with an additional blast multiplier field which is synced and saved to + * allow for the spread of particles to be changed depending on the blast area. + * @author Electroblob + * @since Wizardry 1.2 + */ +public abstract class EntityBomb extends EntityMagicProjectile implements IEntityAdditionalSpawnData { + + /** The entity blast multiplier. This is now synced and saved centrally from {@link EntityBomb}. */ + public float blastMultiplier = 1.0f; + + public EntityBomb(World world) { + super(world); + } + + public EntityBomb(World world, EntityLivingBase thrower) { + super(world, thrower); + } + + public EntityBomb(World world, EntityLivingBase thrower, float damageMultiplier, float blastMultiplier) { + super(world, thrower, damageMultiplier); + this.blastMultiplier = blastMultiplier; + } + + public EntityBomb(World par1World, double par2, double par4, double par6) { + super(par1World, par2, par4, par6); + } + + @Override + public void writeSpawnData(ByteBuf buffer) { + buffer.writeFloat(blastMultiplier); + } + + @Override + public void readSpawnData(ByteBuf buffer) { + blastMultiplier = buffer.readFloat(); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + blastMultiplier = nbttagcompound.getFloat("blastMultiplier"); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + nbttagcompound.setFloat("blastMultiplier", blastMultiplier); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java new file mode 100644 index 00000000..1ba45a28 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java @@ -0,0 +1,88 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityDarknessOrb extends EntityMagicProjectile +{ + public EntityDarknessOrb(World par1World) + { + super(par1World); + } + + public EntityDarknessOrb(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntityDarknessOrb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier); + } + + public EntityDarknessOrb(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + @Override + protected float getSpeed(){ + return 0.5F; + } + + @Override + protected void onImpact(RayTraceResult RayTraceResult) + { + Entity target = RayTraceResult.entityHit; + + if (target != null && !MagicDamage.isEntityImmune(DamageType.WITHER, target)) + { + float damage = 8 * damageMultiplier; + + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.WITHER).setProjectile(), damage); + + if(target instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.WITHER, target)) ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.WITHER, 150, 1)); + + this.playSound(SoundEvents.ENTITY_WITHER_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + } + + this.setDead(); + } + + public void onUpdate(){ + + super.onUpdate(); + + if(worldObj.isRemote){ + float brightness = rand.nextFloat()*0.2f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0, 20 + rand.nextInt(10), brightness, 0.0f, brightness); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); + } + + if(this.ticksExisted > 150){ + this.setDead(); + } + + // Cancels out the slowdown effect in EntityThrowable + this.motionX /= 0.99; + this.motionY /= 0.99; + this.motionZ /= 0.99; + } + + /** + * Gets the amount of gravity to apply to the thrown entity with each tick. + */ + protected float getGravityVelocity() + { + return 0.0F; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java new file mode 100644 index 00000000..3625f995 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java @@ -0,0 +1,95 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.world.World; + +public class EntityDart extends EntityMagicArrow +{ + /** Basic shell constructor. Should only be used by the client. */ + public EntityDart(World world) { + super(world); + } + + /** Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this + * constructor and then call setVelocity() as that method is, bizarrely, client-side only. */ + public EntityDart(World world, double x, double y, double z) + { + super(world, x, y, z); + } + + /** Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be altered + * slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on easy, 6 on + * normal and 2 on hard difficulty. */ + public EntityDart(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, float damageMultiplier) + { + super(world, caster, target, speed, aimingError, damageMultiplier); + } + + /** Creates a projectile pointing in the direction the caster is looking, with the given speed. + * USE THIS CONSTRUCTOR FOR NORMAL SPELLS. */ + public EntityDart(World world, EntityLivingBase caster, float speed, float damageMultiplier) + { + super(world, caster, speed, damageMultiplier); + } + + @Override + public void onEntityHit(EntityLivingBase entityHit){ + //Adds a weakness effect to the target. + entityHit.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 200, 1, false, false)); + this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + } + + @Override + public void onBlockHit(){ + this.playSound(SoundEvents.ENTITY_ARROW_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + } + + @Override + public void tickInAir(){ + + if(this.worldObj.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, worldObj, this.posX, this.posY, this.posZ, 0, -0.03, 0, 10 + rand.nextInt(5)); + } + } + + // Replicates the original behaviour of staying stuck in block for a few seconds before disappearing. + @Override + public void tickInGround(){ + if(this.ticksInGround > 60){ + this.setDead(); + } + } + + @Override + public double getDamage(){ + return 4.0d; + } + + @Override + public DamageType getDamageType(){ + return DamageType.MAGIC; + } + + @Override + public boolean doGravity(){ + return true; + } + + @Override + public boolean doDeceleration(){ + return true; + } + + @Override + protected void entityInit() { + + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java new file mode 100644 index 00000000..ed8c5c0f --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java @@ -0,0 +1,93 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityFirebolt extends EntityMagicProjectile +{ + public EntityFirebolt(World par1World) + { + super(par1World); + } + + public EntityFirebolt(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntityFirebolt(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier); + } + + public EntityFirebolt(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + @Override + protected void onImpact(RayTraceResult rayTrace) + { + Entity entityHit = rayTrace.entityHit; + + if (entityHit != null) + { + float damage = 5 * damageMultiplier; + + entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(), damage); + + if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit)) entityHit.setFire(5); + } + + this.playSound(SoundEvents.BLOCK_LAVA_POP, 2, 0.8f + rand.nextFloat()*0.3f); + + // Particle effect + if(worldObj.isRemote){ + for(int i=0;i<8;i++){ + worldObj.spawnParticle(EnumParticleTypes.LAVA, this.posX + rand.nextFloat() - 0.5, this.posY + this.height/2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0); + } + } + + this.setDead(); + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(worldObj.isRemote){ + for(int i=0; i<4; i++){ + worldObj.spawnParticle(EnumParticleTypes.FLAME, this.posX + rand.nextFloat()*0.2 - 0.1, this.posY + this.height/2 + rand.nextFloat()*0.2 - 0.1, this.posZ + rand.nextFloat()*0.2 - 0.1, 0, 0, 0); + } + } + + if(this.ticksExisted > 8){ + this.setDead(); + } + } + + /** + * Gets the amount of gravity to apply to the thrown entity with each tick. + */ + @Override + protected float getGravityVelocity() + { + return 0.0F; + } + + /** + * Return whether this entity should be rendered as on fire. + */ + @Override + public boolean canRenderOnFire() + { + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java new file mode 100644 index 00000000..637fe5e8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java @@ -0,0 +1,87 @@ +package electroblob.wizardry.entity.projectile; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityFirebomb extends EntityBomb { + + public EntityFirebomb(World par1World) + { + super(par1World); + } + + public EntityFirebomb(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntityFirebomb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, float blastMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); + } + + public EntityFirebomb(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + /** + * Called when this EntityThrowable hits a block or entity. + */ + protected void onImpact(RayTraceResult par1RayTraceResult) + { + Entity entityHit = par1RayTraceResult.entityHit; + + if (entityHit != null) + { + // This is if the firebomb gets a direct hit + float damage = 5 * damageMultiplier; + + entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(), damage); + + if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit)) entityHit.setFire(10); + } + + // Particle effect + if(worldObj.isRemote){ + this.worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); + for(int i=0;i<60*blastMultiplier;i++){ + //this.worldObj.spawnParticle(EnumParticleTypes.FLAME, this.posX + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0, 0, 0); + Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_FIRE, worldObj, this.posX + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0, 0, 0, 15 + rand.nextInt(5), 2 + rand.nextFloat(), 0, 0); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0.0d, 0.0d, 0.0d, 0, 1.0f, 0.2f + rand.nextFloat()*0.4f, 0.0f); + } + } + + if(!this.worldObj.isRemote){ + + this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.5F, rand.nextFloat() * 0.4F + 0.6F); + this.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + + double range = 3.0d*blastMultiplier; + + List targets = WizardryUtilities.getEntitiesWithinRadius(range, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + if(target != entityHit && target != this.getThrower() && !MagicDamage.isEntityImmune(DamageType.FIRE, target)){ + // Splash damage does not count as projectile damage + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE), 4.0f * damageMultiplier); + target.setFire(7); + } + } + + this.setDead(); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java new file mode 100644 index 00000000..0cf2ec6d --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java @@ -0,0 +1,85 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.util.MagicDamage.DamageType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.world.World; + +public class EntityForceArrow extends EntityMagicArrow { + + /** Basic shell constructor. Should only be used by the client. */ + public EntityForceArrow(World world) { + super(world); + } + + /** Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this + * constructor and then call setVelocity() as that method is, bizarrely, client-side only. */ + public EntityForceArrow(World world, double x, double y, double z) + { + super(world, x, y, z); + } + + /** Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be altered + * slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on easy, 6 on + * normal and 2 on hard difficulty. */ + public EntityForceArrow(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, float damageMultiplier) + { + super(world, caster, target, speed, aimingError, damageMultiplier); + } + + /** Creates a projectile pointing in the direction the caster is looking, with the given speed. + * USE THIS CONSTRUCTOR FOR NORMAL SPELLS. */ + public EntityForceArrow(World world, EntityLivingBase caster, float speed, float damageMultiplier) + { + super(world, caster, speed, damageMultiplier); + } + + @Override + public void onEntityHit(EntityLivingBase entityHit){ + this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.0F, 1.0F); + } + + @Override + public void tickInGround(){ + this.setDead(); + } + + @Override + public void onBlockHit(){ + this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.0F, 1.0F); + } + + @Override + public void tickInAir(){ + if (this.ticksExisted > 20){ + this.setDead(); + } + } + + @Override + public double getDamage(){ + return 7.0d; + } + + @Override + public DamageType getDamageType(){ + return DamageType.FORCE; + } + + @Override + public boolean doGravity(){ + return false; + } + + @Override + public boolean doDeceleration(){ + return false; + } + + @Override + protected void entityInit() { + + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java new file mode 100644 index 00000000..9a4eaa7e --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java @@ -0,0 +1,111 @@ +package electroblob.wizardry.entity.projectile; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityForceOrb extends EntityMagicProjectile { + + /** The entity blast multiplier. In this particular case, it doesn't need syncing, so this class doesn't extend + * EntityBlastProjectile. */ + public float blastMultiplier; + + public EntityForceOrb(World par1World) + { + super(par1World); + } + + public EntityForceOrb(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntityForceOrb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, float blastMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier); + this.blastMultiplier = blastMultiplier; + } + + public EntityForceOrb(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + /** + * Called when this EntityThrowable hits a block or entity. + */ + protected void onImpact(RayTraceResult par1RayTraceResult){ + + if (par1RayTraceResult.entityHit != null) + { + // This is if the force orb gets a direct hit + this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + } + + // Particle effect + if(this.worldObj.isRemote){ + for(int j=0; j<20; j++){ + float brightness = 0.5f + (rand.nextFloat()/2); + double x = this.posX - 0.25d + (rand.nextDouble()/2); + double y = this.posY - 0.25d + (rand.nextDouble()/2); + double z = this.posZ - 0.25d + (rand.nextDouble()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, x, y, z, (x - this.posX)*2, (y - this.posY)*2, (z - this.posZ)*2, 6, brightness, 1.0f, brightness + 0.2f); + } + this.worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); + } + + if(!this.worldObj.isRemote){ + + // 2 gives a cool flanging effect! + float pitch = this.rand.nextFloat() * 0.2F + 0.3F; + this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.5F, pitch); + this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.5F, pitch - 0.01f); + + double blastRadius = 4.0d*blastMultiplier; + + List targets = WizardryUtilities.getEntitiesWithinRadius(blastRadius, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + if(target != this.getThrower()){ + + double velY = target.motionY; + + double dx = this.posX-target.posX > 0? -0.5 - (this.posX-target.posX)/8 : 0.5 - (this.posX-target.posX)/8; + double dz = this.posZ-target.posZ > 0? -0.5 - (this.posZ-target.posZ)/8 : 0.5 - (this.posZ-target.posZ)/8; + + float damage = 4*damageMultiplier; + + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.BLAST), damage); + + target.motionX = dx; + target.motionY = velY + 0.4; + target.motionZ = dz; + } + } + + this.setDead(); + } + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + blastMultiplier = nbttagcompound.getFloat("blastMultiplier"); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + nbttagcompound.setFloat("blastMultiplier", blastMultiplier); + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java new file mode 100644 index 00000000..ce5c9907 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java @@ -0,0 +1,135 @@ +package electroblob.wizardry.entity.projectile; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.Blocks; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityIceCharge extends EntityBomb { + + public EntityIceCharge(World par1World) + { + super(par1World); + } + + public EntityIceCharge(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntityIceCharge(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, float blastMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); + } + + public EntityIceCharge(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + /** + * Called when this EntityThrowable hits a block or entity. + */ + protected void onImpact(RayTraceResult par1RayTraceResult) + { + Entity entityHit = par1RayTraceResult.entityHit; + + if (entityHit != null) + { + // This is if the ice charge gets a direct hit + float damage = 4 * damageMultiplier; + + entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FROST).setProjectile(), damage); + + if(entityHit instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.FROST, entityHit)) + ((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(WizardryPotions.frost, 120, 1)); + } + + // Particle effect + if(worldObj.isRemote){ + this.worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); + for(int i=0;i<30*blastMultiplier;i++){ + float brightness = 0.4f + rand.nextFloat()*0.5f; + Wizardry.proxy.spawnParticle(WizardryParticleType.ICE, worldObj, this.posX + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0.0d, 0.0d, 0.0d, 35); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0.0d, 0.0d, 0.0d, 0, brightness, brightness+0.1f, 1.0f); + } + } + + if(!this.worldObj.isRemote){ + + this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.5f, rand.nextFloat() * 0.4f + 0.6f); + this.playSound(WizardrySounds.SPELL_ICE, 1.2f, rand.nextFloat() * 0.4f + 1.2f); + + double radius = 3.0d*blastMultiplier; + + List targets = WizardryUtilities.getEntitiesWithinRadius(radius, this.posX, this.posY, this.posZ, this.worldObj); + + // Slows targets + for(EntityLivingBase target : targets){ + if(target != entityHit && target != this.getThrower()){ + if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 100, 0)); + } + } + + // Places snow and ice on ground. + for(int i=-1; i<2; i++){ + for(int j=-1; j<2; j++){ + + BlockPos pos = new BlockPos(this.posX + i, this.posY, this.posZ + j); + + int y = WizardryUtilities.getNearestFloorLevelB(worldObj, pos, 7); + + pos = new BlockPos(pos.getX(), y, pos.getZ()); + + double dist = this.getDistance(pos.getX(), pos.getY(), pos.getZ()); + + // Randomised with weighting so that the nearer the block the more likely it is to be snowed. + if(y != -1 && rand.nextInt((int)dist*2 + 1) < 1 && dist < 2){ + if(worldObj.getBlockState(pos.down()).getBlock() == Blocks.WATER){ + worldObj.setBlockState(pos.down(), Blocks.ICE.getDefaultState()); + }else{ + // Don't need to check whether the block at pos can be replaced since getNearestFloorLevelB + // only ever returns floors with air above them. + worldObj.setBlockState(pos, Blocks.SNOW_LAYER.getDefaultState()); + } + } + } + } + + // Releases shards + for(int i=0; i<10; i++){ + double dx = rand.nextDouble()-0.5; + double dy = rand.nextDouble()-0.5; + double dz = rand.nextDouble()-0.5; + EntityIceShard iceshard = new EntityIceShard(worldObj, this.posX + dx, this.posY + dy, this.posZ + dz); + iceshard.motionX = dx; + iceshard.motionY = dy; + iceshard.motionZ = dz; + iceshard.setShootingEntity(this.getThrower()); + iceshard.damageMultiplier = this.damageMultiplier; + worldObj.spawnEntityInWorld(iceshard); + } + + this.setDead(); + } + } + + @Override + public boolean canRenderOnFire() { + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java new file mode 100644 index 00000000..ca4dd674 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java @@ -0,0 +1,117 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.world.World; + +public class EntityIceLance extends EntityMagicArrow { + + /** Basic shell constructor. Should only be used by the client. */ + public EntityIceLance(World world) { + super(world); + this.setKnockbackStrength(1); + } + + /** Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this + * constructor and then call setVelocity() as that method is, bizarrely, client-side only. */ + public EntityIceLance(World world, double x, double y, double z) + { + super(world, x, y, z); + this.setKnockbackStrength(1); + } + + /** Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be altered + * slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on easy, 6 on + * normal and 2 on hard difficulty. */ + public EntityIceLance(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, float damageMultiplier) + { + super(world, caster, target, speed, aimingError, damageMultiplier); + this.setKnockbackStrength(1); + } + + /** Creates a projectile pointing in the direction the caster is looking, with the given speed. + * USE THIS CONSTRUCTOR FOR NORMAL SPELLS. */ + public EntityIceLance(World world, EntityLivingBase caster, float speed, float damageMultiplier) + { + super(world, caster, speed, damageMultiplier); + this.setKnockbackStrength(1); + } + + @Override + public void onEntityHit(EntityLivingBase entityHit){ + + // Adds a freeze effect to the target. + if(!MagicDamage.isEntityImmune(DamageType.FROST, entityHit)) entityHit.addPotionEffect(new PotionEffect(WizardryPotions.frost, 300, 0)); + + this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + } + + @Override + public void tickInAir(){ + + } + + @Override + public void onBlockHit(){ + // Adds a particle effect when the ice lance hits a block. + if(this.worldObj.isRemote){ + for(int j=0; j<10; j++){ + double x = this.posX - 0.25d + (rand.nextDouble()/2); + double y = this.posY - 0.25d + (rand.nextDouble()/2); + double z = this.posZ - 0.25d + (rand.nextDouble()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.ICE, worldObj, x, y, z, x - this.posX, y - this.posY, z - this.posZ, 20 + rand.nextInt(10)); + } + } + // Parameters for sound: sound event name, volume, pitch. + this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.0F, rand.nextFloat() * 0.4F + 1.2F); + + } + + @Override + public void tickInGround(){ + this.setDead(); + } + + @Override + public double getDamage(){ + return 10.0d; + } + + @Override + public DamageType getDamageType(){ + return DamageType.FROST; + } + + @Override + public boolean doGravity(){ + return true; + } + + @Override + public boolean doDeceleration(){ + return true; + } + + @Override + public boolean doOverpenetration(){ + return true; + } + + @Override + protected void entityInit() { + + } + + @Override + public boolean canRenderOnFire() { + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java new file mode 100644 index 00000000..0805c4e0 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java @@ -0,0 +1,103 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.world.World; + +public class EntityIceShard extends EntityMagicArrow { + + /** Basic shell constructor. Should only be used by the client. */ + public EntityIceShard(World world) { + super(world); + } + + /** Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this + * constructor and then call setVelocity() as that method is, bizarrely, client-side only. */ + public EntityIceShard(World world, double x, double y, double z) + { + super(world, x, y, z); + } + + /** Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be altered + * slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on easy, 6 on + * normal and 2 on hard difficulty. */ + public EntityIceShard(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, float damageMultiplier) + { + super(world, caster, target, speed, aimingError, damageMultiplier); + } + + /** Creates a projectile pointing in the direction the caster is looking, with the given speed. + * USE THIS CONSTRUCTOR FOR NORMAL SPELLS. */ + public EntityIceShard(World world, EntityLivingBase caster, float speed, float damageMultiplier) + { + super(world, caster, speed, damageMultiplier); + } + + @Override + public void onEntityHit(EntityLivingBase entityHit){ + + // Adds a freeze effect to the target. + if(!MagicDamage.isEntityImmune(DamageType.FROST, entityHit)) entityHit.addPotionEffect(new PotionEffect(WizardryPotions.frost, 200, 0)); + + this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + } + + @Override + public void tickInAir(){ + + } + + @Override + public void onBlockHit(){ + // Adds a particle effect when the ice shard hits a block. + if(this.worldObj.isRemote){ + for(int j=0; j<10; j++){ + double x = this.posX - 0.25d + (rand.nextDouble()/2); + double y = this.posY - 0.25d + (rand.nextDouble()/2); + double z = this.posZ - 0.25d + (rand.nextDouble()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.ICE, worldObj, x, y, z, x - this.posX, y - this.posY, z - this.posZ, 20 + rand.nextInt(10)); + } + } + // Parameters for sound: sound event name, volume, pitch. + this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.0F, rand.nextFloat() * 0.4F + 1.2F); + + } + + @Override + public double getDamage(){ + return 6.0d; + } + + @Override + public DamageType getDamageType(){ + return DamageType.FROST; + } + + @Override + public boolean doGravity(){ + return true; + } + + @Override + public boolean doDeceleration(){ + return true; + } + + @Override + protected void entityInit() { + + } + + @Override + public boolean canRenderOnFire() { + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java new file mode 100644 index 00000000..e7f250ba --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java @@ -0,0 +1,95 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.world.World; + +public class EntityLightningArrow extends EntityMagicArrow { + + /** Basic shell constructor. Should only be used by the client. */ + public EntityLightningArrow(World world) { + super(world); + } + + /** Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this + * constructor and then call setVelocity() as that method is, bizarrely, client-side only. */ + public EntityLightningArrow(World world, double x, double y, double z) + { + super(world, x, y, z); + } + + /** Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be altered + * slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on easy, 6 on + * normal and 2 on hard difficulty. */ + public EntityLightningArrow(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, float damageMultiplier) + { + super(world, caster, target, speed, aimingError, damageMultiplier); + } + + /** Creates a projectile pointing in the direction the caster is looking, with the given speed. + * USE THIS CONSTRUCTOR FOR NORMAL SPELLS. */ + public EntityLightningArrow(World world, EntityLivingBase caster, float speed, float damageMultiplier) + { + super(world, caster, speed, damageMultiplier); + } + + @Override + public void onEntityHit(EntityLivingBase entityHit){ + + if(worldObj.isRemote){ + for(int j=0;j<8;j++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, this.posX + rand.nextFloat() - 0.5, this.posY + this.height/2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0, 3); + } + } + /* Pretty sure this needn't be here, probably missed it when I implemented the damage type system. + if(entityHit instanceof EntityCreeper && !((EntityCreeper)entityHit).getPowered()){ + entityHit.getDataWatcher().updateObject(17, Byte.valueOf((byte)1)); + if(this.getShootingEntity() instanceof EntityPlayer) ((EntityPlayer)this.getShootingEntity()).addStat(Wizardry.chargeCreeper); + } + */ + this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.0F); + } + + @Override + public void tickInAir(){ + + if (this.ticksExisted > 20){ + this.setDead(); + } + + if(worldObj.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, this.posX, this.posY, this.posZ, 0, 0, 0, 3); + } + + } + + @Override + public double getDamage(){ + return 7.0d; + } + + @Override + public DamageType getDamageType(){ + return DamageType.SHOCK; + } + + @Override + public boolean doGravity(){ + return false; + } + + @Override + public boolean doDeceleration(){ + return false; + } + + @Override + protected void entityInit() { + + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java new file mode 100644 index 00000000..e27e34d1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java @@ -0,0 +1,121 @@ +package electroblob.wizardry.entity.projectile; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityLightningDisc extends EntityMagicProjectile +{ + public EntityLightningDisc(World par1World) + { + super(par1World); + } + + public EntityLightningDisc(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntityLightningDisc(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier); + } + + public EntityLightningDisc(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + this.width = 2.0f; + this.height = 0.5f; + } + + @Override + protected float getSpeed(){ + return 1.2f; + } + + + @Override + protected void onImpact(RayTraceResult mop) + { + Entity entityHit = mop.entityHit; + + if (entityHit != null) + { + float damage = 12 * damageMultiplier; + + entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK), damage); + } + + this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + + if(mop.typeOfHit == RayTraceResult.Type.BLOCK) this.setDead(); + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + // Particle effect + if(worldObj.isRemote){ + for(int i=0;i<8;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, this.posX + rand.nextFloat()*2 - 1, this.posY, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0, 3); + //worldObj.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + rand.nextFloat() - 0.5, this.posY + this.height/2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0); + } + } + + if(!this.isCollided && !worldObj.isRemote){ + + double seekingRange = 5.0d; + + List entities = WizardryUtilities.getEntitiesWithinRadius(seekingRange, this.posX, this.posY, this.posZ, this.worldObj); + Entity target = null; + + for(Entity possibleTarget : entities){ + // Decides if current entity should be replaced. + if(target == null || this.getDistanceToEntity(target) > this.getDistanceToEntity(possibleTarget)){ + // Decides if new entity is a valid target. + if(WizardryUtilities.isValidTarget(this.getThrower(), possibleTarget)){ + target = possibleTarget; + } + } + } + + if(target != null && Math.abs(this.motionX) < 1 && Math.abs(this.motionY) < 1 && Math.abs(this.motionZ) < 1){ + this.addVelocity((target.posX - this.posX)/30, (target.posY + target.height/2 - this.posY)/30, (target.posZ - this.posZ)/30); + } + } + + if(this.ticksExisted > 50){ + this.setDead(); + } + + // Cancels out the slowdown effect in EntityThrowable + this.motionX /= 0.99; + this.motionY /= 0.99; + this.motionZ /= 0.99; + } + + + @Override + protected float getGravityVelocity() + { + return 0.0F; + } + + + @Override + public boolean canRenderOnFire() + { + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java new file mode 100644 index 00000000..fefa58cd --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java @@ -0,0 +1,582 @@ +package electroblob.wizardry.entity.projectile; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.UUID; + +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IProjectile; +import net.minecraft.entity.monster.EntityEnderman; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.play.server.SPacketChangeGameState; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** This class was copied from EntityArrow in the 1.7.10 update as part of the overhaul and major cleanup + * of the code for the projectiles. It provides a unifying superclass for all directed projectiles (i.e. not + * spherical stuff like snowballs), namely magic missile, ice shard, force arrow, lightning arrow and dart. + * All spherical projectiles should extend {@link EntityMagicProjectile}. + *

    + * This class handles saving of the damage multiplier and all shared logic. Methods are provided which are + * triggered at useful points during the entity update cycle as well as a few getters for various properties. + * Override any of these to change the behaviour (no need to call super for any of them). + * @since Wizardry 1.0 + * @author Electroblob + */ +public abstract class EntityMagicArrow extends Entity implements IProjectile, IEntityAdditionalSpawnData { + + private int blockX = -1; + private int blockY = -1; + private int blockZ = -1; + /** The block the arrow is stuck in */ + private IBlockState stuckInBlock; + /** The metadata of the block the arrow is stuck in */ + private int inData; + private boolean inGround; + /** Seems to be some sort of timer for animating an arrow. */ + public int arrowShake; + /** The owner of this arrow. */ + private WeakReference shootingEntity; + /** The UUID of the caster. Note that this is only for loading purposes; during normal updates + * the actual entity instance is stored (so that getEntityByUUID is not called constantly), + * so this will not always be synced (this is why it is private). */ + private UUID casterUUID; + int ticksInGround; + int ticksInAir; + /** The amount of knockback an arrow applies when it hits a mob. */ + private int knockbackStrength; + /** The damage multiplier for the arrow. Normally this isn't set directly, since it can be done via the + * constructor. An exception is where other entities need to pass in their multipliers, e.g. ice charge. */ + public float damageMultiplier = 1.0f; + + /** Basic shell constructor. Should only be used by the client. */ + public EntityMagicArrow(World world) + { + super(world); + this.setSize(0.5F, 0.5F); + } + + /** Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this + * constructor and then call setVelocity() as that method is, bizarrely, client-side only. */ + public EntityMagicArrow(World world, double x, double y, double z) + { + super(world); + this.setSize(0.5F, 0.5F); + this.setPosition(x, y, z); + // yOffset was set to 0 here, but that has been replaced by getYOffset(), which returns 0 in Entity anyway. + } + + /** Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be altered + * slightly by a random amount determined by the aimingError parameter. For reference, skeletons set this to 10 on easy, 6 on + * normal and 2 on hard difficulty. */ + public EntityMagicArrow(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, float damageMultiplier) + { + super(world); + this.shootingEntity = new WeakReference(caster); + this.damageMultiplier = damageMultiplier; + + this.posY = caster.posY + (double)caster.getEyeHeight() - 0.10000000149011612D; + double d0 = target.posX - caster.posX; + double d1 = this.doGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0F) - this.posY + : target.getEntityBoundingBox().minY + (double)(target.height / 2.0F) - this.posY; + double d2 = target.posZ - caster.posZ; + double d3 = (double)MathHelper.sqrt_double(d0 * d0 + d2 * d2); + + if (d3 >= 1.0E-7D) + { + float f2 = (float)(Math.atan2(d2, d0) * 180.0D / Math.PI) - 90.0F; + float f3 = (float)(-(Math.atan2(d1, d3) * 180.0D / Math.PI)); + double d4 = d0 / d3; + double d5 = d2 / d3; + this.setLocationAndAngles(caster.posX + d4, this.posY, caster.posZ + d5, f2, f3); + // yOffset was set to 0 here, but that has been replaced by getYOffset(), which returns 0 in Entity anyway. + + // f4 depends on the horizontal distance between the two entities and accounts for bullet drop, + // but of course if gravity is ignored this should be 0. + float bulletDropCompensation = this.doGravity() ? (float)d3 * 0.2F : 0; + this.setThrowableHeading(d0, d1 + (double)bulletDropCompensation, d2, speed, aimingError); + } + } + + /** Creates a projectile pointing in the direction the caster is looking, with the given speed. + * Use this constructor for normal, player-cast spells. */ + public EntityMagicArrow(World world, EntityLivingBase caster, float speed, float damageMultiplier) + { + super(world); + this.shootingEntity = new WeakReference(caster); + this.damageMultiplier = damageMultiplier; + + this.setSize(0.5F, 0.5F); + this.setLocationAndAngles(caster.posX, caster.posY + (double)caster.getEyeHeight(), caster.posZ, caster.rotationYaw, caster.rotationPitch); + this.posX -= (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F); + this.posY -= 0.10000000149011612D; + this.posZ -= (double)(MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F); + this.setPosition(this.posX, this.posY, this.posZ); + // yOffset was set to 0 here, but that has been replaced by getYOffset(), which returns 0 in Entity anyway. + this.motionX = (double)(-MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI)); + this.motionZ = (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI)); + this.motionY = (double)(-MathHelper.sin(this.rotationPitch / 180.0F * (float)Math.PI)); + this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, speed * 1.5F, 1.0F); + } + + /** Subclasses must override this to set their own base damage. */ + public abstract double getDamage(); + + /** Override this to specify the damage type dealt. Defaults to {@link DamageType#MAGIC}. */ + public DamageType getDamageType(){ + return DamageType.MAGIC; + } + + /** Override this to disable gravity. Returns true by default. */ + public boolean doGravity(){ + return true; + } + + /** Override this to disable deceleration (generally speaking, this isn't noticeable unless gravity + * is turned off). Returns true by default. */ + public boolean doDeceleration(){ + return true; + } + + /** Override this to allow the projectile to pass through mobs intact (the onEntityHit method will + * still be called and damage will still be applied). Returns false by default. */ + public boolean doOverpenetration(){ + return false; + } + + /** + * Similar to setArrowHeading, it's point the throwable entity to a x, y, z direction. + */ + public void setThrowableHeading(double x, double y, double z, float speed, float randomness) + { + float f2 = MathHelper.sqrt_double(x * x + y * y + z * z); + x /= (double)f2; + y /= (double)f2; + z /= (double)f2; + x += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)randomness; + y += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)randomness; + z += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)randomness; + x *= (double)speed; + y *= (double)speed; + z *= (double)speed; + this.motionX = x; + this.motionY = y; + this.motionZ = z; + float f3 = MathHelper.sqrt_double(x * x + z * z); + this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(x, z) * 180.0D / Math.PI); + this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(y, (double)f3) * 180.0D / Math.PI); + this.ticksInGround = 0; + } + + // There was an override for setPositionAndRotationDirect here, but it was exactly the same as the superclass + // method (in Entity), so it was removed since it was redundant. + + /** + * Sets the velocity to the args. Args: x, y, z. THIS IS CLIENT SIDE ONLY! DO NOT USE IN COMMON OR SERVER CODE! + */ + @Override + @SideOnly(Side.CLIENT) + public void setVelocity(double p_70016_1_, double p_70016_3_, double p_70016_5_) + { + this.motionX = p_70016_1_; + this.motionY = p_70016_3_; + this.motionZ = p_70016_5_; + + if (this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F) + { + float f = MathHelper.sqrt_double(p_70016_1_ * p_70016_1_ + p_70016_5_ * p_70016_5_); + this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(p_70016_1_, p_70016_5_) * 180.0D / Math.PI); + this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(p_70016_3_, (double)f) * 180.0D / Math.PI); + this.prevRotationPitch = this.rotationPitch; + this.prevRotationYaw = this.rotationYaw; + this.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch); + this.ticksInGround = 0; + } + } + + /** Called each tick when the projectile is in a block. Defaults to setDead(), but can be overridden to + * change the behaviour. */ + public void tickInGround(){ + this.setDead(); + } + + /** Called each tick when the projectile is in the air. Override to add particles and such like. */ + public void tickInAir(){} + + /** Called when the projectile hits an entity. Override to add potion effects and such like. */ + public void onEntityHit(EntityLivingBase entityHit){} + + /** Called when the projectile hits a block. Override to add sound effects and such like. */ + public void onBlockHit(){} + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(this.getShootingEntity() == null && this.casterUUID != null){ + Entity entity = WizardryUtilities.getEntityByUUID(worldObj, casterUUID); + if(entity instanceof EntityLivingBase){ + this.shootingEntity = new WeakReference((EntityLivingBase)entity); + } + } + + if (this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F) + { + float f = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ); + this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(this.motionX, this.motionZ) * 180.0D / Math.PI); + this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(this.motionY, (double)f) * 180.0D / Math.PI); + } + + BlockPos blockpos = new BlockPos(this.blockX, this.blockY, this.blockZ); + IBlockState iblockstate = this.worldObj.getBlockState(blockpos); + + if (iblockstate.getMaterial() != Material.AIR) + { + AxisAlignedBB axisalignedbb = iblockstate.getCollisionBoundingBox(this.worldObj, blockpos); + + if (axisalignedbb != Block.NULL_AABB && axisalignedbb.offset(blockpos).isVecInside(new Vec3d(this.posX, this.posY, this.posZ))) + { + this.inGround = true; + } + } + + if (this.arrowShake > 0) + { + --this.arrowShake; + } + + // When the arrow is in the ground + if (this.inGround) + { + ++this.ticksInGround; + this.tickInGround(); + } + // When the arrow is in the air + else{ + + this.tickInAir(); + + this.ticksInGround = 0; + ++this.ticksInAir; + Vec3d vec3d1 = new Vec3d(this.posX, this.posY, this.posZ); + Vec3d vec3d = new Vec3d(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ); + RayTraceResult raytraceresult = this.worldObj.rayTraceBlocks(vec3d1, vec3d, false, true, false); + vec3d1 = new Vec3d(this.posX, this.posY, this.posZ); + vec3d = new Vec3d(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ); + + if (raytraceresult != null) + { + vec3d = new Vec3d(raytraceresult.hitVec.xCoord, raytraceresult.hitVec.yCoord, raytraceresult.hitVec.zCoord); + } + + + Entity entity = null; + List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.getEntityBoundingBox().addCoord(this.motionX, this.motionY, this.motionZ).expand(1.0D, 1.0D, 1.0D)); + double d0 = 0.0D; + int i; + float f1; + + for (i = 0; i < list.size(); ++i) + { + Entity entity1 = (Entity)list.get(i); + + if (entity1.canBeCollidedWith() && (entity1 != this.getShootingEntity() || this.ticksInAir >= 5)) + { + f1 = 0.3F; + AxisAlignedBB axisalignedbb1 = entity1.getEntityBoundingBox().expand((double)f1, (double)f1, (double)f1); + RayTraceResult RayTraceResult1 = axisalignedbb1.calculateIntercept(vec3d1, vec3d); + + if (RayTraceResult1 != null) + { + double d1 = vec3d1.distanceTo(RayTraceResult1.hitVec); + + if (d1 < d0 || d0 == 0.0D) + { + entity = entity1; + d0 = d1; + } + } + } + } + + if (entity != null) + { + raytraceresult = new RayTraceResult(entity); + } + + // Players that are considered invulnerable to the caster allow the projectile to pass straight through them. + if (raytraceresult != null && raytraceresult.entityHit != null && raytraceresult.entityHit instanceof EntityPlayer) + { + EntityPlayer entityplayer = (EntityPlayer)raytraceresult.entityHit; + + if (entityplayer.capabilities.disableDamage || this.getShootingEntity() instanceof EntityPlayer && !((EntityPlayer)this.getShootingEntity()).canAttackPlayer(entityplayer)) + { + raytraceresult = null; + } + } + + // If the arrow hits something + if (raytraceresult != null) + { + // If the arrow hits an entity + if (raytraceresult.entityHit != null) + { + DamageSource damagesource = null; + + if (this.getShootingEntity() == null) + { + damagesource = DamageSource.causeThrownDamage(this, this); + } + else + { + damagesource = MagicDamage.causeIndirectMagicDamage(this, (EntityLivingBase)this.getShootingEntity(), this.getDamageType()).setProjectile(); + } + + if (raytraceresult.entityHit.attackEntityFrom(damagesource, (float)(this.getDamage()*this.damageMultiplier))) + { + if (raytraceresult.entityHit instanceof EntityLivingBase) + { + EntityLivingBase entityHit = (EntityLivingBase)raytraceresult.entityHit; + + this.onEntityHit(entityHit); + + if (this.knockbackStrength > 0) + { + float f4 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ); + + if (f4 > 0.0F) + { + raytraceresult.entityHit.addVelocity(this.motionX * (double)this.knockbackStrength * 0.6000000238418579D / (double)f4, 0.1D, this.motionZ * (double)this.knockbackStrength * 0.6000000238418579D / (double)f4); + } + } + + // Thorns enchantment + if (this.getShootingEntity() != null && this.getShootingEntity() instanceof EntityLivingBase) + { + EnchantmentHelper.applyThornEnchantments(entityHit, this.getShootingEntity()); + EnchantmentHelper.applyArthropodEnchantments((EntityLivingBase)this.getShootingEntity(), entityHit); + } + + if (this.getShootingEntity() != null && raytraceresult.entityHit != this.getShootingEntity() && raytraceresult.entityHit instanceof EntityPlayer && this.getShootingEntity() instanceof EntityPlayerMP) + { + ((EntityPlayerMP)this.getShootingEntity()).connection.sendPacket(new SPacketChangeGameState(6, 0.0F)); + } + } + + if (!(raytraceresult.entityHit instanceof EntityEnderman) && !this.doOverpenetration()) + { + this.setDead(); + } + } + else + { + if(!this.doOverpenetration()) this.setDead(); + + // Was the 'rebound' that happened when entities were immune to damage + /* + this.motionX *= -0.10000000149011612D; + this.motionY *= -0.10000000149011612D; + this.motionZ *= -0.10000000149011612D; + this.rotationYaw += 180.0F; + this.prevRotationYaw += 180.0F; + this.ticksInAir = 0; + */ + } + } + // If the arrow hits a block + else + { + this.blockX = raytraceresult.getBlockPos().getX(); + this.blockY = raytraceresult.getBlockPos().getY(); + this.blockZ = raytraceresult.getBlockPos().getZ(); + this.stuckInBlock = this.worldObj.getBlockState(raytraceresult.getBlockPos()); + this.motionX = (double)((float)(raytraceresult.hitVec.xCoord - this.posX)); + this.motionY = (double)((float)(raytraceresult.hitVec.yCoord - this.posY)); + this.motionZ = (double)((float)(raytraceresult.hitVec.zCoord - this.posZ)); + //f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ); + //this.posX -= this.motionX / (double)f2 * 0.05000000074505806D; + //this.posY -= this.motionY / (double)f2 * 0.05000000074505806D; + //this.posZ -= this.motionZ / (double)f2 * 0.05000000074505806D; + //this.playSound("random.bowhit", 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + this.inGround = true; + this.arrowShake = 7; + + this.onBlockHit(); + + if (this.stuckInBlock.getMaterial() != Material.AIR) + { + this.stuckInBlock.getBlock().onEntityCollidedWithBlock(this.worldObj, raytraceresult.getBlockPos(), this.stuckInBlock, this); + } + } + } + + this.posX += this.motionX; + this.posY += this.motionY; + this.posZ += this.motionZ; + //f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ); + this.rotationYaw = (float)(Math.atan2(this.motionX, this.motionZ) * 180.0D / Math.PI); + + //for (this.rotationPitch = (float)(Math.atan2(this.motionY, (double)f2) * 180.0D / Math.PI); this.rotationPitch - this.prevRotationPitch < -180.0F; this.prevRotationPitch -= 360.0F) + //{ + // ; + //} + + while (this.rotationPitch - this.prevRotationPitch >= 180.0F) + { + this.prevRotationPitch += 360.0F; + } + + while (this.rotationYaw - this.prevRotationYaw < -180.0F) + { + this.prevRotationYaw -= 360.0F; + } + + while (this.rotationYaw - this.prevRotationYaw >= 180.0F) + { + this.prevRotationYaw += 360.0F; + } + + this.rotationPitch = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * 0.2F; + this.rotationYaw = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * 0.2F; + + float f3 = 0.99F; + + if (this.isInWater()) + { + for (int l = 0; l < 4; ++l) + { + float f4 = 0.25F; + this.worldObj.spawnParticle(EnumParticleTypes.WATER_BUBBLE, this.posX - this.motionX * (double)f4, this.posY - this.motionY * (double)f4, this.posZ - this.motionZ * (double)f4, this.motionX, this.motionY, this.motionZ); + } + + f3 = 0.8F; + } + + if (this.isWet()) + { + this.extinguish(); + } + + if(this.doDeceleration()){ + this.motionX *= (double)f3; + this.motionY *= (double)f3; + this.motionZ *= (double)f3; + } + + if(this.doGravity()) this.motionY -= 0.05; + + this.setPosition(this.posX, this.posY, this.posZ); + this.doBlockCollisions(); + } + } + + @Override + public void writeEntityToNBT(NBTTagCompound tag) + { + tag.setShort("xTile", (short)this.blockX); + tag.setShort("yTile", (short)this.blockY); + tag.setShort("zTile", (short)this.blockZ); + tag.setShort("life", (short)this.ticksInGround); + if(this.stuckInBlock != null){ + ResourceLocation resourcelocation = (ResourceLocation)Block.REGISTRY.getNameForObject(this.stuckInBlock.getBlock()); + tag.setString("inTile", resourcelocation == null ? "" : resourcelocation.toString()); + } + tag.setByte("inData", (byte)this.inData); + tag.setByte("shake", (byte)this.arrowShake); + tag.setByte("inGround", (byte)(this.inGround ? 1 : 0)); + tag.setFloat("damageMultiplier", this.damageMultiplier); + if(this.getShootingEntity() != null){ + tag.setUniqueId("casterUUID", this.getShootingEntity().getUniqueID()); + } + } + + @Override + public void readEntityFromNBT(NBTTagCompound tag) + { + this.blockX = tag.getShort("xTile"); + this.blockY = tag.getShort("yTile"); + this.blockZ = tag.getShort("zTile"); + this.ticksInGround = tag.getShort("life"); + // Commented out for now because there's some funny stuff going on with blockstates and metadata. + //this.stuckInBlock = Block.getBlockById(tag.getByte("inTile") & 255); + this.inData = tag.getByte("inData") & 255; + this.arrowShake = tag.getByte("shake") & 255; + this.inGround = tag.getByte("inGround") == 1; + this.damageMultiplier = tag.getFloat("damageMultiplier"); + casterUUID = tag.getUniqueId("casterUUID"); + } + + /** + * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to + * prevent them from trampling crops + */ + protected boolean canTriggerWalking() + { + return false; + } + + @SideOnly(Side.CLIENT) + public float getShadowSize() + { + return 0.0F; + } + + /** + * Sets the amount of knockback the arrow applies when it hits a mob. + */ + public void setKnockbackStrength(int p_70240_1_) + { + this.knockbackStrength = p_70240_1_; + } + + /** + * If returns false, the item will not inflict any damage against entities. + */ + public boolean canAttackWithItem() + { + return false; + } + + public void writeSpawnData(ByteBuf buffer){ + if(this.getShootingEntity() != null) buffer.writeInt(this.getShootingEntity().getEntityId()); + } + + public void readSpawnData(ByteBuf buffer){ + if(buffer.isReadable()) this.shootingEntity = new WeakReference((EntityLivingBase)this.worldObj.getEntityByID(buffer.readInt())); + } + + /** + * Returns the EntityLivingBase that created this construct, or null if it no longer exists. Cases where the + * entity may no longer exist are: entity died or was deleted, mob despawned, player logged out, entity teleported + * to another dimension, or this construct simply had no caster in the first place. + */ + public EntityLivingBase getShootingEntity() { + return shootingEntity == null ? null : shootingEntity.get(); + } + + public void setShootingEntity(EntityLivingBase entity) { + shootingEntity = new WeakReference(entity); + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java new file mode 100644 index 00000000..67c079d9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java @@ -0,0 +1,82 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.SoundEvents; +import net.minecraft.world.World; + +public class EntityMagicMissile extends EntityMagicArrow { + + /** Basic shell constructor. Should only be used by the client. */ + public EntityMagicMissile(World world) { + super(world); + } + + /** Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this + * constructor and then call setVelocity() as that method is, bizarrely, client-side only. */ + public EntityMagicMissile(World world, double x, double y, double z) + { + super(world, x, y, z); + } + + /** Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be altered + * slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on easy, 6 on + * normal and 2 on hard difficulty. */ + public EntityMagicMissile(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, float damageMultiplier) + { + super(world, caster, target, speed, aimingError, damageMultiplier); + } + + /** Creates a projectile pointing in the direction the caster is looking, with the given speed. + * USE THIS CONSTRUCTOR FOR NORMAL SPELLS. */ + public EntityMagicMissile(World world, EntityLivingBase caster, float speed, float damageMultiplier) + { + super(world, caster, speed, damageMultiplier); + } + + @Override + public void onEntityHit(EntityLivingBase entityHit){ + this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + } + + @Override + public void tickInAir(){ + + if (this.ticksExisted > 20){ + this.setDead(); + } + + if(this.worldObj.isRemote){ + + if(this.ticksExisted % 2 == 1){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX, this.posY, this.posZ, 0, 0, 0, 20 + rand.nextInt(10), 0.5f + (rand.nextFloat()/2), 0.5f + (rand.nextFloat()/2), 0.5f + (rand.nextFloat()/2)); + } + else{ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX, this.posY, this.posZ, 0, 0, 0, 20 + rand.nextInt(10), 0.5f + (rand.nextFloat()/2), 0.5f + (rand.nextFloat()/2), 0.5f + (rand.nextFloat()/2)); + } + } + } + + @Override + public double getDamage(){ + return 4.0d; + } + + @Override + public boolean doGravity(){ + return false; + } + + @Override + public boolean doDeceleration(){ + return false; + } + + @Override + protected void entityInit() { + + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java new file mode 100644 index 00000000..e37c45fa --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java @@ -0,0 +1,79 @@ +package electroblob.wizardry.entity.projectile; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.projectile.EntityThrowable; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; + +/** This class is a generic superclass for all non-directed projectiles, namely: darkness orb, firebolt, firebomb, + * force orb, ice charge, lightning disc, poison bomb, spark, spark bomb and thunderbolt. Directed (arrow-like) projectiles + * should instead extend {@link EntityMagicArrow}. + *

    + * This class purely handles saving of the damage multiplier; EntityThrowable is pretty well suited to my purposes + * as it is. Range is done via the velocity when the constructor is called. Caster is already handled by EntityThrowable.getThrower(). + * + * Note that this class does not implement {@link IEntityAdditionalSpawnData}; subclasses that need to transfer extra data + * to the client should implement that interface themselves. See {@link EntityBomb} for an example. + * @since Wizardry 1.0 + * @author Electroblob + * @see EntityBomb + */ +public abstract class EntityMagicProjectile extends EntityThrowable { + + public float damageMultiplier = 1.0f; + + public EntityMagicProjectile(World world) + { + super(world); + } + + public EntityMagicProjectile(World world, EntityLivingBase thrower) + { + super(world, thrower); + } + + public EntityMagicProjectile(World world, EntityLivingBase thrower, float damageMultiplier) + { + super(world, thrower); + // This is the standard set of parameters for this method, used by snowballs and ender pearls amongst others. + this.setHeadingFromThrower(thrower, thrower.rotationPitch, thrower.rotationYaw, 0.0f, this.getSpeed(), 1.0f); + this.damageMultiplier = damageMultiplier; + } + + public EntityMagicProjectile(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + /** This got removed at some point since 1.7.10, but I liked it so I thought I'd add it back in again. */ + protected float getSpeed(){ + return 1.5f; + } + + /** Sets this projectile's velocity as a normalised vector towards the target. */ + public void directTowards(Entity target, float velocity){ + + double dx = target.posX - this.posX; + double dy = target.getEntityBoundingBox().minY + (double)(target.height / 2.0F) - (this.posY + (double)(this.height / 2.0F)); + double dz = target.posZ - this.posZ; + + this.motionX = dx/this.getDistanceToEntity(target) * velocity; + this.motionY = dy/this.getDistanceToEntity(target) * velocity; + this.motionZ = dz/this.getDistanceToEntity(target) * velocity; + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + damageMultiplier = nbttagcompound.getFloat("damageMultiplier"); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + nbttagcompound.setFloat("damageMultiplier", damageMultiplier); + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java new file mode 100644 index 00000000..717aa618 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java @@ -0,0 +1,85 @@ +package electroblob.wizardry.entity.projectile; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityPoisonBomb extends EntityBomb { + + public EntityPoisonBomb(World par1World) + { + super(par1World); + } + + public EntityPoisonBomb(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntityPoisonBomb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, float blastMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); + } + + public EntityPoisonBomb(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + @Override + protected void onImpact(RayTraceResult par1RayTraceResult) + { + Entity entityHit = par1RayTraceResult.entityHit; + + if (entityHit != null) + { + // This is if the poison bomb gets a direct hit + float damage = 5 * damageMultiplier; + + entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.POISON).setProjectile(), damage); + + if(entityHit instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.POISON, entityHit)) ((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(MobEffects.POISON, 120, 1)); + } + + // Particle effect + if(worldObj.isRemote){ + for(int i=0;i<60*blastMultiplier;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, worldObj, this.posX + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0.0d, 0.0d, 0.0d, 35, 0.2f + rand.nextFloat()*0.3f, 0.6f, 0.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0.0d, 0.0d, 0.0d, 0, 0.2f + rand.nextFloat()*0.2f, 0.8f, 0.0f); + } + // Spawning this after the other particles fixes the rendering colour bug. It's a bit of a cheat, but it works pretty well. + this.worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); + } + + if(!this.worldObj.isRemote){ + + this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.5F, rand.nextFloat() * 0.4F + 0.6F); + this.playSound(SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.2F, 1.0f); + + double range = 3.0d*blastMultiplier; + + List targets = WizardryUtilities.getEntitiesWithinRadius(range, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + if(target != entityHit && target != this.getThrower() && !MagicDamage.isEntityImmune(DamageType.POISON, target)){ + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.POISON), 4.0f * damageMultiplier); + target.addPotionEffect(new PotionEffect(MobEffects.POISON, 100, 1)); + } + } + + this.setDead(); + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java new file mode 100644 index 00000000..1ed5dea0 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java @@ -0,0 +1,81 @@ +package electroblob.wizardry.entity.projectile; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntitySmokeBomb extends EntityBomb { + + public EntitySmokeBomb(World par1World) + { + super(par1World); + } + + public EntitySmokeBomb(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntitySmokeBomb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, float blastMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); + } + + public EntitySmokeBomb(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + @Override + protected void onImpact(RayTraceResult par1RayTraceResult){ + + // Particle effect + if(worldObj.isRemote){ + this.worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); + for(int i=0;i<60*blastMultiplier;i++){ + this.worldObj.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0, 0, 0); + float brightness = rand.nextFloat() * 0.3f; + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0.0d, 0.0d, 0.0d, 0, brightness, brightness, brightness); + } + } + + if(!this.worldObj.isRemote){ + + this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.5F, rand.nextFloat() * 0.4F + 0.6F); + this.playSound(SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.2F, 1.0f); + + double range = 3.0d * blastMultiplier; + + List targets = WizardryUtilities.getEntitiesWithinRadius(range, this.posX, this.posY, this.posZ, this.worldObj); + + for(EntityLivingBase target : targets){ + if(target != this.getThrower()){ + // Gives the target blindness if it is a player, mind trick otherwise (since this has the desired + // effect of preventing targeting) + if(target instanceof EntityPlayer){ + target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, 120, 0)); + }else if(target instanceof EntityLiving){ + // New AI + ((EntityLiving)target).setAttackTarget(null); + + target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, 120, 0)); + } + } + } + + this.setDead(); + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java new file mode 100644 index 00000000..4061b954 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java @@ -0,0 +1,116 @@ +package electroblob.wizardry.entity.projectile; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntitySpark extends EntityMagicProjectile { + + public EntitySpark(World par1World) + { + super(par1World); + } + + public EntitySpark(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntitySpark(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier); + } + + public EntitySpark(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + /** This is the speed */ + protected float getSpeed() + { + return 0.5F; + } + + /** + * Called when this EntityThrowable hits a block or entity. + */ + protected void onImpact(RayTraceResult par1RayTraceResult) + { + Entity entityHit = par1RayTraceResult.entityHit; + + if (entityHit != null){ + + float damage = 6 * damageMultiplier; + entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK), damage); + + } + + this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + + // Particle effect + if(worldObj.isRemote){ + for(int i=0;i<8;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, this.posX + rand.nextFloat() - 0.5, this.posY + this.height/2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0, 3); + } + } + + this.setDead(); + } + + public void onUpdate(){ + + super.onUpdate(); + + if(!this.isCollided && !worldObj.isRemote){ + + double seekingRange = 5.0d; + + List entities = WizardryUtilities.getEntitiesWithinRadius(seekingRange, this.posX, this.posY, this.posZ, this.worldObj); + Entity target = null; + + for(Entity possibleTarget : entities){ + // Decides if current entity should be replaced. + if(target == null || this.getDistanceToEntity(target) > this.getDistanceToEntity(possibleTarget)){ + // Decides if new entity is a valid target. + if(WizardryUtilities.isValidTarget(this.getThrower(), possibleTarget)){ + target = possibleTarget; + } + } + } + + if(target != null && Math.abs(this.motionX) < 1 && Math.abs(this.motionY) < 1 && Math.abs(this.motionZ) < 1){ + this.addVelocity((target.posX - this.posX)/30, (target.posY + target.height/2 - this.posY)/30, (target.posZ - this.posZ)/30); + } + } + + if(this.ticksExisted > 100){ + this.setDead(); + } + } + + /** + * Gets the amount of gravity to apply to the thrown entity with each tick. + */ + protected float getGravityVelocity() + { + return 0.0F; + } + + /** + * Return whether this entity should be rendered as on fire. + */ + public boolean canRenderOnFire() + { + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java new file mode 100644 index 00000000..9ffedcdf --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java @@ -0,0 +1,124 @@ +package electroblob.wizardry.entity.projectile; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntitySparkBomb extends EntityBomb { + + /** For client use, because thrower field is not visible. */ + private int casterID; + + public EntitySparkBomb(World par1World) + { + super(par1World); + } + + public EntitySparkBomb(World par1World, EntityLivingBase par2EntityLivingBase) + { + super(par1World, par2EntityLivingBase); + } + + public EntitySparkBomb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, float blastMultiplier) + { + super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); + } + + public EntitySparkBomb(World par1World, double par2, double par4, double par6) + { + super(par1World, par2, par4, par6); + } + + /** + * Called when this EntityThrowable hits a block or entity. + */ + protected void onImpact(RayTraceResult par1RayTraceResult) + { + this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST_FAR, 0.5f, 0.5f); + + Entity entityHit = par1RayTraceResult.entityHit; + + if (entityHit != null) + { + // This is if the spark bomb gets a direct hit + float damage = 6 * damageMultiplier; + + this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + + entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(), damage); + + } + + // Particle effect + if(worldObj.isRemote){ + for(int i=0;i<8;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, worldObj, this.posX + rand.nextFloat() - 0.5, this.posY + this.height/2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0, 3); + worldObj.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + rand.nextFloat() - 0.5, this.posY + this.height/2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0); + } + } + + double seekerRange = 5.0d * blastMultiplier; + + List targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX, this.posY, this.posZ, this.worldObj); + + for(int i=0; i 8){ + this.setDead(); + } + } + + /** + * Gets the amount of gravity to apply to the thrown entity with each tick. + */ + protected float getGravityVelocity() + { + return 0.0F; + } + + /** + * Return whether this entity should be rendered as on fire. + */ + public boolean canRenderOnFire() + { + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/event/DiscoverSpellEvent.java b/src/main/java/electroblob/wizardry/event/DiscoverSpellEvent.java new file mode 100644 index 00000000..48ca70a9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/event/DiscoverSpellEvent.java @@ -0,0 +1,35 @@ +package electroblob.wizardry.event; + +import electroblob.wizardry.spell.Spell; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.fml.common.eventhandler.Cancelable; + +/** + * [NYI] DiscoverSpellEvent is fired when a player discovers a spell by any method.
    + *
    + * This event is {@link Cancelable}.
    + * If this event is canceled, the spell is not discovered.
    + *
    + * This event does not have a result. {@link HasResult}
    + *
    + * This event is fired on the {@link MinecraftForge#EVENT_BUS}. + * + * @author Electroblob + * @since Wizardry 2.1 + */ +public class DiscoverSpellEvent extends PlayerEvent { + + public DiscoverSpellEvent(EntityPlayer player, Spell spell, Source source) { + super(player); + } + + public enum Source { + /** Signifies that the spell was discovered by trying to cast it. */ CASTING, + /** Signifies that the spell was discovered using a scroll of identification. */ IDENTIFICATION_SCROLL, + /** Signifies that the spell was discovered using commands. */ COMMAND, + /** Signifies that the spell was discovered by some other means (. */ OTHER + } + +} diff --git a/src/main/java/electroblob/wizardry/event/SpellBindEvent.java b/src/main/java/electroblob/wizardry/event/SpellBindEvent.java new file mode 100644 index 00000000..f1a88f43 --- /dev/null +++ b/src/main/java/electroblob/wizardry/event/SpellBindEvent.java @@ -0,0 +1,28 @@ +package electroblob.wizardry.event; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.fml.common.eventhandler.Cancelable; + +/** + * [NYI] SpellBindEvent is fired when a player presses the apply button in the arcane workbench.
    + *
    + * This event is {@link Cancelable}.
    + * If this event is canceled, no further processing takes place: spells are not bound, upgrades are not applied and + * crystals are not consumed.
    + *
    + * This event does not have a result. {@link HasResult}
    + *
    + * This event is fired on the {@link MinecraftForge#EVENT_BUS}. + * + * @author Electroblob + * @since Wizardry 2.1 + */ +public class SpellBindEvent extends PlayerEvent { + + public SpellBindEvent(EntityPlayer player) { + super(player); + } + +} diff --git a/src/main/java/electroblob/wizardry/event/SpellCastEvent.java b/src/main/java/electroblob/wizardry/event/SpellCastEvent.java new file mode 100644 index 00000000..2c5346df --- /dev/null +++ b/src/main/java/electroblob/wizardry/event/SpellCastEvent.java @@ -0,0 +1,22 @@ +package electroblob.wizardry.event; + +import electroblob.wizardry.spell.Spell; +import net.minecraft.entity.EntityLivingBase; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.living.LivingEvent; + +/** + * [NYI] SpellCastEvent is the parent event class for all spell casting events.
    + *
    + * This event is fired on the {@link MinecraftForge#EVENT_BUS}. + * + * @author Electroblob + * @since Wizardry 2.1 + */ +public abstract class SpellCastEvent extends LivingEvent { + + public SpellCastEvent(EntityLivingBase entity, Spell spell) { + super(entity); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/IConjuredItem.java b/src/main/java/electroblob/wizardry/item/IConjuredItem.java new file mode 100644 index 00000000..6ae44c6e --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/IConjuredItem.java @@ -0,0 +1,32 @@ +package electroblob.wizardry.item; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +/** Allows wizardry to identify items that are conjured (and therefore need destroying if they leave the inventory) + * without explicitly referencing each, thereby allowing for better expandibility. */ +public interface IConjuredItem { + + /** The NBT tag key used to store the duration multiplier for conjured items. */ + public static final String DURATION_MULTIPLIER_KEY = "durationMultiplier"; + + /** Helper method for setting the duration multiplier (via NBT) for conjured items. */ + public static void setDurationMultiplier(ItemStack stack, float multiplier){ + if(!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound()); + stack.getTagCompound().setFloat(DURATION_MULTIPLIER_KEY, multiplier); + } + + /** Helper method for returning the max damage of a conjured item based on its NBT data. Centralises the code. + * Implementors will almost certainly want to call this from {@link Item#getMaxDamage(ItemStack stack)}. */ + public default int getMaxDamageFromNBT(ItemStack stack){ + if(stack.hasTagCompound() && stack.getTagCompound().hasKey(DURATION_MULTIPLIER_KEY)){ + return (int)(this.getBaseDuration() * stack.getTagCompound().getFloat(DURATION_MULTIPLIER_KEY)); + } + return this.getBaseDuration(); + } + + /** Returns the base duration in ticks for this conjured item. Should be a constant (commonly 600). + * Implementors may want to call this when setting an item's max damage in its constructor. */ + public int getBaseDuration(); +} diff --git a/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java b/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java new file mode 100644 index 00000000..dd7688d7 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java @@ -0,0 +1,59 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemArcaneTome extends Item { + + public ItemArcaneTome() { + super(); + this.setHasSubtypes(true); + this.setMaxStackSize(1); + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List list){ + for(int i=1; i tooltip, boolean showAdvanced){ + Tier tier = Tier.values()[stack.getItemDamage()]; + Tier tier2 = Tier.values()[stack.getItemDamage()-1]; + tooltip.add(tier.getDisplayNameWithFormatting()); + tooltip.add("\u00A77" + net.minecraft.client.resources.I18n.format("item.wizardry:arcane_tome.desc1", tier2.getDisplayNameWithFormatting())); + tooltip.add("\u00A77" + net.minecraft.client.resources.I18n.format("item.wizardry:arcane_tome.desc2", tier.getDisplayNameWithFormatting() + "\u00A77")); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemArmourUpgrade.java b/src/main/java/electroblob/wizardry/item/ItemArmourUpgrade.java new file mode 100644 index 00000000..b7b96f10 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemArmourUpgrade.java @@ -0,0 +1,46 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemArmourUpgrade extends Item { + + public ItemArmourUpgrade() { + super(); + this.setMaxStackSize(1); + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public EnumRarity getRarity(ItemStack stack){ + return EnumRarity.EPIC; + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack stack, EntityPlayer player, List tooltip, boolean advanced){ + tooltip.add(net.minecraft.client.resources.I18n.format("item.wizardry:armour_upgrade.desc1", "\u00A77")); + tooltip.add(net.minecraft.client.resources.I18n.format("item.wizardry:armour_upgrade.desc2", "\u00A77", "\u00A7d")); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List subItems){ + subItems.add(new ItemStack(this, 1)); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemFirebomb.java b/src/main/java/electroblob/wizardry/item/ItemFirebomb.java new file mode 100644 index 00000000..add289ef --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemFirebomb.java @@ -0,0 +1,50 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.entity.projectile.EntityFirebomb; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemFirebomb extends Item { + + public ItemFirebomb(){ + this.maxStackSize = 16; + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand){ + + if(!player.capabilities.isCreativeMode){ + --stack.stackSize; + } + + player.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); + + if(!world.isRemote){ + EntityFirebomb firebomb = new EntityFirebomb(world, player); + // This is the standard set of parameters for this method, used by snowballs and ender pearls. + firebomb.setHeadingFromThrower(player, player.rotationPitch, player.rotationYaw, 0.0f, 1.5f, 1.0f); + world.spawnEntityInWorld(firebomb); + } + + return ActionResult.newResult(EnumActionResult.SUCCESS, stack); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item parItem, CreativeTabs parTab, List parListSubItems){ + parListSubItems.add(new ItemStack(this, 1)); + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java b/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java new file mode 100644 index 00000000..28e1400b --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java @@ -0,0 +1,92 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemAxe; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemFlamingAxe extends ItemAxe implements IConjuredItem { + + public ItemFlamingAxe(ToolMaterial material) { + super(material, 8, -3); + this.setMaxDamage(getBaseDuration()); + this.setNoRepair(); + this.setCreativeTab(null); + } + + @Override + public int getBaseDuration(){ + return 600; + } + + @Override + public int getMaxDamage(ItemStack stack){ + return this.getMaxDamageFromNBT(stack); + } + + @Override + // This method allows the code for the item's timer to be greatly simplified by damaging it directly from + // onUpdate() and removing the workaround that involved WizardData and all sorts of crazy stuff. + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ + + if(oldStack != null || newStack != null){ + // We only care about the situation where we specifically want the animation NOT to play. + if(oldStack.getItem() == newStack.getItem() && !slotChanged) return false; + } + + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean selected){ + int damage = stack.getItemDamage(); + if(damage > stack.getMaxDamage()) entity.replaceItemInInventory(slot, null); + stack.setItemDamage(damage + 1); + } + + @Override + public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase wielder){ + if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)) target.setFire(8); + return false; + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + public boolean getIsRepairable(ItemStack stack, ItemStack par2ItemStack){ + return false; + } + + @Override + public int getItemEnchantability(){ + return 0; + } + + // Cannot be dropped + @Override + public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ + return false; + } + + @Override + @SideOnly(Side.CLIENT) + // Why does this method pass in an item as an argument? It is always the same item the method is invoked on. + public void getSubItems(Item item, CreativeTabs tab, List items){ + items.add(new ItemStack(this, 1)); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java b/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java new file mode 100644 index 00000000..0e6100e1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java @@ -0,0 +1,94 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemAxe; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemFrostAxe extends ItemAxe implements IConjuredItem { + + public ItemFrostAxe(ToolMaterial material) { + super(material, 8, -3); + this.setMaxDamage(getBaseDuration()); + this.setNoRepair(); + this.setCreativeTab(null); + } + + @Override + public int getBaseDuration(){ + return 600; + } + + @Override + public int getMaxDamage(ItemStack stack){ + return this.getMaxDamageFromNBT(stack); + } + + @Override + // This method allows the code for the item's timer to be greatly simplified by damaging it directly from + // onUpdate() and removing the workaround that involved WizardData and all sorts of crazy stuff. + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ + + if(oldStack != null || newStack != null){ + // We only care about the situation where we specifically want the animation NOT to play. + if(oldStack.getItem() == newStack.getItem() && !slotChanged) return false; + } + + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean selected){ + int damage = stack.getItemDamage(); + if(damage > stack.getMaxDamage()) entity.replaceItemInInventory(slot, null); + stack.setItemDamage(damage + 1); + } + + @Override + public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase wielder) + { + if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 160, 1)); + return false; + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + public boolean getIsRepairable(ItemStack stack, ItemStack par2ItemStack){ + return false; + } + + @Override + public int getItemEnchantability(){ + return 0; + } + + // Cannot be dropped + @Override + public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ + return false; + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item parItem, CreativeTabs parTab, List parListSubItems){ + parListSubItems.add(new ItemStack(this, 1)); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemIdentificationScroll.java b/src/main/java/electroblob/wizardry/item/ItemIdentificationScroll.java new file mode 100644 index 00000000..da85487d --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemIdentificationScroll.java @@ -0,0 +1,81 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemIdentificationScroll extends Item { + + public ItemIdentificationScroll() { + super(); + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack stack, EntityPlayer player, List tooltip, boolean par4){ + tooltip.add(net.minecraft.client.resources.I18n.format("item.wizardry:identification_scroll.desc1", "\u00A77")); + tooltip.add(net.minecraft.client.resources.I18n.format("item.wizardry:identification_scroll.desc2", "\u00A77")); + } + + @Override + public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand){ + + if(WizardData.get(player) != null){ + + WizardData properties = WizardData.get(player); + + for(ItemStack stack1 : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){ + + if(stack1 != null){ + Spell spell = Spell.get(stack1.getItemDamage()); + if((stack1.getItem() instanceof ItemSpellBook || stack1.getItem() instanceof ItemScroll) + && !properties.hasSpellBeenDiscovered(spell)){ + + // Identification scrolls give the chat readout in creative mode, otherwise it looks like + // nothing happens! + properties.discoverSpell(spell); + player.addStat(WizardryAchievements.identify_spell); + player.playSound(SoundEvents.ENTITY_PLAYER_LEVELUP, 1.25f, 1); + if(!player.capabilities.isCreativeMode) stack.stackSize--; + if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("spell.discover", spell.getNameForTranslationFormatted())); + + return new ActionResult(EnumActionResult.SUCCESS, stack); + } + } + } + // If it found nothing to identify, it says so! + if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("item.wizardry:identification_scroll.nothing_to_identify")); + } + + return new ActionResult(EnumActionResult.FAIL, stack); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item parItem, CreativeTabs parTab, List parListSubItems){ + parListSubItems.add(new ItemStack(this, 1)); + } +} diff --git a/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java b/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java new file mode 100644 index 00000000..94261841 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java @@ -0,0 +1,51 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.entity.projectile.EntityPoisonBomb; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemPoisonBomb extends Item { + + public ItemPoisonBomb(){ + this.maxStackSize = 16; + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand){ + + if(!player.capabilities.isCreativeMode){ + --stack.stackSize; + } + + player.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); + + if(!world.isRemote){ + EntityPoisonBomb poisonbomb = new EntityPoisonBomb(world, player); + // This is the standard set of parameters for this method, used by snowballs and ender pearls. + poisonbomb.setHeadingFromThrower(player, player.rotationPitch, player.rotationYaw, 0.0f, 1.5f, 1.0f); + world.spawnEntityInWorld(poisonbomb); + } + + return ActionResult.newResult(EnumActionResult.SUCCESS, stack); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List subItems){ + subItems.add(new ItemStack(this, 1)); + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/item/ItemScroll.java b/src/main/java/electroblob/wizardry/item/ItemScroll.java new file mode 100644 index 00000000..e238b5b8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemScroll.java @@ -0,0 +1,139 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketCastSpell; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemScroll extends Item { + + public ItemScroll(){ + super(); + this.setHasSubtypes(true); + this.setMaxStackSize(1); + this.setCreativeTab(WizardryTabs.SPELLS); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List list){ + // Isn't this sooooo much neater with the filter thing? + for(Spell spell : Spell.getSpells(Spell.nonContinuousSpells)){ + list.add(new ItemStack(item, 1, spell.id())); + } + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + // Item's version of this method is, quite frankly, an abomination. Why is a deprecated method being used as such + // an integral part of the code? And what's the point in getUnlocalisedNameInefficiently? + public String getItemStackDisplayName(ItemStack stack){ + + /* Ok, so this method can be called from either the client or the server side. Obviously, on the client the + * spell name is either translated or obfuscated, then it is put into the item name as part of that translation. + * On the server side, however, there's a problem: on the one hand, the spell name shouldn't be obfuscated in + * case the server wants to do something with it, and in that case returning world-specific gobbledegook is + * not particularly helpful. On the other hand, something might happen that causes this method to be called on + * the server side, but the result to then be sent to the client, which means broken discovery system. + * Simply put, I can't predict that, and it's not my job to cater for other people's incorrect usage of code, + * especially when that might compromise some perfectly reasonable use (think Bibliocraft's 'best guess' book + * detection). */ + // TODO: Backport this proxy-based fix. + return Wizardry.proxy.getScrollDisplayName(stack); + + } + + @Override + public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand){ + + if(player.isPotionActive(WizardryPotions.arcane_jammer)) return new ActionResult(EnumActionResult.FAIL, stack);; + + Spell spell = Spell.get(stack.getItemDamage()); + + // If a spell is disabled in the config, it will not work. + if(!spell.isEnabled()){ + if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("spell.disabled", spell.getNameForTranslationFormatted())); + return new ActionResult(EnumActionResult.FAIL, stack); + } + + if(!spell.isContinuous){ + + /* + if(spell.chargeup > 0 && !entityplayer.isUsingItem()){ + // Spells with a chargeup time are now handled separately. + entityplayer.setItemInUse(stack, this.getMaxItemUseDuration(stack)); + return stack; + } + */ + + if(!world.isRemote){ + + if(spell.cast(world, player, hand, 0, new SpellModifiers())){ + + if(spell.doesSpellRequirePacket()){ + // Sends a packet to all players in dimension to tell them to spawn particles. + IMessage msg = new PacketCastSpell.Message(player.getEntityId(), hand, spell.id(), new SpellModifiers()); + WizardryPacketHandler.net.sendToDimension(msg, world.provider.getDimension()); + } + + if(!player.capabilities.isCreativeMode && !WizardData.get(player).hasSpellBeenDiscovered(spell) && Wizardry.settings.discoveryMode){ + player.playSound(SoundEvents.ENTITY_PLAYER_LEVELUP, 1.25f, 1); + if(!player.worldObj.isRemote) player.addChatMessage(new TextComponentTranslation("spell.discover", spell.getNameForTranslationFormatted())); + } + WizardData.get(player).discoverSpell(spell); + + if(!player.capabilities.isCreativeMode) stack.stackSize--; + + return new ActionResult(EnumActionResult.SUCCESS, stack); + } + + // Client-inconsistent spell casting. The code inside the else if statement only runs client-side. + // This else if check was bugging me for AGES! I can't believe I didn't compare to ItemWand before. + }else if(!spell.doesSpellRequirePacket()){ + // This is all that needs to happen, because everything above works fine on just the server side. + if(spell.cast(world, player, hand, 0, new SpellModifiers())){ + // Added in version 1.1.3 to fix the client-side spell discovery not updating for spells with the + // packet optimisation. + if(WizardData.get(player) != null){ + WizardData.get(player).discoverSpell(spell); + } + + new ActionResult(EnumActionResult.SUCCESS, stack); + } + } + } + + return new ActionResult(EnumActionResult.FAIL, stack); + + } + + @Override + @SideOnly(Side.CLIENT) + public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack){ + return Wizardry.proxy.getFontRenderer(stack); + } +} diff --git a/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java b/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java new file mode 100644 index 00000000..a2180d97 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java @@ -0,0 +1,50 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.entity.projectile.EntitySmokeBomb; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemSmokeBomb extends Item { + + public ItemSmokeBomb(){ + this.maxStackSize = 16; + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand){ + + if(!player.capabilities.isCreativeMode){ + --stack.stackSize; + } + + player.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); + + if(!world.isRemote){ + EntitySmokeBomb smokebomb = new EntitySmokeBomb(world, player); + // This is the standard set of parameters for this method, used by snowballs and ender pearls. + smokebomb.setHeadingFromThrower(player, player.rotationPitch, player.rotationYaw, 0.0f, 1.5f, 1.0f); + world.spawnEntityInWorld(smokebomb); + } + + return ActionResult.newResult(EnumActionResult.SUCCESS, stack); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List subItems){ + subItems.add(new ItemStack(this, 1)); + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java b/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java new file mode 100644 index 00000000..951b69d9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java @@ -0,0 +1,110 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemArmor; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemSpectralArmour extends ItemArmor implements IConjuredItem { + + public ItemSpectralArmour(ArmorMaterial material, int renderIndex, EntityEquipmentSlot armourType) { + + super(material, renderIndex, armourType); + + this.setCreativeTab(null); + this.setMaxDamage(getBaseDuration()); + } + + @Override + public int getBaseDuration(){ + return 1200; + } + + @Override + public int getMaxDamage(ItemStack stack){ + return this.getMaxDamageFromNBT(stack); + } + + // Overridden to stop the enchantment trick making the name turn blue. + @Override + public EnumRarity getRarity(ItemStack stack){ + return EnumRarity.COMMON; + } + + @Override + // This method allows the code for the item's timer to be greatly simplified by damaging it directly from + // onUpdate() and removing the workaround that involved WizardData and all sorts of crazy stuff. + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ + + if(oldStack != null || newStack != null){ + // We only care about the situation where we specifically want the animation NOT to play. + if(oldStack.getItem() == newStack.getItem() && !slotChanged) return false; + } + + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public void onArmorTick(World world, EntityPlayer player, ItemStack stack){ + int damage = stack.getItemDamage(); + if(damage > stack.getMaxDamage()) player.inventory.clearMatchingItems(this, -1, 1, null); + stack.setItemDamage(damage + 1); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + public boolean getIsRepairable(ItemStack stack, ItemStack par2ItemStack){ + return false; + } + + @Override + public int getItemEnchantability(){ + return 0; + } + + // Cannot be dropped + @Override + public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ + return false; + } + + @Override + public String getArmorTexture(ItemStack stack, Entity entity, EntityEquipmentSlot slot, String type) { + + if(slot == EntityEquipmentSlot.LEGS) return "wizardry:textures/armour/spectral_armour_legs.png"; + + return "wizardry:textures/armour/spectral_armour.png"; + } + + @Override + @SideOnly(Side.CLIENT) + public net.minecraft.client.model.ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, EntityEquipmentSlot armorSlot, + net.minecraft.client.model.ModelBiped _default) { + net.minecraft.client.renderer.GlStateManager.enableBlend(); + net.minecraft.client.renderer.GlStateManager.tryBlendFuncSeparate(net.minecraft.client.renderer.GlStateManager.SourceFactor.SRC_ALPHA, net.minecraft.client.renderer.GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + net.minecraft.client.renderer.GlStateManager.SourceFactor.ONE, net.minecraft.client.renderer.GlStateManager.DestFactor.ZERO); + return super.getArmorModel(entityLiving, itemStack, armorSlot, _default); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item parItem, CreativeTabs parTab, List parListSubItems){ + parListSubItems.add(new ItemStack(this, 1)); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java b/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java new file mode 100644 index 00000000..b25efc8d --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java @@ -0,0 +1,229 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import javax.annotation.Nullable; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.Minecraft; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.init.Enchantments; +import net.minecraft.init.Items; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.IItemPropertyGetter; +import net.minecraft.item.Item; +import net.minecraft.item.ItemArrow; +import net.minecraft.item.ItemBow; +import net.minecraft.item.ItemStack; +import net.minecraft.stats.StatList; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundCategory; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemSpectralBow extends ItemBow implements IConjuredItem { + + public ItemSpectralBow(){ + super(); + this.setMaxDamage(getBaseDuration()); + this.setNoRepair(); + this.setCreativeTab(null); + this.addPropertyOverride(new ResourceLocation("pull"), new IItemPropertyGetter() + { + @SideOnly(Side.CLIENT) + public float apply(ItemStack stack, @Nullable World worldIn, @Nullable EntityLivingBase entityIn) + { + if (entityIn == null) + { + return 0.0F; + } + else + { + ItemStack itemstack = entityIn.getActiveItemStack(); + // Mojang, observe - hardcoding item references into their own classes is NOT good Java. + return itemstack != null && itemstack.getItem() == ItemSpectralBow.this ? (float)(stack.getMaxItemUseDuration() - entityIn.getItemInUseCount()) / 20.0F : 0.0F; + } + } + }); + this.addPropertyOverride(new ResourceLocation("pulling"), new IItemPropertyGetter() + { + @SideOnly(Side.CLIENT) + public float apply(ItemStack stack, @Nullable World worldIn, @Nullable EntityLivingBase entityIn) + { + return entityIn != null && entityIn.isHandActive() && entityIn.getActiveItemStack() == stack ? 1.0F : 0.0F; + } + }); + } + + @Override + @SideOnly(Side.CLIENT) + // Why does this still exist? Item models deal with this now, right? + public boolean isFull3D(){ + return true; + } + + @Override + public int getBaseDuration(){ + return 600; + } + + @Override + public int getMaxDamage(ItemStack stack){ + return this.getMaxDamageFromNBT(stack); + } + + @Override + // This method allows the code for the item's timer to be greatly simplified by damaging it directly from + // onUpdate() and removing the workaround that involved WizardData and all sorts of crazy stuff. + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ + + if(oldStack != null && newStack != null){ + // We only care about the situation where we specifically want the animation NOT to play. + if(oldStack.getItem() == newStack.getItem() && !slotChanged + // This code should only run on the client side, so using Minecraft is ok. + && !Minecraft.getMinecraft().thePlayer.isHandActive()) return false; + } + + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean selected){ + int damage = stack.getItemDamage(); + if(damage > stack.getMaxDamage()) entity.replaceItemInInventory(slot, null); + // Can't damage it whilst in use because for some reason it causes the item use to constantly reset. + if(!(entity instanceof EntityLivingBase) || !((EntityLivingBase)entity).isHandActive()){ + stack.setItemDamage(damage + 1); + } + } + + // The following two methods re-route the displayed durability through the proxies in order to override the pausing + // of the item timer when the bow is being pulled. + + @Override + public double getDurabilityForDisplay(ItemStack stack){ + return Wizardry.proxy.getConjuredBowDurability(stack); + } + + public double getDefaultDurabilityForDisplay(ItemStack stack){ + return super.getDurabilityForDisplay(stack); + } + + @Override + public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand){ + + ActionResult ret = net.minecraftforge.event.ForgeEventFactory.onArrowNock(stack, world, player, hand, true); + + if(ret != null) return ret; + + player.setActiveHand(hand); + + return ActionResult.newResult(EnumActionResult.SUCCESS, stack); + + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + public boolean getIsRepairable(ItemStack stack, ItemStack stack2){ + return false; + } + + @Override + public int getItemEnchantability(){ + return 0; + } + + // Cannot be dropped + @Override + public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ + return false; + } + + @Override + public void onUsingTick(ItemStack stack, EntityLivingBase player, int count){ + // player.getItemInUseMaxCount() is named incorrectly; you only have to look at the method to see what it really + // does. + if(stack.getItemDamage() + player.getItemInUseMaxCount() > stack.getMaxDamage()) + player.replaceItemInInventory(player.getActiveHand() == EnumHand.MAIN_HAND ? 98 : 99, null); + } + + @Override + public void onPlayerStoppedUsing(ItemStack stack, World world, EntityLivingBase entity, int timeLeft){ + // Decreases the timer by the amount it should have been decreased while the bow was in use. + if(!world.isRemote) stack.setItemDamage(stack.getItemDamage() + (this.getMaxItemUseDuration(stack) - timeLeft)); + + if (entity instanceof EntityPlayer){ + + EntityPlayer entityplayer = (EntityPlayer)entity; + + int i = this.getMaxItemUseDuration(stack) - timeLeft; + i = net.minecraftforge.event.ForgeEventFactory.onArrowLoose(stack, world, (EntityPlayer)entity, i, true); + if (i < 0) return; + + float f = getArrowVelocity(i); + + if ((double)f >= 0.1D){ + + if (!world.isRemote){ + + ItemArrow itemarrow = (ItemArrow)Items.ARROW; + EntityArrow entityarrow = itemarrow.createArrow(world, new ItemStack(itemarrow), entityplayer); + entityarrow.setAim(entityplayer, entityplayer.rotationPitch, entityplayer.rotationYaw, 0.0F, f * 3.0F, 1.0F); + + if (f == 1.0F) + { + entityarrow.setIsCritical(true); + } + + int j = EnchantmentHelper.getEnchantmentLevel(Enchantments.POWER, stack); + + if (j > 0) + { + entityarrow.setDamage(entityarrow.getDamage() + (double)j * 0.5D + 0.5D); + } + + int k = EnchantmentHelper.getEnchantmentLevel(Enchantments.PUNCH, stack); + + if (k > 0) + { + entityarrow.setKnockbackStrength(k); + } + + if (EnchantmentHelper.getEnchantmentLevel(Enchantments.FLAME, stack) > 0) + { + entityarrow.setFire(100); + } + + entityarrow.pickupStatus = EntityArrow.PickupStatus.DISALLOWED; + + world.spawnEntityInWorld(entityarrow); + } + + world.playSound((EntityPlayer)null, entityplayer.posX, entityplayer.posY, entityplayer.posZ, SoundEvents.ENTITY_ARROW_SHOOT, SoundCategory.NEUTRAL, 1.0F, 1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + f * 0.5F); + + entityplayer.addStat(StatList.getObjectUseStats(this)); + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List subItems){ + subItems.add(new ItemStack(this, 1)); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java b/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java new file mode 100644 index 00000000..a91c9000 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java @@ -0,0 +1,82 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemPickaxe; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemSpectralPickaxe extends ItemPickaxe implements IConjuredItem { + + public ItemSpectralPickaxe(ToolMaterial material){ + super(material); + this.setMaxDamage(getBaseDuration()); + this.setNoRepair(); + this.setCreativeTab(null); + } + + @Override + public int getBaseDuration(){ + return 600; + } + + @Override + public int getMaxDamage(ItemStack stack){ + return this.getMaxDamageFromNBT(stack); + } + + @Override + // This method allows the code for the item's timer to be greatly simplified by damaging it directly from + // onUpdate() and removing the workaround that involved WizardData and all sorts of crazy stuff. + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ + + if(oldStack != null || newStack != null){ + // We only care about the situation where we specifically want the animation NOT to play. + if(oldStack.getItem() == newStack.getItem() && !slotChanged) return false; + } + + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean selected){ + int damage = stack.getItemDamage(); + if(damage > stack.getMaxDamage()) entity.replaceItemInInventory(slot, null); + stack.setItemDamage(damage + 1); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + public boolean getIsRepairable(ItemStack stack, ItemStack par2ItemStack){ + return false; + } + + @Override + public int getItemEnchantability(){ + return 0; + } + + // Cannot be dropped + @Override + public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ + return false; + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List subItems){ + subItems.add(new ItemStack(this, 1)); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java b/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java new file mode 100644 index 00000000..b1db6b6e --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java @@ -0,0 +1,82 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemSword; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemSpectralSword extends ItemSword implements IConjuredItem { + + public ItemSpectralSword(ToolMaterial material) { + super(material); + this.setMaxDamage(getBaseDuration()); + this.setNoRepair(); + this.setCreativeTab(null); + } + + @Override + public int getBaseDuration(){ + return 600; + } + + @Override + public int getMaxDamage(ItemStack stack){ + return this.getMaxDamageFromNBT(stack); + } + + @Override + // This method allows the code for the item's timer to be greatly simplified by damaging it directly from + // onUpdate() and removing the workaround that involved WizardData and all sorts of crazy stuff. + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ + + if(oldStack != null || newStack != null){ + // We only care about the situation where we specifically want the animation NOT to play. + if(oldStack.getItem() == newStack.getItem() && !slotChanged) return false; + } + + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean selected){ + int damage = stack.getItemDamage(); + if(damage > stack.getMaxDamage()) entity.replaceItemInInventory(slot, null); + stack.setItemDamage(damage + 1); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + public boolean getIsRepairable(ItemStack stack, ItemStack par2ItemStack){ + return false; + } + + @Override + public int getItemEnchantability(){ + return 0; + } + + // Cannot be dropped + @Override + public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ + return false; + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List subItems){ + subItems.add(new ItemStack(this, 1)); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java new file mode 100644 index 00000000..742c660a --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java @@ -0,0 +1,82 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.SpellGlyphData; +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.WizardryGuiHandler; +import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.spell.Spell; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.oredict.OreDictionary; + +public class ItemSpellBook extends Item { + + public ItemSpellBook() { + super(); + this.setHasSubtypes(true); + this.setMaxStackSize(1); + this.setCreativeTab(WizardryTabs.SPELLS); + } + + @Override + public void getSubItems(Item item, CreativeTabs tab, List list){ + // In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance + // is not required, only the id. + for(int i = 0; i < Spell.getTotalSpellCount(); i++){ + // i+1 is used so that the metadata ties up with the id() method. In other words, the none spell has id + // 0 and since this is not used as a spell book the metadata starts at 1. + list.add(new ItemStack(item, 1, i+1)); + } + } + + @Override + public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand){ + player.openGui(Wizardry.instance, WizardryGuiHandler.SPELL_BOOK, world, 0, 0, 0); + return ActionResult.newResult(EnumActionResult.SUCCESS, stack); + } + + @Override + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack itemstack, EntityPlayer player, List tooltip, boolean advanced){ + // Tooltip is left blank for wizards buying generic spell books. + if(itemstack.getItemDamage() != OreDictionary.WILDCARD_VALUE){ + + Spell spell = Spell.get(itemstack.getItemDamage()); + + boolean discovered = true; + if(Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null + && !WizardData.get(player).hasSpellBeenDiscovered(spell)){ + discovered = false; + } + + // Element colour is not given for undiscovered spells + tooltip.add(discovered ? "\u00A77" + spell.getDisplayNameWithFormatting() : "#\u00A79" + SpellGlyphData.getGlyphName(spell, player.worldObj)); + tooltip.add(spell.tier.getDisplayNameWithFormatting()); + } + /* Removed to streamline the tooltip a bit. Information is now within the book. + if(spell.isContinuous){ + tooltip.add("\u00A79Mana Cost: " + spell.cost + " per second"); + }else{ + tooltip.add("\u00A79Mana Cost: " + spell.cost); + } + */ + } + + @Override + @SideOnly(Side.CLIENT) + public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack){ + return Wizardry.proxy.getFontRenderer(stack); + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemWand.java b/src/main/java/electroblob/wizardry/item/ItemWand.java new file mode 100644 index 00000000..59d126e5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemWand.java @@ -0,0 +1,430 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.SpellGlyphData; +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.ISummonedCreature; +import electroblob.wizardry.packet.PacketCastSpell; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WandHelper; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumAction; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** This class is (literally) where the magic happens! All wand types are single instances of this class. There's a lot + * of quite hard-to-read code in here, but unfortunately there's not much I can do about that. For this reason, I have + * written the {@link WandHelper} class. I strongly recommend you use it for interacting with wand items wherever + * possible. + *

    + * It's unikely that anything in this class will be of much use externally, but should you wish to use it for whatever + * reason (perhaps if you extend it), it works as follows: + *

    + * - onItemRightClick is where non-continuous spells are cast, and it sets the item in use for continuous spells
    + * - onUsingTick does the casting for continuous spells
    + * - onUpdate deals with the cooldowns for the spells + * @since Wizardry 1.0 */ +public class ItemWand extends Item { + + public Tier tier; + public Element element; + + public ItemWand(Tier tier, Element element) { + super(); + setMaxStackSize(1); + if(element == null || tier == Tier.BASIC){ + setCreativeTab(WizardryTabs.WIZARDRY); + } + this.tier = tier; + this.element = element; + this.setMaxDamage(this.tier.maxCharge); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean isFull3D(){ + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack){ + return Wizardry.proxy.getFontRenderer(stack); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item parItem, CreativeTabs parTab, List parListSubItems){ + parListSubItems.add(new ItemStack(this, 1)); + } + + // Max damage is modifiable with upgrades. + @Override + public int getMaxDamage(ItemStack itemstack){ + // + 0.5f corrects small float errors rounding down + return (int)(super.getMaxDamage(itemstack)*(1.0f + Constants.STORAGE_INCREASE_PER_LEVEL * WandHelper.getUpgradeLevel(itemstack, WizardryItems.storage_upgrade)) + 0.5f); + } + + @Override + public void onCreated(ItemStack stack, World par2World, EntityPlayer par3EntityPlayer){ + /* Removed because of mana flasks, which would cause a new book to be given each time a mana flask + * is crafted with the wand. Handbook is now given on acquiring a crystal. + ExtendedPlayer properties = ExtendedPlayer.get(par3EntityPlayer); + if(properties != null && !properties.handbookGiven){ + par3EntityPlayer.inventory.addItemStackToInventory(new ItemStack(Wizardry.wizardHandbook)); + properties.handbookGiven = true; + }*/ + par3EntityPlayer.addStat(WizardryAchievements.arcane_initiate); + } + + @Override + public void onUpdate(ItemStack itemstack, World world, Entity entity, int slot, boolean isHeld){ + + WandHelper.decrementCooldowns(itemstack); + + // Decrements wand damage (increases mana) every 1.5 seconds if it has a condenser upgrade + if(!world.isRemote && itemstack.isItemDamaged() && world.getWorldTime() % Constants.CONDENSER_TICK_INTERVAL == 0){ + // If the upgrade level is 0, this does nothing anyway. + itemstack.setItemDamage(itemstack.getItemDamage() - WandHelper.getUpgradeLevel(itemstack, WizardryItems.condenser_upgrade)); + } + + if(entity instanceof EntityPlayer && this.element != null && this.element != Element.MAGIC){ + // As it stands, this will trigger every tick. Not ideal, but I can't find a way to detect if a player + // has a certain achievement. + // EDIT: There is a way to check, using StatFileWriter#hasAchievementUnlocked, but this ends up calling the same + // thing as addStat anyway, meaning there's no point and it's probably not much of a problem anyway. + ((EntityPlayer)entity).addStat(WizardryAchievements.elemental); + } + } + + @Override + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ + + // This method does some VERY strange things! Despite its name, it also seems to affect the updating of NBT... + + if(oldStack != null || newStack != null){ + // We only care about the situation where we specifically want the animation NOT to play. + if(oldStack.getItem() == newStack.getItem() && !slotChanged + && oldStack.getItem() instanceof ItemWand && newStack.getItem() instanceof ItemWand + && WandHelper.getCurrentSpell(oldStack) == WandHelper.getCurrentSpell(newStack)) return false; + } + + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public EnumAction getItemUseAction(ItemStack itemstack){ + return WandHelper.getCurrentSpell(itemstack).action; + } + + @Override + public int getMaxItemUseDuration(ItemStack stack){ + return 72000; + } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List text, boolean advanced){ + + // +0.5f is necessary due to the error in the way floats are calculated. + if(element != null) text.add("\u00A78" + net.minecraft.client.resources.I18n.format("item.wizardry:wand.buff", (int)((tier.level+1)*Constants.DAMAGE_INCREASE_PER_TIER*100 + 0.5f) + "%", element.getDisplayName())); + + Spell spell = WandHelper.getCurrentSpell(itemstack); + + boolean discovered = true; + if(Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null + && !WizardData.get(player).hasSpellBeenDiscovered(spell)){ + discovered = false; + } + + text.add("\u00A77" + net.minecraft.client.resources.I18n.format("item.wizardry:wand.spell", discovered ? "\u00A77" + spell.getDisplayNameWithFormatting() : "#\u00A79" + SpellGlyphData.getGlyphName(spell, player.worldObj))); + + text.add("\u00A79" + net.minecraft.client.resources.I18n.format("item.wizardry:wand.mana", (this.getMaxDamage(itemstack) - this.getDamage(itemstack)), this.getMaxDamage(itemstack))); + } + + @Override + public String getItemStackDisplayName(ItemStack stack){ + return (this.element == null ? "" : this.element.getFormattingCode()) + super.getItemStackDisplayName(stack); + } + + // Continuous spells use the onUsingItemTick method instead of this one. + /* An important thing to note about this method: it is only called on the server and the client of the player + * holding the item. This means if you spawn particles here they will not show up on other players' screens. + * Instead, this must be done via packets. */ + @Override + public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand){ + + if(this.selectMinionTarget(player, world)) return new ActionResult(EnumActionResult.SUCCESS, stack); + + if(player.isPotionActive(WizardryPotions.arcane_jammer)) return new ActionResult(EnumActionResult.FAIL, stack); + + Spell spell = WandHelper.getCurrentSpell(stack); + + // If a spell is disabled in the config, it will not work. + if(!spell.isEnabled()){ + if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("spell.disabled", spell.getNameForTranslationFormatted())); + return new ActionResult(EnumActionResult.FAIL, stack); + } + + // This is here to start the inUse thing, otherwise the onItemUsingTick method will not fire. + // If the castSpell method then returns false nothing will happen (continuous spells have no EnumAction + // either so setting the item in use has no direct visible effect). + // Edit: Strictly speaking this is not true but the spells that do have an action (shield, shadow ward and levitation) + // will never return false. + if(spell.isContinuous && !player.isHandActive()){ + player.setActiveHand(hand); + } + + // Conditions for the spell to be attempted. The tier check is a failsafe; it should never be false unless the + // NBT is modified directly. + if(!spell.isContinuous && spell.tier.level <= this.tier.level + // Checks that the wand has enough mana to cast the spell + && spell.cost <= (stack.getMaxDamage() - stack.getItemDamage()) + // Checks that the spell is not in cooldown or that the player is in creative mode + && (WandHelper.getCurrentCooldown(stack) == 0 || player.capabilities.isCreativeMode)){ + + // = Spell modifiers = + SpellModifiers modifiers = this.calculateModifiers(stack, spell); + + // If the spell does not require a packet, the code is run in the old client-inconsistent way, since this + // means that swingItem() doesn't need packets in order to work, improving performance. + if(!world.isRemote){ + + if(spell.cast(world, player, hand, 0, modifiers)){ + + // = Packets = + if(spell.doesSpellRequirePacket()){ + // Sends a packet to all players in dimension to tell them to spawn particles. + // Only sent if the spell succeeded, because if the spell failed, you wouldn't + // need to spawn any particles! + IMessage msg = new PacketCastSpell.Message(player.getEntityId(), hand, spell.id(), modifiers); + WizardryPacketHandler.net.sendToDimension(msg, world.provider.getDimension()); + } + + player.setActiveHand(hand); + + WizardData data = WizardData.get(player); + + // = Discovery = + if(data != null && !player.capabilities.isCreativeMode && !data.hasSpellBeenDiscovered(spell) && Wizardry.settings.discoveryMode){ + // We are only server side here, so we need to play the sound on the server side to everyone. + world.playSound(null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_PLAYER_LEVELUP, + SoundCategory.PLAYERS, 1.25f, 1); + player.addChatMessage(new TextComponentTranslation("spell.discover", spell.getNameForTranslationFormatted())); + } + WizardData.get(player).discoverSpell(spell); + + // = Cooldown = + // Spells only have a cooldown in survival + if(!player.capabilities.isCreativeMode){ + + float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(stack, WizardryItems.cooldown_upgrade)*Constants.COOLDOWN_REDUCTION_PER_LEVEL; + + if(player.isPotionActive(WizardryPotions.font_of_mana)){ + // Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously + cooldownMultiplier /= 2 + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier(); + } + + WandHelper.setCurrentCooldown(stack, (int)(spell.cooldown * cooldownMultiplier)); + } + + // = Mana cost = + // The spell costs 20% less for every armour piece of the matching element. + int armourPieces = getMatchingArmourCount(player, spell); + + stack.damageItem((int)(spell.cost * (1.0f - armourPieces*Constants.COST_REDUCTION_PER_ARMOUR)), player); + + return new ActionResult(EnumActionResult.SUCCESS, stack); + } + + // Client-inconsistent spell casting. The code inside the else if statement only runs client-side. + }else if(!spell.doesSpellRequirePacket()){ + // This is all that needs to happen, because everything above works fine on just the server side. + if(spell.cast(world, player, hand, 0, new SpellModifiers())){ + // Added in version 1.1.3 to fix the client-side spell discovery not updating for spells with the + // packet optimisation. + if(WizardData.get(player) != null){ + WizardData.get(player).discoverSpell(spell); + } + + new ActionResult(EnumActionResult.SUCCESS, stack); + } + } + } + + return new ActionResult(EnumActionResult.FAIL, stack); + } + + // For continuous spells. The count argument actually decrements by 1 each tick. + @Override + public void onUsingTick(ItemStack stack, EntityLivingBase user, int count){ + + if(user instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)user; + + Spell spell = WandHelper.getCurrentSpell(stack); + + WizardData data = WizardData.get(player); + + // Continuous spells (these must check if they can be cast each tick since the mana changes) + if(spell.isContinuous && spell.tier.level <= this.tier.level + && spell.cost/5 <= (stack.getMaxDamage() - stack.getItemDamage())){ + + // = Spell modifiers = + SpellModifiers modifiers = this.calculateModifiers(stack, spell); + + if(spell.cast(player.worldObj, player, player.getActiveHand(), stack.getMaxItemUseDuration() - count, modifiers)){ + + // = Discovery = + if(data != null && !player.capabilities.isCreativeMode && !data.hasSpellBeenDiscovered(spell) && Wizardry.settings.discoveryMode){ + player.playSound(SoundEvents.ENTITY_PLAYER_LEVELUP, 1.25f, 1); + if(!player.worldObj.isRemote) player.addChatMessage(new TextComponentTranslation("spell.discover", spell.getNameForTranslationFormatted())); + } + data.discoverSpell(spell); + + // = Mana cost = + // Divides the mana cost over a second appropriately; since damage is an integer it cannot + // just be divided by 20. + // Now does five times per second regardless of the spell cost, but each time it does 1/5 of the + // cost per second. + int tickNumber = (count % 20) + 1; + // Tests if the tick counter is a multiple of 4 plus 1, i.e. is true when tickNumber = 1, 5, 9, 13 or 17. + // Made a slight adjustment since the counter starts on 1 and not 4. + if(tickNumber % 4 == 1){ + + int armourPieces = getMatchingArmourCount(player, spell); + + switch(armourPieces){ + + case 0: stack.damageItem(spell.cost/5, player); + break; + + case 1: if(tickNumber != 17) stack.damageItem(spell.cost/5, player); + break; + + case 2: if(tickNumber != 9 && tickNumber != 17) stack.damageItem(spell.cost/5, player); + break; + + case 3: if(tickNumber != 5 && tickNumber != 13 && tickNumber != 17) stack.damageItem(spell.cost/5, player); + break; + + case 4: if(tickNumber == 1) stack.damageItem(spell.cost/5, player); + break; + + } + } + } + } + } + } + + /** Returns a SpellModifiers object with the appropriate modifiers applied for the given ItemStack and Spell. */ + protected SpellModifiers calculateModifiers(ItemStack stack, Spell spell){ + + SpellModifiers modifiers = new SpellModifiers(); + + // Now we only need to add multipliers if they are not 1. + int level = WandHelper.getUpgradeLevel(stack, WizardryItems.range_upgrade); + if(level > 0) modifiers.set(WizardryItems.range_upgrade, 1.0f + level * Constants.RANGE_INCREASE_PER_LEVEL, true); + + level = WandHelper.getUpgradeLevel(stack, WizardryItems.duration_upgrade); + if(level > 0) modifiers.set(WizardryItems.duration_upgrade, 1.0f + level * Constants.DURATION_INCREASE_PER_LEVEL, false); + + level = WandHelper.getUpgradeLevel(stack, WizardryItems.blast_upgrade); + if(level > 0) modifiers.set(WizardryItems.blast_upgrade, 1.0f + level * Constants.BLAST_RADIUS_INCREASE_PER_LEVEL, true); + + // I would have liked to have made potion effects increase in strength according to the damage multiplier, + // but the amplifier level is too discrete to make this work. For example, wither 3 for 10 seconds will kill a + // normal mob on full 20 health, but wither 2 for the same duration only deals about 6 hearts of damage in total. + if(this.element == spell.element){ + modifiers.set(SpellModifiers.DAMAGE, 1.0f + (this.tier.level + 1) * Constants.DAMAGE_INCREASE_PER_TIER, true); + } + + return modifiers; + } + + @Override + public boolean itemInteractionForEntity(ItemStack stack, EntityPlayer player, EntityLivingBase entity, EnumHand hand){ + + if(player.isSneaking() && entity instanceof EntityPlayer && WizardData.get(player) != null){ + // This is one of those "the method doing the work looks as if it's just returning a value" situations. + // ... I know, right?! I feel very programmer-y. But it's not too confusing here, and it looks neat. + String string = WizardData.get(player).toggleAlly((EntityPlayer)entity) ? "item.wizardry:wand.addally" : "item.wizardry:wand.removeally"; + if(!player.worldObj.isRemote) player.addChatMessage(new TextComponentTranslation(string, entity.getName())); + return true; + } + + return false; + } + + /** Counts the number of armour pieces the given player is wearing that match the given spell's element. */ + private int getMatchingArmourCount(EntityPlayer player, Spell spell){ + + int armourPieces = 0; + + for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ + + ItemStack armour = player.getItemStackFromSlot(slot); + + if(armour != null && armour.getItem() instanceof ItemWizardArmour + && ((ItemWizardArmour)armour.getItem()).element == spell.element) armourPieces++; + } + + return armourPieces; + } + + private boolean selectMinionTarget(EntityPlayer player, World world){ + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, player, 16); + + if(rayTrace != null && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase entity = (EntityLivingBase)rayTrace.entityHit; + + // Sets the selected minion's target to the right-clicked entity + if(player.isSneaking() && WizardData.get(player) != null && WizardData.get(player).selectedMinion != null){ + + ISummonedCreature minion = WizardData.get(player).selectedMinion.get(); + + if(minion instanceof EntityLiving && minion != entity){ + // There is now only the new AI! (which greatly improves things) + ((EntityLiving)minion).setAttackTarget(entity); + // Deselects the selected minion + WizardData.get(player).selectedMinion = null; + return true; + } + } + } + + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java new file mode 100644 index 00000000..97a18fee --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java @@ -0,0 +1,217 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.spell.Petrify; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumAction; +import net.minecraft.item.Item; +import net.minecraft.item.ItemArmor; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumHandSide; +import net.minecraftforge.common.ISpecialArmor; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemWizardArmour extends ItemArmor implements ISpecialArmor { + + public Element element; + + public ItemWizardArmour(ArmorMaterial material, int renderIndex, EntityEquipmentSlot armourType, Element element) { + super(material, renderIndex, armourType); + this.element = element; + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack stack, EntityPlayer player, List tooltip, boolean advanced){ + + if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) tooltip.add("\u00A7d" + net.minecraft.client.resources.I18n.format("item.wizardry:wizard_armour.legendary")); + if(element != null) tooltip.add("\u00A78" + net.minecraft.client.resources.I18n.format("item.wizardry:wizard_armour.buff", (int)(Constants.COST_REDUCTION_PER_ARMOUR*100) + "%", element.getDisplayName())); + tooltip.add("\u00A79" + net.minecraft.client.resources.I18n.format("item.wizardry:wizard_armour.mana", (this.getMaxDamage(stack) - this.getDamage(stack)), this.getMaxDamage(stack))); + } + + @Override + public String getItemStackDisplayName(ItemStack stack){ + return ((this.element == null ? "" : this.element.getFormattingCode()) + super.getItemStackDisplayName(stack)); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack stack){ + return stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary"); + } + + @Override + @SideOnly(Side.CLIENT) + public net.minecraft.client.model.ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, EntityEquipmentSlot armourSlot, net.minecraft.client.model.ModelBiped _default){ + + net.minecraft.client.model.ModelBiped model = Wizardry.proxy.getWizardArmourModel(); + + // Legs use modelBiped + if(armourSlot == EntityEquipmentSlot.LEGS) return null; + + if(model != null){ + + model.bipedHead.showModel = armourSlot == EntityEquipmentSlot.HEAD; + model.bipedHeadwear.showModel = false; + model.bipedBody.showModel = armourSlot == EntityEquipmentSlot.CHEST || armourSlot == EntityEquipmentSlot.LEGS; + model.bipedRightArm.showModel = armourSlot == EntityEquipmentSlot.CHEST; + model.bipedLeftArm.showModel = armourSlot == EntityEquipmentSlot.CHEST; + model.bipedRightLeg.showModel = armourSlot == EntityEquipmentSlot.LEGS || armourSlot == EntityEquipmentSlot.FEET; + model.bipedLeftLeg.showModel = armourSlot == EntityEquipmentSlot.LEGS || armourSlot == EntityEquipmentSlot.FEET; + + model.isSneak = entityLiving.isSneaking(); + model.isRiding = entityLiving.isRiding(); + model.isChild = entityLiving.isChild(); + + boolean leftHanded = entityLiving.getPrimaryHand() == EnumHandSide.LEFT; + + ItemStack itemstackR = leftHanded ? entityLiving.getHeldItemOffhand() : entityLiving.getHeldItemMainhand(); + ItemStack itemstackL = leftHanded ? entityLiving.getHeldItemMainhand() : entityLiving.getHeldItemOffhand(); + + if (itemstackR != null) + { + model.rightArmPose = net.minecraft.client.model.ModelBiped.ArmPose.ITEM; + + if (entityLiving.getItemInUseCount() > 0) + { + EnumAction enumaction = itemstackR.getItemUseAction(); + + if (enumaction == EnumAction.BLOCK) + { + model.rightArmPose = net.minecraft.client.model.ModelBiped.ArmPose.BLOCK; + } + else if (enumaction == EnumAction.BOW) + { + model.rightArmPose = net.minecraft.client.model.ModelBiped.ArmPose.BOW_AND_ARROW; + } + } + } + + if (itemstackL != null) + { + model.leftArmPose = net.minecraft.client.model.ModelBiped.ArmPose.ITEM; + + if (entityLiving.getItemInUseCount() > 0) + { + EnumAction enumaction1 = itemstackL.getItemUseAction(); + + if (enumaction1 == EnumAction.BLOCK) + { + model.leftArmPose = net.minecraft.client.model.ModelBiped.ArmPose.BLOCK; + } + else if (enumaction1 == EnumAction.BOW) + { + model.leftArmPose = net.minecraft.client.model.ModelBiped.ArmPose.BOW_AND_ARROW; + } + } + } + } + + return model; + } + + @Override + public String getArmorTexture(ItemStack stack, Entity entity, EntityEquipmentSlot slot, String type) { + + // Returns a completely transparent texture if the player is invisible. This is such an annoyingly easy + // fix, considering how long I spent trying to do this before - a bit of lateral thinking was all it took. + // Do note however that a texture pack could override this. + if(entity instanceof EntityLivingBase && ((EntityLivingBase)entity).isInvisible() + && !entity.getEntityData().getBoolean(Petrify.NBT_KEY)) return "wizardry:textures/armour/invisible_armour.png"; + + if(slot == EntityEquipmentSlot.LEGS) return this.element == null ? "wizardry:textures/armour/wizard_armour_legs.png" : + "wizardry:textures/armour/wizard_armour_" + this.element.getUnlocalisedName() + "_legs.png"; + + return this.element == null ? "wizardry:textures/armour/wizard_armour.png" : + "wizardry:textures/armour/wizard_armour_" + this.element.getUnlocalisedName() + ".png"; + } + + @Override + public boolean getIsRepairable(ItemStack stack, ItemStack par2ItemStack) + { + return false; + } + + @Override + public ArmorProperties getProperties(EntityLivingBase player, ItemStack armor, DamageSource source, double damage, int slotIndex){ + + EntityEquipmentSlot slot = getArmorSlotFromIndex(slotIndex); + + if (!source.isUnblockable() && armor.getItemDamage() < armor.getMaxDamage()){ + if(armor.hasTagCompound() && armor.getTagCompound().getBoolean("legendary")){ + // Legendary armour gives full 10 shields, like diamond. + return new ArmorProperties(0, ArmorMaterial.DIAMOND.getDamageReductionAmount(slot) / 25D, armor.getMaxDamage() + 1 - armor.getItemDamage()); + }else{ + return new ArmorProperties(0, this.damageReduceAmount / 25D, armor.getMaxDamage() + 1 - armor.getItemDamage()); + } + }else{ + return new ArmorProperties(0, 0, 0); + } + } + + @Override + public int getArmorDisplay(EntityPlayer player, ItemStack armor, int slotIndex) { + + EntityEquipmentSlot slot = getArmorSlotFromIndex(slotIndex); + + if(armor.getItemDamage() < armor.getMaxDamage()){ + if(armor.hasTagCompound() && armor.getTagCompound().getBoolean("legendary")){ + // Legendary armour gives full 10 shields, like diamond. + return ArmorMaterial.DIAMOND.getDamageReductionAmount(slot); + }else{ + return this.getArmorMaterial().getDamageReductionAmount(slot); + } + }else{ + return 0; + } + } + + @Override + public void damageArmor(EntityLivingBase entity, ItemStack stack, DamageSource source, int damage, int slot){ + if(stack.getItemDamage() < stack.getMaxDamage()){ + if(stack.getItemDamage() + damage > stack.getMaxDamage()){ + // Note for reference: this is the method to use, despite how it sounds attemptDamageItem() is called + // by this one, not the other way round. + stack.damageItem(stack.getMaxDamage() - stack.getItemDamage(), entity); + }else{ + stack.damageItem(damage, entity); + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List subItems){ + subItems.add(new ItemStack(this, 1)); + } + + /** Returns the EntityEquipmentSlot for which index() returns an integer equal to the passed in slotIndex and + * which is an armour slot (not a hand slot). This only exists because the 1.10.2 version of Forge still uses + * an integer slot index in ISpecialArmor instead of an EntityEquipmentSlot. */ + // NOTE: Remove in 1.11.2 + private EntityEquipmentSlot getArmorSlotFromIndex(int slotIndex) { + // Had to pick something to begin with. + EntityEquipmentSlot slot = EntityEquipmentSlot.HEAD; + + for(EntityEquipmentSlot s : WizardryUtilities.ARMOUR_SLOTS){ + if(s.getIndex() == slotIndex){ + slot = s; + } + } + return slot; + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemWizardHandbook.java b/src/main/java/electroblob/wizardry/item/ItemWizardHandbook.java new file mode 100644 index 00000000..3b7060db --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemWizardHandbook.java @@ -0,0 +1,46 @@ +package electroblob.wizardry.item; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.WizardryGuiHandler; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class ItemWizardHandbook extends Item { + + // Yep, I hardcoded my own name into the mod. Don't want people changing it now, do I? + private static final String AUTHOR = "Electroblob"; + + public ItemWizardHandbook() { + super(); + this.setMaxStackSize(1); + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public void addInformation(ItemStack stack, EntityPlayer player, List tooltip, boolean advanced){ + tooltip.add("\u00A77" + net.minecraft.client.resources.I18n.format("item.wizardry:wizard_handbook.desc", AUTHOR)); + } + + @Override + public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand){ + player.openGui(Wizardry.instance, WizardryGuiHandler.WIZARD_HANDBOOK, world, 0, 0, 0); + return ActionResult.newResult(EnumActionResult.SUCCESS, stack); + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List items){ + items.add(new ItemStack(this, 1)); + } +} diff --git a/src/main/java/electroblob/wizardry/loot/RandomSpell.java b/src/main/java/electroblob/wizardry/loot/RandomSpell.java new file mode 100644 index 00000000..90c7c661 --- /dev/null +++ b/src/main/java/electroblob/wizardry/loot/RandomSpell.java @@ -0,0 +1,259 @@ +package electroblob.wizardry.loot; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSyntaxException; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.item.ItemScroll; +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.item.ItemStack; +import net.minecraft.util.JsonUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.world.storage.loot.conditions.LootCondition; +import net.minecraft.world.storage.loot.functions.LootFunction; + +/** Loot function that allows spell books and scrolls to select a random spell based on the standard weighting. + * Automatically discounts continuous spells when the item in question is a scroll. Can be used as-is with no + * parameters, but several optional parameters are available for those wishing to customise further: + *

    + * - spells: A list of spells to choose from. Defaults to all enabled spells.
    + * - ignore_weighting: true to ignore the standard weighting and just pick a completely random spell. Defaults to + * false.
    + * - tiers: A list of tiers to choose from. Defaults to all tiers.
    + * - elements: A list of elements to choose from. Defaults to all elements. + *

    + * This class is effectively a loot table-friendly replacement for the standard weighting method in WizardryUtilities + * which was the basis of all the old loot systems (not counting wizard trades, which were - and still are - completely + * separate). + *

    + * Since spells are stored as metadata, this could be done by having an entry for each tier and letting it pick a + * random spell from that tier by setting the metadata to a random value in the range of values that correspond to that + * tier. However, this creates a two-fold problem: firstly, not all spells are in tier order, and secondly, if spells are + * added via addon mods the entries would have to be updated manually with the new numbers. + *

    + * (This reasoning is similar to that for the enchant_randomly function in vanilla Minecraft, since you can specify NBT + * data in loot tables, but using NBT in this way would be incredibly verbose and inflexible, hence the loot function.) + * @see WizardryUtilities#getStandardWeightedRandomSpellId(Random, boolean) + * @author Electroblob + * @since Wizardry 1.2 + */ +/* + * You could even use the yet more long-winded method of adding each spell as an individual entry, which would be + * stupidly long but would allow precise control over each individual spell... I'll leave that for pack makers to do + * if they have the patience! + * */ +public class RandomSpell extends LootFunction { + + private final List spells; + private final boolean ignoreWeighting; + private final List tiers; + private final List elements; + + protected RandomSpell(LootCondition[] conditions, List spells, boolean ignoreWeighting, List tiers, List elements){ + super(conditions); + this.spells = spells; + this.ignoreWeighting = ignoreWeighting; + this.tiers = tiers; + this.elements = elements; + } + + @Override + public ItemStack apply(ItemStack stack, Random random, LootContext context){ + + if(!(stack.getItem() instanceof ItemSpellBook) || !(stack.getItem() instanceof ItemScroll)) + Wizardry.logger.warn("Applying the random_spell loot function to an item that isn't a spell book or scroll."); + + Tier tier; + Element element; + + if(ignoreWeighting){ + if(tiers == null || tiers.isEmpty()){ + tier = Tier.values()[random.nextInt(Tier.values().length)]; + }else{ + tier = tiers.get(random.nextInt(tiers.size())); + } + }else{ + if(tiers == null || tiers.isEmpty()){ + tier = Tier.getWeightedRandomTier(random); + }else{ + tier = Tier.getWeightedRandomTier(random, tiers.toArray(new Tier[0])); + } + } + + // Elements aren't weighted + if(elements == null || elements.isEmpty()){ + element = Element.values()[random.nextInt(Element.values().length)]; + }else{ + // In theory, swapping this line to the commented one should make absolutely no difference. + element = elements.get(random.nextInt(tiers.size())); + //element = null; + } + + // Here's a thought: does randomly selecting the element beforehand (as opposed to leaving it null and letting + // the spell randomiser use any element) change the overall outcome at all? + List spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element)); + if(stack.getItem() instanceof ItemScroll) spellsList.retainAll(Spell.getSpells(Spell.nonContinuousSpells)); + + // Ensures the tier chosen actually has spells in it, and if not uses BASIC instead. BASIC always has at least + // the NONE spell since this spell cannot be disabled. + // NOTE: Commented out for now because it will interfere with the ability to specify tiers and elements. + // To be honest, I may as well just say that if you disable enough spells to make this important, you deserve + // less loot! + /* + if(spells.isEmpty()){ + spellsList = Spell.getSpells(new Spell.TierElementFilter(EnumTier.BASIC, null)); + if(stack.getItem() instanceof ItemScroll) spellsList.retainAll(Spell.getSpells(Spell.nonContinuousSpells)); + } + */ + + if(spells != null && !spells.isEmpty()){ + spellsList.retainAll(spells); + } + + if(spellsList.isEmpty()){ + Wizardry.logger.warn("Tried to apply the random_spell loot function to an item, but no enabled spells" + + "matched the criteria specified. Substituting placeholder (metadata 0) item."); + stack.setItemDamage(0); + }else{ + stack.setItemDamage(spellsList.get(random.nextInt(spellsList.size())).id()); + } + + return stack; + } + + public static class Serializer extends LootFunction.Serializer{ + + public Serializer(){ + super(new ResourceLocation(Wizardry.MODID, "random_spell"), RandomSpell.class); + } + + public void serialize(JsonObject object, RandomSpell function, JsonSerializationContext serializationContext){ + + if(function.spells != null && !function.spells.isEmpty()){ + + JsonArray jsonarray = new JsonArray(); + + for(Spell spell : function.spells){ + jsonarray.add(new JsonPrimitive(spell.getRegistryName().toString())); + } + + object.add("spells", jsonarray); + } + + object.addProperty("ignore_weighting", function.ignoreWeighting); + + if(function.tiers != null && !function.tiers.isEmpty()){ + + JsonArray jsonarray = new JsonArray(); + + for(Tier tier : function.tiers){ + jsonarray.add(new JsonPrimitive(tier.getUnlocalisedName())); + } + + object.add("tiers", jsonarray); + } + + if(function.elements != null && !function.elements.isEmpty()){ + + JsonArray jsonarray = new JsonArray(); + + for(Element element : function.elements){ + jsonarray.add(new JsonPrimitive(element.getUnlocalisedName())); + } + + object.add("elements", jsonarray); + } + } + + public RandomSpell deserialize(JsonObject object, JsonDeserializationContext deserializationContext, LootCondition[] conditions){ + + List spells = null; + List tiers = null; + List elements = null; + + if(object.has("spells")){ + + // Vanilla Minecraft calls Lists.newArrayList() here, which is completely pointless. + spells = new ArrayList(); + + // Importantly, it is necessary to specify a default (the new JsonArray) here because otherwise the + // parameter will be mandatory, and the game will crash if it isn't present. + for (JsonElement element : JsonUtils.getJsonArray(object, "spells", new JsonArray())){ + + String string = JsonUtils.getString(element, "spell"); + + Spell spell = Spell.get(string); + + if(spell == null){ + throw new JsonSyntaxException("Unknown spell \'" + string + "\'"); + } + + spells.add(spell); + } + } + + boolean ignoreWeighting = JsonUtils.getBoolean(object, "ignore_weighting", false); + + if(object.has("tiers")){ + + // Vanilla Minecraft calls Lists.newArrayList() here, which is completely pointless. + tiers = new ArrayList(); + + jsonarray: + for(JsonElement element : JsonUtils.getJsonArray(object, "tiers", new JsonArray())){ + + String string = JsonUtils.getString(element, "tier"); + + // IDEA: If it is necessary to get tiers by name elsewhere in the future, move this to EnumTier. + for(Tier tier : Tier.values()){ + if(tier.getUnlocalisedName().equals(string)){ + tiers.add(tier); + continue jsonarray; + } + } + // If the string does not match any of the tiers, throws an exception. + throw new JsonSyntaxException("Unknown tier \'" + string + "\'"); + } + } + + if(object.has("elements")){ + + // Vanilla Minecraft calls Lists.newArrayList() here, which is completely pointless. + elements = new ArrayList(); + + jsonarray: + for(JsonElement jelement : JsonUtils.getJsonArray(object, "elements", new JsonArray())){ + + String string = JsonUtils.getString(jelement, "element"); + + // IDEA: If it is necessary to get elements by name elsewhere in the future, move this to EnumElement. + for(Element element : Element.values()){ + if(element.getUnlocalisedName().equals(string)){ + elements.add(element); + continue jsonarray; + } + } + // If the string does not match any of the elements, throws an exception. + throw new JsonSyntaxException("Unknown element \'" + string + "\'"); + } + } + + return new RandomSpell(conditions, spells, ignoreWeighting, tiers, elements); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/loot/WizardSpell.java b/src/main/java/electroblob/wizardry/loot/WizardSpell.java new file mode 100644 index 00000000..c52898b5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/loot/WizardSpell.java @@ -0,0 +1,65 @@ +package electroblob.wizardry.loot; + +import java.util.List; +import java.util.Random; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.living.ISpellCaster; +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.world.storage.loot.conditions.LootCondition; +import net.minecraft.world.storage.loot.functions.LootFunction; + +/** + * Loot function that allows spell books to select a random spell from the spells used by the ISpellCaster that dropped + * them. + * @author Electroblob + * @since Wizardry 1.2 + */ +public class WizardSpell extends LootFunction { + + protected WizardSpell(LootCondition[] conditions){ + super(conditions); + } + + @Override + public ItemStack apply(ItemStack stack, Random random, LootContext context){ + + if(!(stack.getItem() instanceof ItemSpellBook)) + Wizardry.logger.warn("Applying the wizard_spell loot function to an item that isn't a spell book or scroll."); + + if(context.getLootedEntity() instanceof ISpellCaster){ + List spells = ((ISpellCaster)context.getLootedEntity()).getSpells(); + spells.remove(Spells.magic_missile); // Can't drop magic missile + stack.setItemDamage(spells.get(random.nextInt(spells.size())).id()); + }else{ + Wizardry.logger.warn("Applying the wizard_spell loot function to an entity that isn't a spell caster."); + } + + return stack; + } + + public static class Serializer extends LootFunction.Serializer{ + + public Serializer(){ + super(new ResourceLocation(Wizardry.MODID, "wizard_spell"), WizardSpell.class); + } + + public void serialize(JsonObject object, WizardSpell function, JsonSerializationContext serializationContext){ + + } + + public WizardSpell deserialize(JsonObject object, JsonDeserializationContext deserializationContext, LootCondition[] conditions){ + return new WizardSpell(conditions); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketCastContinuousSpell.java b/src/main/java/electroblob/wizardry/packet/PacketCastContinuousSpell.java new file mode 100644 index 00000000..9ef22bae --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketCastContinuousSpell.java @@ -0,0 +1,70 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketCastContinuousSpell.Message; +import electroblob.wizardry.util.SpellModifiers; +import io.netty.buffer.ByteBuf; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** [Server -> Client] This packet is sent when the /cast command is used with a continuous spell, in order to + * sync the relevant variables in {@link electroblob.wizardry.WizardData WizardData}. */ +public class PacketCastContinuousSpell implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ + @Override + public void run() { + Wizardry.proxy.handleCastContinuousSpellPacket(message); + } + }); + } + + return null; + } + + public static class Message implements IMessage { + + // Note that range and blast multipliers are the only two that affect particle spawning, so they are the + // only two that need to be sent. + + /** EntityID of the caster */ + public int casterID; + /** ID of the spell being cast */ + public int spellID; + /** SpellModifiers for the spell */ + public SpellModifiers modifiers; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){} + + public Message(int casterID, int spellID, SpellModifiers modifiers){ + this.casterID = casterID; + this.spellID = spellID; + this.modifiers = modifiers; + } + + @Override + public void fromBytes(ByteBuf buf){ + // The order is important + this.casterID = buf.readInt(); + this.spellID = buf.readInt(); + this.modifiers = new SpellModifiers(); + modifiers.read(buf); + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeInt(casterID); + buf.writeInt(spellID); + this.modifiers.write(buf); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketCastSpell.java b/src/main/java/electroblob/wizardry/packet/PacketCastSpell.java new file mode 100644 index 00000000..cf57872c --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketCastSpell.java @@ -0,0 +1,80 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketCastSpell.Message; +import electroblob.wizardry.util.SpellModifiers; +import io.netty.buffer.ByteBuf; +import net.minecraft.item.Item; +import net.minecraft.util.EnumHand; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** [Server -> Client] This packet is sent when a spell is cast by a player and returns true, and is sent to other + * clients so they can spawn the particles themselves. What sending this packet effectively does is make the + * {@link Item#onItemRightClick} method client-consistent just for the item that sends it. Interestingly, + * {@link Item#onUsingTick} is client-consistent already, so continuous spells don't need to send packets from there + * (this is probably something to do with eating particles or usage actions). */ +public class PacketCastSpell implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ + @Override + public void run(){ + Wizardry.proxy.handleCastSpellPacket(message); + } + }); + } + + return null; + } + + public static class Message implements IMessage { + + /** EntityID of the caster */ + public int casterID; + /** ID of the spell being cast */ + public int spellID; + /** SpellModifiers for the spell */ + public SpellModifiers modifiers; + /** The hand that is holding the itemstack used to cast the spell. Defaults to MAIN_HAND. */ + public EnumHand hand; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){} + + public Message(int casterID, EnumHand hand, int spellID, SpellModifiers modifiers){ + + this.casterID = casterID; + this.spellID = spellID; + this.modifiers = modifiers; + this.hand = hand == null ? EnumHand.MAIN_HAND : hand; + } + + @Override + public void fromBytes(ByteBuf buf){ + + // The order is important + this.casterID = buf.readInt(); + this.spellID = buf.readInt(); + this.modifiers = new SpellModifiers(); + this.modifiers.read(buf); + this.hand = buf.readBoolean() ? EnumHand.OFF_HAND : EnumHand.MAIN_HAND; + } + + @Override + public void toBytes(ByteBuf buf){ + + buf.writeInt(casterID); + buf.writeInt(spellID); + this.modifiers.write(buf); + buf.writeBoolean(this.hand == EnumHand.OFF_HAND); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketClairvoyance.java b/src/main/java/electroblob/wizardry/packet/PacketClairvoyance.java new file mode 100644 index 00000000..f7f350bd --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketClairvoyance.java @@ -0,0 +1,81 @@ +package electroblob.wizardry.packet; + +import java.util.ArrayList; +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketClairvoyance.Message; +import io.netty.buffer.ByteBuf; +import net.minecraft.pathfinding.Path; +import net.minecraft.pathfinding.PathPoint; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** [Server -> Client] This packet is sent when a player casts the clairvoyance spell to allow pathing to chunks + * outside the render distance. */ +public class PacketClairvoyance implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx) + { + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ + @Override + public void run(){ + Wizardry.proxy.handleClairvoyancePacket(message); + } + }); + } + + return null; + } + + public static class Message implements IMessage { + + public Path path; + public float durationMultiplier; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message() {} + + public Message(Path path, float durationMultiplier){ + + this.path = path; + this.durationMultiplier = durationMultiplier; + } + + @Override + public void fromBytes(ByteBuf buf){ + + // The order is important + this.durationMultiplier = buf.readFloat(); + + List points = new ArrayList(); + + while(buf.isReadable()){ + points.add(new PathPoint(buf.readInt(), buf.readInt(), buf.readInt())); + } + + this.path = new Path(points.toArray(new PathPoint[0])); + } + + @Override + public void toBytes(ByteBuf buf){ + + buf.writeFloat(durationMultiplier); + + for(int i=0; i[Client -> Server] This packet is for control events such as buttons in GUIs and key presses. */ +public class PacketControlInput implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isServer()){ + + final EntityPlayerMP player = ctx.getServerHandler().playerEntity; + + player.getServerWorld().addScheduledTask(new Runnable(){ + + public void run() { + + ItemStack wand = player.getHeldItemMainhand(); + + if(wand == null || !(wand.getItem() instanceof ItemWand)){ + wand = player.getHeldItemOffhand(); + } + + switch(message.controlType){ + + case APPLY_BUTTON: + + TileEntityArcaneWorkbench tileentity = ((ContainerArcaneWorkbench)player.openContainer).tileEntityArcaneWorkbench; + tileentity.onApplyButtonPressed(player); + break; + + case NEXT_SPELL_KEY: + + if(wand != null && wand.getItem() instanceof ItemWand){ + + WandHelper.selectNextSpell(wand); + // This line fixes the bug with continuous spells casting when they shouldn't be + player.stopActiveHand(); + } + + break; + + case PREVIOUS_SPELL_KEY: + + if(wand != null && wand.getItem() instanceof ItemWand){ + + WandHelper.selectPreviousSpell(wand); + // This line fixes the bug with continuous spells casting when they shouldn't be + player.stopActiveHand(); + } + + break; + } + } + } + ); + } + + return null; + } + + public static enum ControlType { + APPLY_BUTTON, + NEXT_SPELL_KEY, + PREVIOUS_SPELL_KEY; + } + + public static class Message implements IMessage { + + private ControlType controlType; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message() {} + + public Message(ControlType type){ + this.controlType = type; + } + + @Override + public void fromBytes(ByteBuf buf){ + // The order is important + this.controlType = ControlType.values()[buf.readInt()]; + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeInt(controlType.ordinal()); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketGlyphData.java b/src/main/java/electroblob/wizardry/packet/PacketGlyphData.java new file mode 100644 index 00000000..7f7191e5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketGlyphData.java @@ -0,0 +1,70 @@ +package electroblob.wizardry.packet; + +import java.util.ArrayList; +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketGlyphData.Message; +import io.netty.buffer.ByteBuf; +import net.minecraftforge.fml.common.network.ByteBufUtils; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** [Server -> Client] This packet is sent each time a player joins a world to synchronise the client-side spell + * glyph names with the server-side ones. */ +public class PacketGlyphData implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx) + { + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ + @Override + public void run(){ + Wizardry.proxy.handleGlyphDataPacket(message); + } + }); + } + + return null; + } + + public static class Message implements IMessage { + + /** The list of randomised spell names. */ + public List names; + /** The list of randomised spell descriptions. */ + public List descriptions; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message() {} + + public Message(List names, List descriptions) + { + this.names = names; + this.descriptions = descriptions; + } + + @Override + public void fromBytes(ByteBuf buf){ + names = new ArrayList(); + descriptions = new ArrayList(); + while(buf.isReadable()){ + names.add(ByteBufUtils.readUTF8String(buf)); + descriptions.add(ByteBufUtils.readUTF8String(buf)); + } + } + + @Override + public void toBytes(ByteBuf buf){ + for(int i=0; i[Server -> Client] This packet is sent when an {@link ISpellCaster} casts a spell which returns true, and is + * sent to clients so they can spawn the particles. Unlike the player packets, this is for both continuous and + * non-continuous spells. */ +public class PacketNPCCastSpell implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ + @Override + public void run(){ + Wizardry.proxy.handleNPCCastSpellPacket(message); + } + }); + } + + return null; + } + + public static class Message implements IMessage { + + /** EntityID of the caster */ + public int casterID; + /** EntityID of the target, or -1 if there is none */ + public int targetID; + /** ID of the spell being cast */ + public int spellID; + /** SpellModifiers for the spell */ + public SpellModifiers modifiers; + /** The hand that is holding the itemstack used to cast the spell. Defaults to MAIN_HAND. */ + public EnumHand hand; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){} + + public Message(int casterID, int targetID, EnumHand hand, int spellID, SpellModifiers modifiers){ + this.casterID = casterID; + this.targetID = targetID; + this.spellID = spellID; + this.modifiers = modifiers; + this.hand = hand == null ? EnumHand.MAIN_HAND : hand; + } + + @Override + public void fromBytes(ByteBuf buf){ + // The order is important + this.casterID = buf.readInt(); + this.targetID = buf.readInt(); + this.spellID = buf.readInt(); + this.modifiers = new SpellModifiers(); + this.modifiers.read(buf); + this.hand = buf.readBoolean() ? EnumHand.OFF_HAND : EnumHand.MAIN_HAND; + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeInt(casterID); + buf.writeInt(targetID); + buf.writeInt(spellID); + this.modifiers.write(buf); + buf.writeBoolean(this.hand == EnumHand.OFF_HAND); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketPlayerSync.java b/src/main/java/electroblob/wizardry/packet/PacketPlayerSync.java new file mode 100644 index 00000000..d58dfbe4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketPlayerSync.java @@ -0,0 +1,71 @@ +package electroblob.wizardry.packet; + +import java.util.HashSet; +import java.util.Set; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketPlayerSync.Message; +import electroblob.wizardry.spell.Spell; +import io.netty.buffer.ByteBuf; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** [Server -> Client] This packet is sent to synchronise any fields that need synchronising in + * {@link electroblob.wizardry.WizardData WizardData}. This packet is not sent often enough and is too small to warrant + * having separate packets for each field that needs synchronising. */ +public class PacketPlayerSync implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx) + { + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ + @Override + public void run(){ + Wizardry.proxy.handlePlayerSyncPacket(message); + } + }); + } + + return null; + } + + public static class Message implements IMessage { + + public Set spellsDiscovered; + public int selectedMinionID; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message() {} + + public Message(Set spellsDiscovered2, int selectedMinionID){ + this.spellsDiscovered = spellsDiscovered2; + this.selectedMinionID = selectedMinionID; + } + + @Override + public void fromBytes(ByteBuf buf){ + this.selectedMinionID = buf.readInt(); + this.spellsDiscovered = new HashSet(); + while(buf.isReadable()){ + this.spellsDiscovered.add(Spell.get(buf.readInt())); + } + } + + @Override + public void toBytes(ByteBuf buf){ + + buf.writeInt(selectedMinionID); + + if(this.spellsDiscovered == null) return; + + for(Spell spell : this.spellsDiscovered){ + buf.writeInt(spell.id()); + } + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java b/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java new file mode 100644 index 00000000..bed891c6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java @@ -0,0 +1,90 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Settings; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketSyncSettings.Message; +import io.netty.buffer.ByteBuf; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** [Server -> Client] This packet is sent to synchronise the config settings with clients on player login. + * @see Settings */ +public class PacketSyncSettings implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ + @Override + public void run(){ + copySettings(message); + } + }); + + } + + return null; + } + + private static void copySettings(Message message){ + Wizardry.settings.firebombIsCraftable = message.settings.firebombIsCraftable; + Wizardry.settings.poisonBombIsCraftable = message.settings.poisonBombIsCraftable; + Wizardry.settings.smokeBombIsCraftable = message.settings.smokeBombIsCraftable; + Wizardry.settings.useAlternateScrollRecipe = message.settings.useAlternateScrollRecipe; + Wizardry.settings.discoveryMode = message.settings.discoveryMode; +// Wizardry.settings.maxSpellCommandMultiplier = message.settings.maxSpellCommandMultiplier; +// Wizardry.settings.castCommandName = message.settings.castCommandName; +// Wizardry.settings.discoverspellCommandName = message.settings.discoverspellCommandName; +// Wizardry.settings.allyCommandName = message.settings.allyCommandName; +// Wizardry.settings.alliesCommandName = message.settings.alliesCommandName; + } + + public static class Message implements IMessage { + + /** EntityID of the caster */ + public Settings settings; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){} + + public Message(Settings settings){ + this.settings = settings; + } + + @Override + public void fromBytes(ByteBuf buf){ + // I'm guessing the settings field will be null here, so it needs initialising. + // This is also a great reason to have the settings as an actual object. + settings = new Settings(); + // The order is important + settings.firebombIsCraftable = buf.readBoolean(); + settings.poisonBombIsCraftable = buf.readBoolean(); + settings.smokeBombIsCraftable = buf.readBoolean(); + settings.useAlternateScrollRecipe = buf.readBoolean(); + settings.discoveryMode = buf.readBoolean(); +// settings.maxSpellCommandMultiplier = buf.readDouble(); +// settings.castCommandName = ByteBufUtils.readUTF8String(buf); +// settings.discoverspellCommandName = ByteBufUtils.readUTF8String(buf); +// settings.allyCommandName = ByteBufUtils.readUTF8String(buf); +// settings.alliesCommandName = ByteBufUtils.readUTF8String(buf); + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeBoolean(settings.firebombIsCraftable); + buf.writeBoolean(settings.poisonBombIsCraftable); + buf.writeBoolean(settings.smokeBombIsCraftable); + buf.writeBoolean(settings.useAlternateScrollRecipe); + buf.writeBoolean(settings.discoveryMode); +// buf.writeDouble(settings.maxSpellCommandMultiplier); +// ByteBufUtils.writeUTF8String(buf, settings.castCommandName); +// ByteBufUtils.writeUTF8String(buf, settings.discoverspellCommandName); +// ByteBufUtils.writeUTF8String(buf, settings.allyCommandName); +// ByteBufUtils.writeUTF8String(buf, settings.alliesCommandName); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketTransportation.java b/src/main/java/electroblob/wizardry/packet/PacketTransportation.java new file mode 100644 index 00000000..7a7085c8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketTransportation.java @@ -0,0 +1,58 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketTransportation.Message; +import io.netty.buffer.ByteBuf; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** [Server -> Client] This packet is sent when a player is teleported due to the transportation spell to spawn + * the particles. */ +public class PacketTransportation implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx) + { + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ + @Override + public void run(){ + Wizardry.proxy.handleTransportationPacket(message); + } + }); + } + + return null; + } + + public static class Message implements IMessage + { + /** EntityID of the caster */ + public int casterID; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message() {} + + public Message(int casterID) + { + this.casterID = casterID; + } + + @Override + public void fromBytes(ByteBuf buf) + { + // The order is important + this.casterID = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf) + { + buf.writeInt(casterID); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java new file mode 100644 index 00000000..dedaead6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java @@ -0,0 +1,36 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; +import net.minecraftforge.fml.relauncher.Side; + +public class WizardryPacketHandler { + + public static SimpleNetworkWrapper net; + + public static void initPackets() + { + net = NetworkRegistry.INSTANCE.newSimpleChannel(Wizardry.MODID.toUpperCase()); + registerMessage(PacketControlInput.class, PacketControlInput.Message.class); + registerMessage(PacketCastSpell.class, PacketCastSpell.Message.class); + registerMessage(PacketTransportation.class, PacketTransportation.Message.class); + registerMessage(PacketPlayerSync.class, PacketPlayerSync.Message.class); + registerMessage(PacketGlyphData.class, PacketGlyphData.Message.class); + registerMessage(PacketCastContinuousSpell.class, PacketCastContinuousSpell.Message.class); + registerMessage(PacketClairvoyance.class, PacketClairvoyance.Message.class); + registerMessage(PacketSyncSettings.class, PacketSyncSettings.Message.class); + registerMessage(PacketNPCCastSpell.class, PacketNPCCastSpell.Message.class); + } + + private static int nextPacketId = 0; + + private static void registerMessage(Class> packet, Class message) + { + net.registerMessage(packet, message, nextPacketId, Side.CLIENT); + net.registerMessage(packet, message, nextPacketId, Side.SERVER); + nextPacketId++; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java b/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java new file mode 100644 index 00000000..4b66e59d --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java @@ -0,0 +1,23 @@ +package electroblob.wizardry.potion; + +import net.minecraft.world.World; + +/** + * Interface for potion effects that spawn custom particles instead of (or as well as) the vanilla 'swirly' particles. + * @author Electroblob + * @since Wizardry 1.2 + */ +// TODO: Backport. +public interface ICustomPotionParticles { + + /** + * Called from the event handler to spawn a single custom potion particle. To get an instance of + * Random inside this method, use world.rand. + * @param world The world to spawn the particle in. + * @param x The x coordinate of the particle, already set to a random value within the entity's bounding box. + * @param y The y coordinate of the particle, already set to a random value within the entity's bounding box. + * @param z The z coordinate of the particle, already set to a random value within the entity's bounding box. + */ + void spawnCustomParticle(World world, double x, double y, double z); + +} diff --git a/src/main/java/electroblob/wizardry/potion/PotionDecay.java b/src/main/java/electroblob/wizardry/potion/PotionDecay.java new file mode 100644 index 00000000..8386115a --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/PotionDecay.java @@ -0,0 +1,53 @@ +package electroblob.wizardry.potion; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class PotionDecay extends Potion { + + private static final ResourceLocation ICON = new ResourceLocation(Wizardry.MODID, "textures/gui/decay_icon.png"); + + public PotionDecay(boolean isBadEffect, int liquidColour) { + super(isBadEffect, liquidColour); + // This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet. + this.setPotionName("potion.wizardry:decay"); + this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED, "85602e0b-4801-4a87-94f3-bf617c97014e", -Constants.DECAY_SLOWNESS_PER_LEVEL, 2); + } + + @Override + public boolean isReady(int p_76397_1_, int p_76397_2_) { + // Copied from the vanilla wither effect. It does the timing stuff. 25 is the number of ticks between hits at + // amplifier 0 + int k = 25 >> p_76397_2_; + return k > 0 ? p_76397_1_ % k == 0 : true; + } + + @Override + public void performEffect(EntityLivingBase entitylivingbase, int strength) { + entitylivingbase.attackEntityFrom(DamageSource.wither, 1); + } + + @Override + @SideOnly(Side.CLIENT) + public void renderInventoryEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc) { + mc.renderEngine.bindTexture(ICON); + WizardryUtilities.drawTexturedRect(x + 6, y + 7, 0, 0, 18, 18, 18, 18); + } + + @Override + @SideOnly(Side.CLIENT) + public void renderHUDEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc, float alpha) { + mc.renderEngine.bindTexture(ICON); + WizardryUtilities.drawTexturedRect(x + 3, y + 3, 0, 0, 18, 18, 18, 18); + } + +} diff --git a/src/main/java/electroblob/wizardry/potion/PotionFrost.java b/src/main/java/electroblob/wizardry/potion/PotionFrost.java new file mode 100644 index 00000000..2b2c7783 --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/PotionFrost.java @@ -0,0 +1,53 @@ +package electroblob.wizardry.potion; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class PotionFrost extends Potion implements ICustomPotionParticles { + + private static final ResourceLocation ICON = new ResourceLocation(Wizardry.MODID, "textures/gui/frost_icon.png"); + + public PotionFrost(boolean isBadEffect, int liquidColour) { + super(isBadEffect, liquidColour); + // This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet. + this.setPotionName("potion.wizardry:frost"); + // With -0.5 as the 'amount', frost 1 slows the entity down by a half and frost 2 roots it to the spot + this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED, "35dded48-2f19-4541-8510-b29e2dc2cd51", -Constants.FROST_SLOWNESS_PER_LEVEL, 2); + // More UUIDs: 85602e0b-4801-4a87-94f3-bf617c97014e + } + + @Override + public void performEffect(EntityLivingBase entitylivingbase, int strength) { + // Nothing here because this potion works on attribute modifiers. + } + + @Override + public void spawnCustomParticle(World world, double x, double y, double z) { + Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, x, y, z, 0, -0.02, 0, 15 + world.rand.nextInt(5)); + } + + @Override + @SideOnly(Side.CLIENT) + public void renderInventoryEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc) { + mc.renderEngine.bindTexture(ICON); + WizardryUtilities.drawTexturedRect(x + 6, y + 7, 0, 0, 18, 18, 18, 18); + } + + @Override + @SideOnly(Side.CLIENT) + public void renderHUDEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc, float alpha) { + mc.renderEngine.bindTexture(ICON); + WizardryUtilities.drawTexturedRect(x + 3, y + 3, 0, 0, 18, 18, 18, 18); + } + +} diff --git a/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java b/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java new file mode 100644 index 00000000..bba9a646 --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java @@ -0,0 +1,42 @@ +package electroblob.wizardry.potion; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** Class for all potions that work on events only. */ +public class PotionMagicEffect extends Potion { + + private static final ResourceLocation ICONS = new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons.png"); + private final int textureIndex; + + public PotionMagicEffect(boolean isBadEffect, int liquidColour, int textureIndex) { + super(isBadEffect, liquidColour); + this.textureIndex = textureIndex; + } + + @Override + public void performEffect(EntityLivingBase entitylivingbase, int strength) { + // Nothing here because this potion works on events. + } + + @Override + @SideOnly(Side.CLIENT) + public void renderInventoryEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc){ + mc.renderEngine.bindTexture(ICONS); + WizardryUtilities.drawTexturedRect(x + 6, y + 7, 18*(textureIndex%4), 18*(textureIndex/4), 18, 18, 72, 72); + } + + @Override + @SideOnly(Side.CLIENT) + public void renderHUDEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc, float alpha) { + mc.renderEngine.bindTexture(ICONS); + WizardryUtilities.drawTexturedRect(x + 3, y + 3, 18*(textureIndex%4), 18*(textureIndex/4), 18, 18, 72, 72); + } + +} diff --git a/src/main/java/electroblob/wizardry/potion/PotionMagicEffectParticles.java b/src/main/java/electroblob/wizardry/potion/PotionMagicEffectParticles.java new file mode 100644 index 00000000..b9eac023 --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/PotionMagicEffectParticles.java @@ -0,0 +1,11 @@ +package electroblob.wizardry.potion; + +/** Same as {@link PotionMagicEffect}, but also implements {@link ICustomPotionParticles} to allow anonymous classes + * to extend it and add their own particles. */ +public abstract class PotionMagicEffectParticles extends PotionMagicEffect implements ICustomPotionParticles { + + public PotionMagicEffectParticles(boolean isBadEffect, int liquidColour, int textureIndex){ + super(isBadEffect, liquidColour, textureIndex); + } + +} diff --git a/src/main/java/electroblob/wizardry/registry/Spells.java b/src/main/java/electroblob/wizardry/registry/Spells.java new file mode 100644 index 00000000..f5205f29 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/Spells.java @@ -0,0 +1,351 @@ +package electroblob.wizardry.registry; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.spell.*; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; +import net.minecraftforge.fml.common.registry.IForgeRegistry; +import net.minecraftforge.fml.common.registry.RegistryBuilder; + +/** + * Class responsible for defining, storing and registering all of wizardry's spells. + * @author Electroblob + * @since Wizardry 2.1 + */ +// In case anyone was wondering, the reason @ObjectHolder is useful within one mod is that it allows you to initialise +// stuff during the registry events (or whenever), whilst still having a final field (which is important, not only +// because it makes the text go bold, but also because it stops anyone fiddling with your fields). "Why would I want to +// initialise things within the registry events?", I hear you ask - well, for one, custom registries don't like it if +// you haven't created the registry before you start calling constructors of classes extending IForgeRegistryEntry.Impl. +@ObjectHolder(Wizardry.MODID) +@Mod.EventBusSubscriber +public final class Spells { + + // This is here because this class is already an event handler. + @SubscribeEvent + public static void createRegistry(RegistryEvent.NewRegistry event){ + + // Beats me why we need both of these. Surely the type parameter means it already knows? + RegistryBuilder builder = new RegistryBuilder(); + builder.setType(Spell.class); + builder.setName(new ResourceLocation(Wizardry.MODID, "spells")); + builder.setIDRange(0, 5000); // Is there any penalty for using a larger number? + + Spell.registry = builder.create(); + } + + // Wizardry 1.0 spells + + public static final Spell none = null; + public static final Spell magic_missile = null; + public static final Spell ignite = null; + public static final Spell freeze = null; + public static final Spell snowball = null; + public static final Spell arc = null; + public static final Spell thunderbolt = null; + public static final Spell summon_zombie = null; + public static final Spell snare = null; + public static final Spell dart = null; + public static final Spell light = null; + public static final Spell telekinesis = null; + public static final Spell heal = null; + + public static final Spell fireball = null; + public static final Spell flame_ray = null; + public static final Spell firebomb = null; + public static final Spell fire_sigil = null; + public static final Spell firebolt = null; + public static final Spell frost_ray = null; + public static final Spell summon_snow_golem = null; + public static final Spell ice_shard = null; + public static final Spell ice_statue = null; + public static final Spell frost_sigil = null; + public static final Spell lightning_ray = null; + public static final Spell spark_bomb = null; + public static final Spell homing_spark = null; + public static final Spell lightning_sigil = null; + public static final Spell lightning_arrow = null; + public static final Spell life_drain = null; + public static final Spell summon_skeleton = null; + public static final Spell metamorphosis = null; + public static final Spell wither = null; + public static final Spell poison = null; + public static final Spell growth_aura = null; + public static final Spell bubble = null; + public static final Spell whirlwind = null; + public static final Spell poison_bomb = null; + public static final Spell summon_spirit_wolf = null; + public static final Spell blink = null; + public static final Spell agility = null; + public static final Spell conjure_sword = null; + public static final Spell conjure_pickaxe = null; + public static final Spell conjure_bow = null; + public static final Spell force_arrow = null; + public static final Spell shield = null; + public static final Spell replenish_hunger = null; + public static final Spell cure_effects = null; + public static final Spell heal_ally = null; + + public static final Spell summon_blaze = null; + public static final Spell ring_of_fire = null; + public static final Spell detonate = null; + public static final Spell fire_resistance = null; + public static final Spell fireskin = null; + public static final Spell flaming_axe = null; + public static final Spell blizzard = null; + public static final Spell summon_ice_wraith = null; + public static final Spell ice_shroud = null; + public static final Spell ice_charge = null; + public static final Spell frost_axe = null; + public static final Spell invoke_weather = null; + public static final Spell chain_lightning = null; + public static final Spell lightning_bolt = null; + public static final Spell summon_lightning_wraith = null; + public static final Spell static_aura = null; + public static final Spell lightning_disc = null; + public static final Spell mind_control = null; + public static final Spell summon_wither_skeleton = null; + public static final Spell entrapment = null; + public static final Spell wither_skull = null; + public static final Spell darkness_orb = null; + public static final Spell shadow_ward = null; + public static final Spell decay = null; + public static final Spell water_breathing = null; + public static final Spell tornado = null; + public static final Spell glide = null; + public static final Spell summon_spirit_horse = null; + public static final Spell spider_swarm = null; + public static final Spell slime = null; + public static final Spell petrify = null; + public static final Spell invisibility = null; + public static final Spell levitation = null; + public static final Spell force_orb = null; + public static final Spell transportation = null; + public static final Spell spectral_pathway = null; + public static final Spell phase_step = null; + public static final Spell vanishing_box = null; + public static final Spell greater_heal = null; + public static final Spell healing_aura = null; + public static final Spell forcefield = null; + public static final Spell ironflesh = null; + public static final Spell transience = null; + + public static final Spell meteor = null; + public static final Spell firestorm = null; + public static final Spell summon_phoenix = null; + public static final Spell ice_age = null; + public static final Spell wall_of_frost = null; + public static final Spell summon_ice_giant = null; + public static final Spell thunderstorm = null; + public static final Spell lightning_hammer = null; + public static final Spell plague_of_darkness = null; + public static final Spell summon_skeleton_legion = null; + public static final Spell summon_shadow_wraith = null; + public static final Spell forests_curse = null; + public static final Spell flight = null; + public static final Spell silverfish_swarm = null; + public static final Spell black_hole = null; + public static final Spell shockwave = null; + public static final Spell summon_iron_golem = null; + public static final Spell arrow_rain = null; + public static final Spell diamondflesh = null; + public static final Spell font_of_vitality = null; + + // Wizardry 1.1 spells + + public static final Spell smoke_bomb = null; + public static final Spell mind_trick = null; + public static final Spell leap = null; + + public static final Spell pocket_furnace = null; + public static final Spell intimidate = null; + public static final Spell banish = null; + public static final Spell sixth_sense = null; + public static final Spell darkvision = null; + public static final Spell clairvoyance = null; + public static final Spell pocket_workbench = null; + public static final Spell imbue_weapon = null; + public static final Spell invigorating_presence = null; + public static final Spell oakflesh = null; + + public static final Spell greater_fireball = null; + public static final Spell flaming_weapon = null; + public static final Spell ice_lance = null; + public static final Spell freezing_weapon = null; + public static final Spell ice_spikes = null; + public static final Spell lightning_pulse = null; + public static final Spell curse_of_soulbinding = null; + public static final Spell cobwebs = null; + public static final Spell decoy = null; + public static final Spell arcane_jammer = null; + public static final Spell conjure_armour = null; + public static final Spell group_heal = null; + + public static final Spell hailstorm = null; + public static final Spell lightning_web = null; + public static final Spell summon_storm_elemental = null; + public static final Spell earthquake = null; + public static final Spell font_of_mana = null; + + @SubscribeEvent + public static void register(RegistryEvent.Register event){ + + IForgeRegistry registry = event.getRegistry(); + + // event.getRegistry should always equal Spell.registry. + registry.register(new None()); + registry.register(new MagicMissile()); + registry.register(new Ignite()); + registry.register(new Freeze()); + registry.register(new Snowball()); + registry.register(new Arc()); + registry.register(new Thunderbolt()); + registry.register(new SummonZombie()); + registry.register(new Snare()); + registry.register(new Dart()); + registry.register(new Light()); + registry.register(new Telekinesis()); + registry.register(new Heal()); + + registry.register(new Fireball()); + registry.register(new FlameRay()); + registry.register(new Firebomb()); + registry.register(new FireSigil()); + registry.register(new Firebolt()); + registry.register(new FrostRay()); + registry.register(new SummonSnowGolem()); + registry.register(new IceShard()); + registry.register(new IceStatue()); + registry.register(new FrostSigil()); + registry.register(new LightningRay()); + registry.register(new SparkBomb()); + registry.register(new HomingSpark()); + registry.register(new LightningSigil()); + registry.register(new LightningArrow()); + registry.register(new LifeDrain()); + registry.register(new SummonSkeleton()); + registry.register(new Metamorphosis()); + registry.register(new Wither()); + registry.register(new Poison()); + registry.register(new GrowthAura()); + registry.register(new Bubble()); + registry.register(new Whirlwind()); + registry.register(new PoisonBomb()); + registry.register(new SummonSpiritWolf()); + registry.register(new Blink()); + registry.register(new Agility()); + registry.register(new ConjureSword()); + registry.register(new ConjurePickaxe()); + registry.register(new ConjureBow()); + registry.register(new ForceArrow()); + registry.register(new Shield()); + registry.register(new ReplenishHunger()); + registry.register(new CureEffects()); + registry.register(new HealAlly()); + + registry.register(new SummonBlaze()); + registry.register(new RingOfFire()); + registry.register(new Detonate()); + registry.register(new FireResistance()); + registry.register(new Fireskin()); + registry.register(new FlamingAxe()); + registry.register(new Blizzard()); + registry.register(new SummonIceWraith()); + registry.register(new IceShroud()); + registry.register(new IceCharge()); + registry.register(new FrostAxe()); + registry.register(new InvokeWeather()); + registry.register(new ChainLightning()); + registry.register(new LightningBolt()); + registry.register(new SummonLightningWraith()); + registry.register(new StaticAura()); + registry.register(new LightningDisc()); + registry.register(new MindControl()); + registry.register(new SummonWitherSkeleton()); + registry.register(new Entrapment()); + registry.register(new WitherSkull()); + registry.register(new DarknessOrb()); + registry.register(new ShadowWard()); + registry.register(new Decay()); + registry.register(new WaterBreathing()); + registry.register(new Tornado()); + registry.register(new Glide()); + registry.register(new SummonSpiritHorse()); + registry.register(new SpiderSwarm()); + registry.register(new Slime()); + registry.register(new Petrify()); + registry.register(new Invisibility()); + registry.register(new Levitation()); + registry.register(new ForceOrb()); + registry.register(new Transportation()); + registry.register(new SpectralPathway()); + registry.register(new PhaseStep()); + registry.register(new VanishingBox()); + registry.register(new GreaterHeal()); + registry.register(new HealingAura()); + registry.register(new Forcefield()); + registry.register(new Ironflesh()); + registry.register(new Transience()); + + registry.register(new Meteor()); + registry.register(new Firestorm()); + registry.register(new SummonPhoenix()); + registry.register(new IceAge()); + registry.register(new WallOfFrost()); + registry.register(new SummonIceGiant()); + registry.register(new Thunderstorm()); + registry.register(new LightningHammer()); + registry.register(new PlagueOfDarkness()); + registry.register(new SummonSkeletonLegion()); + registry.register(new SummonShadowWraith()); + registry.register(new ForestsCurse()); + registry.register(new Flight()); + registry.register(new SilverfishSwarm()); + registry.register(new BlackHole()); + registry.register(new Shockwave()); + registry.register(new SummonIronGolem()); + registry.register(new ArrowRain()); + registry.register(new Diamondflesh()); + registry.register(new FontOfVitality()); + + // Wizardry 1.1 spells + + registry.register(new SmokeBomb()); + registry.register(new MindTrick()); + registry.register(new Leap()); + + registry.register(new PocketFurnace()); + registry.register(new Intimidate()); + registry.register(new Banish()); + registry.register(new SixthSense()); + registry.register(new Darkvision()); + registry.register(new Clairvoyance()); + registry.register(new PocketWorkbench()); + registry.register(new ImbueWeapon()); + registry.register(new InvigoratingPresence()); + registry.register(new Oakflesh()); + + registry.register(new GreaterFireball()); + registry.register(new FlamingWeapon()); + registry.register(new IceLance()); + registry.register(new FreezingWeapon()); + registry.register(new IceSpikes()); + registry.register(new LightningPulse()); + registry.register(new CurseOfSoulbinding()); + registry.register(new Cobwebs()); + registry.register(new Decoy()); + registry.register(new ArcaneJammer()); + registry.register(new ConjureArmour()); + registry.register(new GroupHeal()); + + registry.register(new Hailstorm()); + registry.register(new LightningWeb()); + registry.register(new SummonStormElemental()); + registry.register(new Earthquake()); + registry.register(new FontOfMana()); + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryAchievements.java b/src/main/java/electroblob/wizardry/registry/WizardryAchievements.java new file mode 100644 index 00000000..2e3ab165 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryAchievements.java @@ -0,0 +1,47 @@ +package electroblob.wizardry.registry; + +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.stats.Achievement; +import net.minecraftforge.common.AchievementPage; + +/** + * Class responsible for defining, storing and registering all of wizardry's achievements (achievements don't have a + * registry, but it make sense to do them the same way as everything else). + * @author Electroblob + * @since Wizardry 2.1 + */ +public final class WizardryAchievements { + + public static final Achievement crystal = new Achievement("crystal", "crystal", -1, -1, WizardryItems.magic_crystal, null).registerStat(); + public static final Achievement arcane_initiate = new Achievement("arcane_initiate", "arcane_initiate", 2, -1, WizardryItems.magic_wand, crystal).registerStat(); + public static final Achievement apprentice = new Achievement("apprentice", "apprentice", 2, 3, WizardryItems.apprentice_wand, arcane_initiate).registerStat(); + public static final Achievement master = new Achievement("master", "master", 3, 6, WizardryItems.master_wand, apprentice).registerStat(); + public static final Achievement all_spells = new Achievement("all_spells", "all_spells", 5, 7, WizardryItems.wizard_handbook, master).registerStat().setSpecial(); + public static final Achievement wizard_trade = new Achievement("wizard_trade", "wizard_trade", 2, -5, Items.EMERALD, arcane_initiate).registerStat(); + public static final Achievement buy_master_spell = new Achievement("buy_master_spell", "buy_master_spell", 5, -5, WizardryItems.spell_book, wizard_trade).registerStat().setSpecial(); + public static final Achievement freeze_blaze = new Achievement("freeze_blaze", "freeze_blaze", -1, 3, Blocks.ICE, apprentice).registerStat(); + public static final Achievement charge_creeper = new Achievement("charge_creeper", "charge_creeper", -1, 1, Items.GUNPOWDER, arcane_initiate).registerStat(); + public static final Achievement frankenstein = new Achievement("frankenstein", "frankenstein", -3, 1, WizardryItems.advanced_lightning_wand, charge_creeper).registerStat().setSpecial(); + public static final Achievement special_upgrade = new Achievement("special_upgrade", "special_upgrade", 4, 1, WizardryItems.condenser_upgrade, arcane_initiate).registerStat(); + public static final Achievement craft_flask = new Achievement("craft_flask", "craft_flask", 4, -2, WizardryItems.mana_flask, arcane_initiate).registerStat(); + public static final Achievement elemental = new Achievement("elemental", "elemental", 6, -1, WizardryItems.basic_fire_wand, arcane_initiate).registerStat(); + public static final Achievement armour_set = new Achievement("armour_set", "armour_set", 0, -4, WizardryItems.wizard_hat, arcane_initiate).registerStat(); + public static final Achievement legendary = new Achievement("legendary", "legendary", -2, -5, WizardryItems.armour_upgrade, armour_set).registerStat().setSpecial(); + public static final Achievement self_destruct = new Achievement("self_destruct", "self_destruct", 1, 0, Blocks.PUMPKIN, arcane_initiate).registerStat(); + public static final Achievement pig_tornado = new Achievement("pig_tornado", "pig_tornado", 6, 3, Items.SADDLE, apprentice).registerStat().setSpecial(); + public static final Achievement jam_wizard = new Achievement("jam_wizard", "jam_wizard", 4, 4, Blocks.WEB, apprentice).registerStat(); + public static final Achievement slime_skeleton = new Achievement("slime_skeleton", "slime_skeleton", 1, 5, Items.SLIME_BALL, apprentice).registerStat(); + public static final Achievement anger_wizard = new Achievement("anger_wizard", "anger_wizard", 1, -7, Items.IRON_SWORD, wizard_trade).registerStat(); + public static final Achievement defeat_evil_wizard = new Achievement("defeat_evil_wizard", "defeat_evil_wizard", 4, -7, WizardryItems.wizard_boots_necromancy, wizard_trade).registerStat(); + public static final Achievement max_out_wand = new Achievement("max_out_wand", "max_out_wand", 7, 1, WizardryItems.arcane_tome, special_upgrade).registerStat().setSpecial(); + public static final Achievement element_master = new Achievement("element_master", "element_master", 7, -3, WizardryItems.master_ice_wand, elemental).registerStat().setSpecial(); + public static final Achievement identify_spell = new Achievement("identify_spell", "identify_spell", -2, -3, WizardryItems.identification_scroll, arcane_initiate).registerStat(); + + private static final Achievement[] ACHIEVEMENTS_LIST = {crystal, arcane_initiate, apprentice, master, all_spells, wizard_trade, buy_master_spell, freeze_blaze, charge_creeper, + frankenstein, special_upgrade, craft_flask, elemental, armour_set, legendary, self_destruct, pig_tornado, jam_wizard, slime_skeleton, anger_wizard, defeat_evil_wizard, + max_out_wand, element_master, identify_spell}; + + public static final AchievementPage WIZARDRY_ACHIEVEMENT_PAGE = new AchievementPage("Wizardry", ACHIEVEMENTS_LIST); + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java b/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java new file mode 100644 index 00000000..b1efa21a --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java @@ -0,0 +1,92 @@ +package electroblob.wizardry.registry; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockArcaneWorkbench; +import electroblob.wizardry.block.BlockCrystalFlower; +import electroblob.wizardry.block.BlockCrystalOre; +import electroblob.wizardry.block.BlockMagicLight; +import electroblob.wizardry.block.BlockSnare; +import electroblob.wizardry.block.BlockSpectral; +import electroblob.wizardry.block.BlockStatue; +import electroblob.wizardry.block.BlockTransportationStone; +import electroblob.wizardry.block.BlockVanishingCobweb; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.IForgeRegistry; + +/** + * Class responsible for defining, storing and registering all of wizardry's blocks. + * @author Electroblob + * @since Wizardry 2.1 + */ +@Mod.EventBusSubscriber +public final class WizardryBlocks { + + // I get registry events, they make sense - even I doubted myself with when to do various things in the load process, + // so I can see why the folks at Forge wanted to save us having to think about it. + // What I do not understand is why you would use @ObjectHolder for your own blocks and items. What's the point in + // making your code longer and more complicated, when you can just define the blocks as constants and register them + // later? + + // Found a very nice way of registering things using arrays, which might make @ObjectHolder actually useful. + // http://www.minecraftforge.net/forum/topic/49497-1112-is-using-registryevent-this-way-ok/ + + // Anything set to use the material 'air' will not render, even with a TESR! + + // setSoundType should be public, but in this particular version it isn't... which is a bit of a pain. + + public static final Block arcane_workbench = new BlockArcaneWorkbench().setHardness(1.0F).setCreativeTab(WizardryTabs.WIZARDRY); + public static final Block crystal_ore = new BlockCrystalOre(Material.ROCK).setHardness(3.0F).setCreativeTab(WizardryTabs.WIZARDRY); + public static final Block petrified_stone = new BlockStatue(Material.ROCK).setHardness(1.5F).setResistance(10.0F); + public static final Block ice_statue = new BlockStatue(Material.ICE).setHardness(0.5F).setLightOpacity(3); + public static final Block magic_light = new BlockMagicLight(Material.CIRCUITS); + public static final Block crystal_flower = new BlockCrystalFlower(Material.PLANTS).setHardness(0.0F).setCreativeTab(WizardryTabs.WIZARDRY); + public static final Block snare = new BlockSnare(Material.PLANTS).setHardness(0.0F); + public static final Block transportation_stone = new BlockTransportationStone(Material.ROCK).setHardness(0.0F).setLightLevel(0.5f).setLightOpacity(0).setCreativeTab(WizardryTabs.WIZARDRY); + public static final Block spectral_block = new BlockSpectral(Material.GLASS).setLightLevel(0.7f).setLightOpacity(0).setBlockUnbreakable().setResistance(6000000.0F); + public static final Block crystal_block = new Block(Material.IRON).setHardness(5.0F).setResistance(10.0F).setCreativeTab(WizardryTabs.WIZARDRY); + public static final Block meteor = new Block(Material.ROCK).setLightLevel(1); + public static final Block vanishing_cobweb = new BlockVanishingCobweb(Material.WEB).setLightOpacity(1).setHardness(4.0F); + + static { + // This is here because Block#setHarvestLevel isn't chainable. + crystal_block.setHarvestLevel("pickaxe", 2); + } + + /** + * Sets both the registry and unlocalised names of the given block, then registers it with the given registry. Use + * this instead of {@link Block#setRegistryName(String)} and {@link Block#setUnlocalizedName(String)} during + * construction, for convenience and consistency. + * @param registry The registry to register the given block to. + * @param item The block to register. + * @param name The name of the block, without the mod ID or the .name stuff. The registry name will be + * {@code wizardry:[name]}. The unlocalised name will be {@code tile.wizardry:[name].name}. + */ + public static void registerBlock(IForgeRegistry registry, Block block, String name){ + block.setRegistryName(Wizardry.MODID, name); + block.setUnlocalizedName(block.getRegistryName().toString()); + registry.register(block); + } + + @SubscribeEvent + public static void register(RegistryEvent.Register event){ + + IForgeRegistry registry = event.getRegistry(); + + registerBlock(registry, arcane_workbench, "arcane_workbench"); + registerBlock(registry, crystal_ore, "crystal_ore"); + registerBlock(registry, petrified_stone, "petrified_stone"); + registerBlock(registry, ice_statue, "ice_statue"); + registerBlock(registry, magic_light, "magic_light"); + registerBlock(registry, crystal_flower, "crystal_flower"); + registerBlock(registry, snare, "snare"); + registerBlock(registry, transportation_stone, "transportation_stone"); + registerBlock(registry, spectral_block, "spectral_block"); + registerBlock(registry, crystal_block, "crystal_block"); + registerBlock(registry, meteor, "meteor"); + registerBlock(registry, vanishing_cobweb, "vanishing_cobweb"); + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java b/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java new file mode 100644 index 00000000..e34ca427 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java @@ -0,0 +1,41 @@ +package electroblob.wizardry.registry; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.enchantment.EnchantmentMagicSword; +import electroblob.wizardry.enchantment.EnchantmentTimed; +import net.minecraft.enchantment.Enchantment; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +/** + * Class responsible for defining, storing and registering all of wizardry's enchantments. + * @author Electroblob + * @since Wizardry 2.1 + */ +@Mod.EventBusSubscriber +public final class WizardryEnchantments { + + // At the moment these enchantments generate on books in dungeon chests due to a bad bit of code (EnchantRandomly:50). + // No idea how to fix this because I have no way of hooking into that code... removing the enchantments from the + // registry works, but breaks everything else! + + // TODO: For the time being, a dynamic solution will have to do, i.e. intercept the book when it is generated and + // reassign its enchantment. + + // All of these have custom classes, so the unlocalised name (referred to simply as 'name' for enchantments) is + // dealt with inside those classes. + public static final Enchantment magic_sword = new EnchantmentMagicSword().setRegistryName(Wizardry.MODID, "magic_sword"); + public static final Enchantment magic_bow = new EnchantmentTimed().setRegistryName(Wizardry.MODID, "magic_bow"); + public static final Enchantment flaming_weapon = new EnchantmentTimed().setRegistryName(Wizardry.MODID, "flaming_weapon"); + public static final Enchantment freezing_weapon = new EnchantmentTimed().setRegistryName(Wizardry.MODID, "freezing_weapon"); + + @SubscribeEvent + public static void register(RegistryEvent.Register event){ + event.getRegistry().register(magic_sword); + event.getRegistry().register(magic_bow); + event.getRegistry().register(flaming_weapon); + event.getRegistry().register(freezing_weapon); + } + +} diff --git a/src/main/java/electroblob/wizardry/registry/WizardryItems.java b/src/main/java/electroblob/wizardry/registry/WizardryItems.java new file mode 100644 index 00000000..89b053dd --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryItems.java @@ -0,0 +1,419 @@ +package electroblob.wizardry.registry; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.item.ItemArcaneTome; +import electroblob.wizardry.item.ItemArmourUpgrade; +import electroblob.wizardry.item.ItemFirebomb; +import electroblob.wizardry.item.ItemFlamingAxe; +import electroblob.wizardry.item.ItemFrostAxe; +import electroblob.wizardry.item.ItemIdentificationScroll; +import electroblob.wizardry.item.ItemPoisonBomb; +import electroblob.wizardry.item.ItemScroll; +import electroblob.wizardry.item.ItemSmokeBomb; +import electroblob.wizardry.item.ItemSpectralArmour; +import electroblob.wizardry.item.ItemSpectralBow; +import electroblob.wizardry.item.ItemSpectralPickaxe; +import electroblob.wizardry.item.ItemSpectralSword; +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.item.ItemWizardArmour; +import electroblob.wizardry.item.ItemWizardHandbook; +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.Item; +import net.minecraft.item.Item.ToolMaterial; +import net.minecraft.item.ItemArmor.ArmorMaterial; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.common.util.EnumHelper; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.IForgeRegistry; + +/** + * Class responsible for defining, storing and registering all of wizardry's items. Also registers the ItemBlocks for + * wizardry's blocks. + * @author Electroblob + * @since Wizardry 2.1 + */ +@Mod.EventBusSubscriber +public final class WizardryItems { + + public static final Item magic_crystal = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + + public static final Item magic_wand = new ItemWand(Tier.BASIC, null); + public static final Item apprentice_wand = new ItemWand(Tier.APPRENTICE, null); + public static final Item advanced_wand = new ItemWand(Tier.ADVANCED, null); + public static final Item master_wand = new ItemWand(Tier.MASTER, null); + + public static final Item arcane_tome = new ItemArcaneTome(); + public static final Item wizard_handbook = new ItemWizardHandbook(); + public static final Item spell_book = new ItemSpellBook(); + + public static final Item basic_fire_wand = new ItemWand(Tier.BASIC, Element.FIRE); + public static final Item basic_ice_wand = new ItemWand(Tier.BASIC, Element.ICE); + public static final Item basic_lightning_wand = new ItemWand(Tier.BASIC, Element.LIGHTNING); + public static final Item basic_necromancy_wand = new ItemWand(Tier.BASIC, Element.NECROMANCY); + public static final Item basic_earth_wand = new ItemWand(Tier.BASIC, Element.EARTH); + public static final Item basic_sorcery_wand = new ItemWand(Tier.BASIC, Element.SORCERY); + public static final Item basic_healing_wand = new ItemWand(Tier.BASIC, Element.HEALING); + + public static final Item apprentice_fire_wand = new ItemWand(Tier.APPRENTICE, Element.FIRE); + public static final Item apprentice_ice_wand = new ItemWand(Tier.APPRENTICE, Element.ICE); + public static final Item apprentice_lightning_wand = new ItemWand(Tier.APPRENTICE, Element.LIGHTNING); + public static final Item apprentice_necromancy_wand = new ItemWand(Tier.APPRENTICE, Element.NECROMANCY); + public static final Item apprentice_earth_wand = new ItemWand(Tier.APPRENTICE, Element.EARTH); + public static final Item apprentice_sorcery_wand = new ItemWand(Tier.APPRENTICE, Element.SORCERY); + public static final Item apprentice_healing_wand = new ItemWand(Tier.APPRENTICE, Element.HEALING); + + public static final Item advanced_fire_wand = new ItemWand(Tier.ADVANCED, Element.FIRE); + public static final Item advanced_ice_wand = new ItemWand(Tier.ADVANCED, Element.ICE); + public static final Item advanced_lightning_wand = new ItemWand(Tier.ADVANCED, Element.LIGHTNING); + public static final Item advanced_necromancy_wand = new ItemWand(Tier.ADVANCED, Element.NECROMANCY); + public static final Item advanced_earth_wand = new ItemWand(Tier.ADVANCED, Element.EARTH); + public static final Item advanced_sorcery_wand = new ItemWand(Tier.ADVANCED, Element.SORCERY); + public static final Item advanced_healing_wand = new ItemWand(Tier.ADVANCED, Element.HEALING); + + public static final Item master_fire_wand = new ItemWand(Tier.MASTER, Element.FIRE); + public static final Item master_ice_wand = new ItemWand(Tier.MASTER, Element.ICE); + public static final Item master_lightning_wand = new ItemWand(Tier.MASTER, Element.LIGHTNING); + public static final Item master_necromancy_wand = new ItemWand(Tier.MASTER, Element.NECROMANCY); + public static final Item master_earth_wand = new ItemWand(Tier.MASTER, Element.EARTH); + public static final Item master_sorcery_wand = new ItemWand(Tier.MASTER, Element.SORCERY); + public static final Item master_healing_wand = new ItemWand(Tier.MASTER, Element.HEALING); + + public static final Item spectral_sword = new ItemSpectralSword(ToolMaterial.IRON); + public static final Item spectral_pickaxe = new ItemSpectralPickaxe(ToolMaterial.IRON); + public static final Item spectral_bow = new ItemSpectralBow(); + + public static final Item mana_flask = new Item(){ + @Override + public void onCreated(ItemStack par1ItemStack, World par2World, EntityPlayer entityplayer){ + entityplayer.addStat(WizardryAchievements.craft_flask); + } + }.setCreativeTab(WizardryTabs.WIZARDRY); + + public static final Item storage_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + public static final Item siphon_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + public static final Item condenser_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + public static final Item range_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + public static final Item duration_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + public static final Item cooldown_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + public static final Item blast_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + public static final Item attunement_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + + public static final Item magic_silk = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + + public static final Item.ToolMaterial MAGICAL = EnumHelper.addToolMaterial("MAGICAL", 3, 1000, 8.0f, 4.0f, 0); + + public static final Item flaming_axe = new ItemFlamingAxe(MAGICAL); + public static final Item frost_axe = new ItemFrostAxe(MAGICAL); + + public static final Item firebomb = new ItemFirebomb(); + public static final Item poison_bomb = new ItemPoisonBomb(); + + public static final Item blank_scroll = new Item().setCreativeTab(WizardryTabs.WIZARDRY); + public static final Item scroll = new ItemScroll().setCreativeTab(WizardryTabs.SPELLS); + + // The only way to get these is in dungeon chests (They are legendary, after all. Wizards don't just have them. + // Also if they were sold you could buy four from the same wizard - and that's no fun at all!) + public static final Item armour_upgrade = new ItemArmourUpgrade(); + + public static final ArmorMaterial SILK = EnumHelper.addArmorMaterial("SILK", "wizardry/textures/armour/wizard_armour", + 15, new int[]{2, 5, 4, 2}, 0, SoundEvents.ITEM_ARMOR_EQUIP_LEATHER, 0.0F); + // Saw a post somewhere that said you have to put these in the init methods rather than defining them as constants. + // I *think* that's because the post was for a newer Minecraft version, where custom armour has its own renderer or + // something, meaning it would be done a lot like the entity rendering registry in ClientProxy. This is all working + // fine it seems, so I'm not going to fiddle with it, but it might be useful to know if I update versions again. + public static final Item wizard_hat = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, null); + public static final Item wizard_robe = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, null); + public static final Item wizard_leggings = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, null); + public static final Item wizard_boots = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, null); + + public static final Item wizard_hat_fire = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.FIRE); + public static final Item wizard_robe_fire = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.FIRE); + public static final Item wizard_leggings_fire = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.FIRE); + public static final Item wizard_boots_fire = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.FIRE); + + public static final Item wizard_hat_ice = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.ICE); + public static final Item wizard_robe_ice = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.ICE); + public static final Item wizard_leggings_ice = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.ICE); + public static final Item wizard_boots_ice = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.ICE); + + public static final Item wizard_hat_lightning = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.LIGHTNING); + public static final Item wizard_robe_lightning = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.LIGHTNING); + public static final Item wizard_leggings_lightning = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.LIGHTNING); + public static final Item wizard_boots_lightning = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.LIGHTNING); + + public static final Item wizard_hat_necromancy = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.NECROMANCY); + public static final Item wizard_robe_necromancy = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.NECROMANCY); + public static final Item wizard_leggings_necromancy = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.NECROMANCY); + public static final Item wizard_boots_necromancy = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.NECROMANCY); + + public static final Item wizard_hat_earth = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.EARTH); + public static final Item wizard_robe_earth = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.EARTH); + public static final Item wizard_leggings_earth = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.EARTH); + public static final Item wizard_boots_earth = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.EARTH); + + public static final Item wizard_hat_sorcery = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.SORCERY); + public static final Item wizard_robe_sorcery = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.SORCERY); + public static final Item wizard_leggings_sorcery = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.SORCERY); + public static final Item wizard_boots_sorcery = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.SORCERY); + + public static final Item wizard_hat_healing = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.HEALING); + public static final Item wizard_robe_healing = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.HEALING); + public static final Item wizard_leggings_healing = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.HEALING); + public static final Item wizard_boots_healing = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.HEALING); + + public static final Item spectral_helmet = new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.HEAD); + public static final Item spectral_chestplate = new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.CHEST); + public static final Item spectral_leggings = new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.LEGS); + public static final Item spectral_boots = new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.FEET); + + public static final Item smoke_bomb = new ItemSmokeBomb(); + + public static final Item identification_scroll = new ItemIdentificationScroll(); + + public static final Map, Item> WAND_MAP = new HashMap<>(); + public static final Map, Item> ARMOUR_MAP = new HashMap<>(); + + static { + + WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.MAGIC), magic_wand); + WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.FIRE), basic_fire_wand); + WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.ICE), basic_ice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.LIGHTNING), basic_lightning_wand); + WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.NECROMANCY), basic_necromancy_wand); + WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.EARTH), basic_earth_wand); + WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.SORCERY), basic_sorcery_wand); + WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.HEALING), basic_healing_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.MAGIC), apprentice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.FIRE), apprentice_fire_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.ICE), apprentice_ice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.LIGHTNING), apprentice_lightning_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.NECROMANCY), apprentice_necromancy_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.EARTH), apprentice_earth_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.SORCERY), apprentice_sorcery_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.HEALING), apprentice_healing_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.MAGIC), advanced_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.FIRE), advanced_fire_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.ICE), advanced_ice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.LIGHTNING), advanced_lightning_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.NECROMANCY), advanced_necromancy_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.EARTH), advanced_earth_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.SORCERY), advanced_sorcery_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.HEALING), advanced_healing_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.MAGIC), master_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.FIRE), master_fire_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.ICE), master_ice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.LIGHTNING), master_lightning_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.NECROMANCY), master_necromancy_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.EARTH), master_earth_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.SORCERY), master_sorcery_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.HEALING), master_healing_wand); + + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.MAGIC), wizard_hat); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.FIRE), wizard_hat_fire); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.ICE), wizard_hat_ice); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.LIGHTNING), wizard_hat_lightning); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.NECROMANCY), wizard_hat_necromancy); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.EARTH), wizard_hat_earth); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.SORCERY), wizard_hat_sorcery); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.HEALING), wizard_hat_healing); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.MAGIC), wizard_robe); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.FIRE), wizard_robe_fire); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.ICE), wizard_robe_ice); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.LIGHTNING), wizard_robe_lightning); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.NECROMANCY), wizard_robe_necromancy); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.EARTH), wizard_robe_earth); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.SORCERY), wizard_robe_sorcery); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.HEALING), wizard_robe_healing); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.MAGIC), wizard_leggings); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.FIRE), wizard_leggings_fire); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.ICE), wizard_leggings_ice); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.LIGHTNING), wizard_leggings_lightning); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.NECROMANCY), wizard_leggings_necromancy); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.EARTH), wizard_leggings_earth); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.SORCERY), wizard_leggings_sorcery); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.HEALING), wizard_leggings_healing); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.MAGIC), wizard_boots); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.FIRE), wizard_boots_fire); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.ICE), wizard_boots_ice); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.LIGHTNING), wizard_boots_lightning); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.NECROMANCY), wizard_boots_necromancy); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.EARTH), wizard_boots_earth); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.SORCERY), wizard_boots_sorcery); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.HEALING), wizard_boots_healing); + } + + /** + * Sets both the registry and unlocalised names of the given item, then registers it with the given registry. Use + * this instead of {@link Item#setRegistryName(String)} and {@link Item#setUnlocalizedName(String)} during + * construction, for convenience and consistency. + * @param registry The registry to register the given item to. + * @param item The item to register. + * @param name The name of the item, without the mod ID or the .name stuff. The registry name will be + * {@code wizardry:[name]}. The unlocalised name will be {@code item.wizardry:[name].name}. + */ + public static void registerItem(IForgeRegistry registry, Item item, String name){ + item.setRegistryName(Wizardry.MODID, name); + item.setUnlocalizedName(item.getRegistryName().toString()); + registry.register(item); + } + + /** Registers an ItemBlock afor the given block, with the same registry name as that block. */ + private static void registerItemBlock(IForgeRegistry registry, Block block){ + // We don't need to keep a reference to the ItemBlock, so this can all be done in one line. + registry.register(new ItemBlock(block).setRegistryName(block.getRegistryName())); + } + + @SubscribeEvent + public static void register(RegistryEvent.Register event){ + + IForgeRegistry registry = event.getRegistry(); + + // ItemBlocks + + // Not all blocks need an ItemBlock + registerItemBlock(registry, WizardryBlocks.arcane_workbench); + registerItemBlock(registry, WizardryBlocks.crystal_ore); + registerItemBlock(registry, WizardryBlocks.crystal_flower); + registerItemBlock(registry, WizardryBlocks.transportation_stone); + registerItemBlock(registry, WizardryBlocks.crystal_block); + + // Items + + registerItem(registry, magic_crystal, "magic_crystal"); + + registerItem(registry, magic_wand, "magic_wand"); + registerItem(registry, apprentice_wand, "apprentice_wand"); + registerItem(registry, advanced_wand, "advanced_wand"); + registerItem(registry, master_wand, "master_wand"); + + registerItem(registry, spell_book, "spell_book"); + registerItem(registry, arcane_tome, "arcane_tome"); + registerItem(registry, wizard_handbook, "wizard_handbook"); + + registerItem(registry, basic_fire_wand, "basic_fire_wand"); + registerItem(registry, basic_ice_wand, "basic_ice_wand"); + registerItem(registry, basic_lightning_wand, "basic_lightning_wand"); + registerItem(registry, basic_necromancy_wand, "basic_necromancy_wand"); + registerItem(registry, basic_earth_wand, "basic_earth_wand"); + registerItem(registry, basic_sorcery_wand, "basic_sorcery_wand"); + registerItem(registry, basic_healing_wand, "basic_healing_wand"); + + registerItem(registry, apprentice_fire_wand, "apprentice_fire_wand"); + registerItem(registry, apprentice_ice_wand, "apprentice_ice_wand"); + registerItem(registry, apprentice_lightning_wand, "apprentice_lightning_wand"); + registerItem(registry, apprentice_necromancy_wand, "apprentice_necromancy_wand"); + registerItem(registry, apprentice_earth_wand, "apprentice_earth_wand"); + registerItem(registry, apprentice_sorcery_wand, "apprentice_sorcery_wand"); + registerItem(registry, apprentice_healing_wand, "apprentice_healing_wand"); + + registerItem(registry, advanced_fire_wand, "advanced_fire_wand"); + registerItem(registry, advanced_ice_wand, "advanced_ice_wand"); + registerItem(registry, advanced_lightning_wand, "advanced_lightning_wand"); + registerItem(registry, advanced_necromancy_wand, "advanced_necromancy_wand"); + registerItem(registry, advanced_earth_wand, "advanced_earth_wand"); + registerItem(registry, advanced_sorcery_wand, "advanced_sorcery_wand"); + registerItem(registry, advanced_healing_wand, "advanced_healing_wand"); + + registerItem(registry, master_fire_wand, "master_fire_wand"); + registerItem(registry, master_ice_wand, "master_ice_wand"); + registerItem(registry, master_lightning_wand, "master_lightning_wand"); + registerItem(registry, master_necromancy_wand, "master_necromancy_wand"); + registerItem(registry, master_earth_wand, "master_earth_wand"); + registerItem(registry, master_sorcery_wand, "master_sorcery_wand"); + registerItem(registry, master_healing_wand, "master_healing_wand"); + + registerItem(registry, spectral_sword, "spectral_sword"); + registerItem(registry, spectral_pickaxe, "spectral_pickaxe"); + registerItem(registry, spectral_bow, "spectral_bow"); + + registerItem(registry, mana_flask, "mana_flask"); + + registerItem(registry, storage_upgrade, "storage_upgrade"); + registerItem(registry, siphon_upgrade, "siphon_upgrade"); + registerItem(registry, condenser_upgrade, "condenser_upgrade"); + registerItem(registry, range_upgrade, "range_upgrade"); + registerItem(registry, duration_upgrade, "duration_upgrade"); + registerItem(registry, cooldown_upgrade, "cooldown_upgrade"); + registerItem(registry, blast_upgrade, "blast_upgrade"); + registerItem(registry, attunement_upgrade, "attunement_upgrade"); + + registerItem(registry, flaming_axe, "flaming_axe"); + registerItem(registry, frost_axe, "frost_axe"); + + registerItem(registry, firebomb, "firebomb"); + registerItem(registry, poison_bomb, "poison_bomb"); + + registerItem(registry, blank_scroll, "blank_scroll"); + registerItem(registry, scroll, "scroll"); + + registerItem(registry, armour_upgrade, "armour_upgrade"); + + registerItem(registry, magic_silk, "magic_silk"); + + registerItem(registry, wizard_hat, "wizard_hat"); + registerItem(registry, wizard_robe, "wizard_robe"); + registerItem(registry, wizard_leggings, "wizard_leggings"); + registerItem(registry, wizard_boots, "wizard_boots"); + + registerItem(registry, wizard_hat_fire, "wizard_hat_fire"); + registerItem(registry, wizard_robe_fire, "wizard_robe_fire"); + registerItem(registry, wizard_leggings_fire, "wizard_leggings_fire"); + registerItem(registry, wizard_boots_fire, "wizard_boots_fire"); + + registerItem(registry, wizard_hat_ice, "wizard_hat_ice"); + registerItem(registry, wizard_robe_ice, "wizard_robe_ice"); + registerItem(registry, wizard_leggings_ice, "wizard_leggings_ice"); + registerItem(registry, wizard_boots_ice, "wizard_boots_ice"); + + registerItem(registry, wizard_hat_lightning, "wizard_hat_lightning"); + registerItem(registry, wizard_robe_lightning, "wizard_robe_lightning"); + registerItem(registry, wizard_leggings_lightning, "wizard_leggings_lightning"); + registerItem(registry, wizard_boots_lightning, "wizard_boots_lightning"); + + registerItem(registry, wizard_hat_necromancy, "wizard_hat_necromancy"); + registerItem(registry, wizard_robe_necromancy, "wizard_robe_necromancy"); + registerItem(registry, wizard_leggings_necromancy, "wizard_leggings_necromancy"); + registerItem(registry, wizard_boots_necromancy, "wizard_boots_necromancy"); + + registerItem(registry, wizard_hat_earth, "wizard_hat_earth"); + registerItem(registry, wizard_robe_earth, "wizard_robe_earth"); + registerItem(registry, wizard_leggings_earth, "wizard_leggings_earth"); + registerItem(registry, wizard_boots_earth, "wizard_boots_earth"); + + registerItem(registry, wizard_hat_sorcery, "wizard_hat_sorcery"); + registerItem(registry, wizard_robe_sorcery, "wizard_robe_sorcery"); + registerItem(registry, wizard_leggings_sorcery, "wizard_leggings_sorcery"); + registerItem(registry, wizard_boots_sorcery, "wizard_boots_sorcery"); + + registerItem(registry, wizard_hat_healing, "wizard_hat_healing"); + registerItem(registry, wizard_robe_healing, "wizard_robe_healing"); + registerItem(registry, wizard_leggings_healing, "wizard_leggings_healing"); + registerItem(registry, wizard_boots_healing, "wizard_boots_healing"); + + registerItem(registry, spectral_helmet, "spectral_helmet"); + registerItem(registry, spectral_chestplate, "spectral_chestplate"); + registerItem(registry, spectral_leggings, "spectral_leggings"); + registerItem(registry, spectral_boots, "spectral_boots"); + + registerItem(registry, smoke_bomb, "smoke_bomb"); + + registerItem(registry, identification_scroll, "identification_scroll"); + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryPotions.java b/src/main/java/electroblob/wizardry/registry/WizardryPotions.java new file mode 100644 index 00000000..4b51a675 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryPotions.java @@ -0,0 +1,113 @@ +package electroblob.wizardry.registry; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.potion.PotionDecay; +import electroblob.wizardry.potion.PotionFrost; +import electroblob.wizardry.potion.PotionMagicEffect; +import electroblob.wizardry.potion.PotionMagicEffectParticles; +import electroblob.wizardry.util.WizardryParticleType; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.potion.Potion; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.world.World; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.IForgeRegistry; + +/** + * Class responsible for defining, storing and registering all of wizardry's potion effects. + * @author Electroblob + * @since Wizardry 2.1 + */ +@Mod.EventBusSubscriber +public final class WizardryPotions { + + /* Interestingly, setting the colour to black stops the particles from rendering. This is great, however, the black + * colour then 'mixes' with other potions that are applied. Whilst this is a bit annoying, for the amount it is + * likely to get noticed it is certainly preferable to always making showParticles false, because now I can give + * the user the option (via commands) of having one of my potion effects without particles, and more importantly + * the potion effect HUD still gets displayed. TODO: Backport to 1.7.10, assuming it also works in that version. + * This means also changing whenever the potion effect is added such that it is NOT ambient. */ + + public static final Potion frost = new PotionFrost(true, 0); // Colour was 0x38ddec (was arbitrary anyway) + + public static final Potion transience = new PotionMagicEffectParticles(false, 0, 0){ + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, x, y, z, 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)), 0.8f, 0.8f, 1.0f); + } + }.setBeneficial(); //0xffe89b + + public static final Potion fireskin = new PotionMagicEffectParticles(false, 0, 1){ + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + world.spawnParticle(EnumParticleTypes.FLAME, x, y, z, 0, 0, 0); + } + @Override + public void performEffect(EntityLivingBase entitylivingbase, int strength){ + entitylivingbase.extinguish(); // Stops melee mobs that are on fire from setting the player on fire, + // without allowing the player to actually stand in fire or swim in lava without taking damage. + }; + }.setBeneficial(); //0xff2f02 + + public static final Potion ice_shroud = new PotionMagicEffectParticles(false, 0, 2){ + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + float brightness = 0.5f + (world.rand.nextFloat()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x, y, z, 0, 0, 0, 48 + world.rand.nextInt(12), brightness, brightness + 0.1f, 1.0f, true, 0); + Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, x, y, z, 0, -0.02, 0, 40 + world.rand.nextInt(10)); + } + }.setBeneficial(); //0x52f1ff + + public static final Potion static_aura = new PotionMagicEffectParticles(false, 0, 3){ + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, x, y, z, 0, 0, 0, 3); + } + }.setBeneficial(); //0x0070ff + + public static final Potion decay = new PotionDecay(true, 0x3c006c); + public static final Potion sixth_sense = new PotionMagicEffect(false, 0xc6ff01, 4).setBeneficial(); + public static final Potion arcane_jammer = new PotionMagicEffect(false, 0xcf4aa2, 5); + public static final Potion mind_trick = new PotionMagicEffect(true, 0x601683, 6); + public static final Potion mind_control = new PotionMagicEffect(true, 0x320b44, 7); + public static final Potion font_of_mana = new PotionMagicEffect(false, 0xffe5bb, 8).setBeneficial(); + public static final Potion fear = new PotionMagicEffect(true, 0xbd0100, 9); + + /** + * Sets both the registry and unlocalised names of the given potion, then registers it with the given registry. Use + * this instead of {@link potion#setRegistryName(String)} and {@link potion#setUnlocalizedName(String)} during + * construction, for convenience and consistency. + * @param registry The registry to register the given potion to. + * @param potion The potion to register. + * @param name The name of the potion, without the mod ID or the .name stuff. The registry name will be + * {@code wizardry:[name]}. The unlocalised name will be {@code potion.wizardry:[name].name}. + */ + public static void registerPotion(IForgeRegistry registry, Potion potion, String name){ + potion.setRegistryName(Wizardry.MODID, name); + // For some reason, Potion#getName() doesn't prepend "potion." itself, so it has to be done here. + potion.setPotionName("potion." + potion.getRegistryName().toString()); + registry.register(potion); + } + + @SubscribeEvent + public static void register(RegistryEvent.Register event){ + + IForgeRegistry registry = event.getRegistry(); + + registerPotion(registry, frost, "frost"); + registerPotion(registry, transience, "transience"); + registerPotion(registry, fireskin, "fireskin"); + registerPotion(registry, ice_shroud, "ice_shroud"); + registerPotion(registry, static_aura, "static_aura"); + registerPotion(registry, decay, "decay"); + registerPotion(registry, sixth_sense, "sixth_sense"); + registerPotion(registry, arcane_jammer, "arcane_jammer"); + registerPotion(registry, mind_trick, "mind_trick"); + registerPotion(registry, mind_control, "mind_control"); + registerPotion(registry, font_of_mana, "font_of_mana"); + registerPotion(registry, fear, "fear"); + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java b/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java new file mode 100644 index 00000000..f8103bf1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java @@ -0,0 +1,320 @@ +package electroblob.wizardry.registry; + +import java.util.ArrayList; +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.entity.EntityMeteor; +import electroblob.wizardry.entity.EntityShield; +import electroblob.wizardry.entity.construct.EntityArrowRain; +import electroblob.wizardry.entity.construct.EntityBlackHole; +import electroblob.wizardry.entity.construct.EntityBlizzard; +import electroblob.wizardry.entity.construct.EntityBubble; +import electroblob.wizardry.entity.construct.EntityDecay; +import electroblob.wizardry.entity.construct.EntityEarthquake; +import electroblob.wizardry.entity.construct.EntityFireRing; +import electroblob.wizardry.entity.construct.EntityFireSigil; +import electroblob.wizardry.entity.construct.EntityForcefield; +import electroblob.wizardry.entity.construct.EntityFrostSigil; +import electroblob.wizardry.entity.construct.EntityHailstorm; +import electroblob.wizardry.entity.construct.EntityHammer; +import electroblob.wizardry.entity.construct.EntityHealAura; +import electroblob.wizardry.entity.construct.EntityIceSpike; +import electroblob.wizardry.entity.construct.EntityLightningPulse; +import electroblob.wizardry.entity.construct.EntityLightningSigil; +import electroblob.wizardry.entity.construct.EntityTornado; +import electroblob.wizardry.entity.living.EntityBlazeMinion; +import electroblob.wizardry.entity.living.EntityDecoy; +import electroblob.wizardry.entity.living.EntityEvilWizard; +import electroblob.wizardry.entity.living.EntityIceGiant; +import electroblob.wizardry.entity.living.EntityIceWraith; +import electroblob.wizardry.entity.living.EntityLightningWraith; +import electroblob.wizardry.entity.living.EntityMagicSlime; +import electroblob.wizardry.entity.living.EntityPhoenix; +import electroblob.wizardry.entity.living.EntityShadowWraith; +import electroblob.wizardry.entity.living.EntitySilverfishMinion; +import electroblob.wizardry.entity.living.EntitySkeletonMinion; +import electroblob.wizardry.entity.living.EntitySpiderMinion; +import electroblob.wizardry.entity.living.EntitySpiritHorse; +import electroblob.wizardry.entity.living.EntitySpiritWolf; +import electroblob.wizardry.entity.living.EntityStormElemental; +import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.entity.living.EntityZombieMinion; +import electroblob.wizardry.entity.projectile.EntityDarknessOrb; +import electroblob.wizardry.entity.projectile.EntityDart; +import electroblob.wizardry.entity.projectile.EntityFirebolt; +import electroblob.wizardry.entity.projectile.EntityFirebomb; +import electroblob.wizardry.entity.projectile.EntityForceArrow; +import electroblob.wizardry.entity.projectile.EntityForceOrb; +import electroblob.wizardry.entity.projectile.EntityIceCharge; +import electroblob.wizardry.entity.projectile.EntityIceLance; +import electroblob.wizardry.entity.projectile.EntityIceShard; +import electroblob.wizardry.entity.projectile.EntityLightningArrow; +import electroblob.wizardry.entity.projectile.EntityLightningDisc; +import electroblob.wizardry.entity.projectile.EntityMagicMissile; +import electroblob.wizardry.entity.projectile.EntityPoisonBomb; +import electroblob.wizardry.entity.projectile.EntitySmokeBomb; +import electroblob.wizardry.entity.projectile.EntitySpark; +import electroblob.wizardry.entity.projectile.EntitySparkBomb; +import electroblob.wizardry.entity.projectile.EntityThunderbolt; +import electroblob.wizardry.loot.RandomSpell; +import electroblob.wizardry.loot.WizardSpell; +import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; +import electroblob.wizardry.tileentity.TileEntityMagicLight; +import electroblob.wizardry.tileentity.TileEntityPlayerSave; +import electroblob.wizardry.tileentity.TileEntityStatue; +import electroblob.wizardry.tileentity.TileEntityTimer; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.init.Biomes; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.storage.loot.LootTableList; +import net.minecraft.world.storage.loot.functions.LootFunctionManager; +import net.minecraftforge.fml.common.registry.EntityRegistry; +import net.minecraftforge.fml.common.registry.GameRegistry; +import net.minecraftforge.oredict.OreDictionary; + +/** + * Class responsible for registering all the things that don't have (or need) instances: entities, loot tables, + * recipes, etc. + * @author Electroblob + * @since Wizardry 1.0 + */ +public final class WizardryRegistry { + + // NOTE: In 1.12, recipes have a registry (they can still stay here though since we don't keep references to them) + + /** Called from the preInit method in the main mod class to register the custom dungeon loot. */ + public static void registerLoot(){ + + /* Loot tables work as follows: + * Minecraft goes through each pool in turn. For each pool, it does a certain number or rolls, which can either + * be set to always be one number or a random number from a range. Each roll, it generates one stack of a single + * random entry in that pool, weighted according to the weights of the entries. Functions allow properties of + * that stack (stack size, damage, nbt) to be set, and even allow it to be replaced dynamically with a + * completely different item (though there's very little point in doing that as it could be achieved just as + * easily with more entries, which makes me think it would be bad practice). + * You can also use conditions to control whether an entry or pool is used at all, which is mostly for mob drops + * under specific conditions, but one of them is simply a random chance, meaning you could use it to make a pool + * that only gets rolled sometimes. + * All in all, this can get rather confusing, because stackable items can have 5 stages of randomness applied + * to them at once: a random chance for the pool, a random number of rolls for the pool, the weighted random + * chance of choosing that particular entry, a random chance for that entry, and a random stack size, and that's + * before you take functions into account. + * + * ...oh, and entries can be entire loot tables in themselves, allowing for potentially infinite levels of + * randomness. Yeah. + * + * Translating to the new system: + * ChestGenHooks.SOME_NAME -> loot table json file + * ??? -> loot pool (I don't think it was split up like this before) + * ChestGenHooks.addItem() -> entry in a loot pool + * Stack sizes in WeightedRandomChestContent -> set_count function for entries + * Weight in WeightedRandomChestContent -> weight of entries + * Custom WeightedRandomChestContent implementations -> custom loot functions, but only for complex/dynamic + * stuff - things that serve to allow the chance for a category of items (like armour) to be specified but still + * have a random chance for which exact item you get should be done with nested loot tables. + */ + + // Always registers the loot tables, but only injects the additions into vanilla if the appropriate option is + // enabled in the config (see WizardryEventHandler). + LootFunctionManager.registerFunction(new RandomSpell.Serializer()); + LootFunctionManager.registerFunction(new WizardSpell.Serializer()); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/wizard_tower")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/dungeon_additions")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/novice_wands")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/wizard_armour")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/arcane_tomes")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/wand_upgrades")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "entities/evil_wizard")); + // TODO: At the moment this is not used anywhere because I can't find a way to add it to all mobs. + //LootTableList.register(new ResourceLocation(Wizardry.MODID, "entities/mob_additions")); + + } + + /** Called from the preInit method in the main mod class to register all the tile entities. */ + public static void registerTileEntities(){ + + GameRegistry.registerTileEntity(TileEntityArcaneWorkbench.class, Wizardry.MODID + "ArcaneWorkbenchTileEntity"); + GameRegistry.registerTileEntity(TileEntityStatue.class, Wizardry.MODID + "PetrifiedStoneTileEntity"); + GameRegistry.registerTileEntity(TileEntityMagicLight.class, Wizardry.MODID + "MagicLightTileEntity"); + GameRegistry.registerTileEntity(TileEntityTimer.class, Wizardry.MODID + "TimerTileEntity"); + GameRegistry.registerTileEntity(TileEntityPlayerSave.class, Wizardry.MODID + "TileEntityPlayerSave"); + } + + /** Not actually the frequency at all; smaller numbers are more frequent. Vanilla uses 3 I think. */ + private static final int LIVING_UPDATE_INTERVAL = 3; + /** Not actually the frequency at all; smaller numbers are more frequent. */ + private static final int PROJECTILE_UPDATE_INTERVAL = 10; + + /** Called from the preInit method in the main mod class to register all the entities. */ + public static void registerEntities(Wizardry wizardry){ + + int id = 0; // Incrementable index for the mod specific entity id. + + EntityRegistry.registerModEntity(EntityZombieMinion.class, "zombie_minion", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityMagicMissile.class, "magic_missile", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + // TODO: This should be a particle + EntityRegistry.registerModEntity(EntityArc.class, "arc", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntitySkeletonMinion.class, "skeleton_minion", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntitySparkBomb.class, "spark_bomb", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntitySpiritWolf.class, "spirit_wolf", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityIceShard.class, "ice_shard", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityBlazeMinion.class, "blaze_minion", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityIceWraith.class, "ice_wraith", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityLightningWraith.class, "lightning_wraith", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityBlackHole.class, "black_hole", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityShield.class, "shield", id++, wizardry, 128, 1, true); + EntityRegistry.registerModEntity(EntityMeteor.class, "meteor", id++, wizardry, 128, 5, true); + EntityRegistry.registerModEntity(EntityBlizzard.class, "blizzard", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityWizard.class, "wizard", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityBubble.class, "bubble", id++, wizardry, 128, 3, false); + EntityRegistry.registerModEntity(EntityTornado.class, "tornado", id++, wizardry, 128, 1, false); + EntityRegistry.registerModEntity(EntityHammer.class, "lightning_hammer", id++, wizardry, 128, 1, true); + EntityRegistry.registerModEntity(EntityFirebomb.class, "firebomb", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityForceOrb.class, "force_orb", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityArrowRain.class, "arrow_rain", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntitySpark.class, "spark", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityShadowWraith.class, "shadow_wraith", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityDarknessOrb.class, "darkness_orb", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntitySpiderMinion.class, "spider_minion", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityHealAura.class, "healing_aura", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityFireSigil.class, "fire_sigil", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityFrostSigil.class, "frost_sigil", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityLightningSigil.class, "lightning_sigil", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityLightningArrow.class, "lightning_arrow", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityFirebolt.class, "firebolt", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityPoisonBomb.class, "poison_bomb", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityIceCharge.class, "ice_charge", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityForceArrow.class, "force_arrow", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityDart.class, "dart", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityMagicSlime.class, "magic_slime", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityForcefield.class, "forcefield", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityFireRing.class, "ring_of_fire", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityLightningDisc.class, "lightning_disc", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityThunderbolt.class, "thunderbolt", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityIceGiant.class, "ice_giant", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntitySpiritHorse.class, "spirit_horse", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityPhoenix.class, "phoenix", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntitySilverfishMinion.class, "silverfish_minion", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityDecay.class, "decay", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityStormElemental.class, "storm_elemental", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityEarthquake.class, "earthquake", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntityIceLance.class, "ice_lance", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityHailstorm.class, "hailstorm", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + EntityRegistry.registerModEntity(EntitySmokeBomb.class, "smoke_bomb", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityEvilWizard.class, "evil_wizard", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityDecoy.class, "decoy", id++, wizardry, 128, LIVING_UPDATE_INTERVAL, true); + EntityRegistry.registerModEntity(EntityIceSpike.class, "ice_spike", id++, wizardry, 128, 1, true); + // TODO: This should be a particle. + EntityRegistry.registerModEntity(EntityLightningPulse.class, "lightning_pulse", id++, wizardry, 128, PROJECTILE_UPDATE_INTERVAL, false); + + EntityRegistry.registerEgg(EntityWizard.class, 0x19295e, 0xee9312); + EntityRegistry.registerEgg(EntityEvilWizard.class, 0x290404, 0xee9312); + + // TODO: May need fixing + List biomes = new ArrayList(); + for(Biome biome : Biome.EXPLORATION_BIOMES_LIST){ + if(biome != null){ + biomes.add(biome); + } + } + biomes.remove(Biomes.MUSHROOM_ISLAND); + biomes.remove(Biomes.MUSHROOM_ISLAND_SHORE); + // For reference: 5, 1, 1 are the parameters for the witch in vanilla. + EntityRegistry.addSpawn(EntityEvilWizard.class, 3, 1, 1, EnumCreatureType.MONSTER, biomes.toArray(new Biome[biomes.size()])); + + } + + /** Called from the init method in the main mod class to register all the recipes. */ + public static void registerRecipes(){ + + ItemStack magicCrystalStack = new ItemStack(WizardryItems.magic_crystal); + ItemStack magicWandStack = new ItemStack(WizardryItems.magic_wand, 1, Tier.BASIC.maxCharge); + ItemStack goldNuggetStack = new ItemStack(Items.GOLD_NUGGET); + ItemStack stickStack = new ItemStack(Items.STICK); + ItemStack bookStack = new ItemStack(Items.BOOK); + ItemStack stringStack = new ItemStack(Items.STRING); + ItemStack spellBookStack = new ItemStack(WizardryItems.spell_book, 1, Spells.magic_missile.id()); + ItemStack arcaneWorkbenchStack = new ItemStack(WizardryBlocks.arcane_workbench); + ItemStack stoneStack = new ItemStack(Blocks.STONE); + ItemStack lapisBlockStack = new ItemStack(Blocks.LAPIS_BLOCK); + ItemStack purpleCarpetStack = new ItemStack(Blocks.CARPET, 1, 10); + ItemStack wizardHandbookStack = new ItemStack(WizardryItems.wizard_handbook); + ItemStack crystalFlowerStack = new ItemStack(WizardryBlocks.crystal_flower); + ItemStack magicCrystalStack1 = new ItemStack(WizardryItems.magic_crystal, 2); + ItemStack magicCrystalStack2 = new ItemStack(WizardryItems.magic_crystal, 9); + ItemStack crystalBlockStack = new ItemStack(WizardryBlocks.crystal_block); + ItemStack manaFlaskStack = new ItemStack(WizardryItems.mana_flask); + ItemStack bottleStack = new ItemStack(Items.GLASS_BOTTLE); + ItemStack gunpowderStack = new ItemStack(Items.GUNPOWDER); + ItemStack blazePowderStack = new ItemStack(Items.BLAZE_POWDER); + ItemStack spiderEyeStack = new ItemStack(Items.SPIDER_EYE); + // Coal or charcoal is equally fine, hence the wildcard value + ItemStack coalStack = new ItemStack(Items.COAL, 1, OreDictionary.WILDCARD_VALUE); + ItemStack firebombStack = new ItemStack(WizardryItems.firebomb, 3); + ItemStack poisonBombStack = new ItemStack(WizardryItems.poison_bomb, 3); + ItemStack smokeBombStack = new ItemStack(WizardryItems.smoke_bomb, 3); + ItemStack transportationStoneStack = new ItemStack(WizardryBlocks.transportation_stone, 2); + ItemStack silkStack = new ItemStack(WizardryItems.magic_silk); + ItemStack silkStack1 = new ItemStack(WizardryItems.magic_silk, 2); + ItemStack hatStack = new ItemStack(WizardryItems.wizard_hat); + ItemStack robeStack = new ItemStack(WizardryItems.wizard_robe); + ItemStack leggingsStack = new ItemStack(WizardryItems.wizard_leggings); + ItemStack bootsStack = new ItemStack(WizardryItems.wizard_boots); + ItemStack scrollStack = new ItemStack(WizardryItems.blank_scroll); + ItemStack paperStack = new ItemStack(Items.PAPER); + + GameRegistry.addRecipe(magicWandStack, " x", " y ", "z ", 'x', magicCrystalStack, 'y', stickStack, 'z', goldNuggetStack); + GameRegistry.addRecipe(spellBookStack, " x ", "xyx", " x ", 'x', magicCrystalStack, 'y', bookStack); + GameRegistry.addRecipe(arcaneWorkbenchStack, "vwv", "xyx", "zzz", 'v', goldNuggetStack, 'w', purpleCarpetStack, 'x', magicCrystalStack, 'y', lapisBlockStack, 'z', stoneStack); + GameRegistry.addRecipe(manaFlaskStack, "yyy", "yxy", "yyy", 'x', bottleStack, 'y', magicCrystalStack); + GameRegistry.addRecipe(transportationStoneStack, " x ", "xyx", " x ", 'x', stoneStack, 'y', magicCrystalStack); + GameRegistry.addRecipe(hatStack, "yyy", "y y", 'y', silkStack); + GameRegistry.addRecipe(robeStack, "y y", "yyy", "yyy", 'y', silkStack); + GameRegistry.addRecipe(leggingsStack, "yyy", "y y", "y y", 'y', silkStack); + GameRegistry.addRecipe(bootsStack, "y y", "y y", 'y', silkStack); + GameRegistry.addRecipe(silkStack1, " x ", "xyx", " x ", 'x', stringStack, 'y', magicCrystalStack); + GameRegistry.addRecipe(crystalBlockStack, "zzz", "zzz", "zzz", 'z', magicCrystalStack); + + GameRegistry.addShapelessRecipe(wizardHandbookStack, bookStack, magicCrystalStack); + GameRegistry.addShapelessRecipe(magicCrystalStack1, crystalFlowerStack); + GameRegistry.addShapelessRecipe(magicCrystalStack2, crystalBlockStack); + if(Wizardry.settings.firebombIsCraftable) GameRegistry.addShapelessRecipe(firebombStack, bottleStack, gunpowderStack, blazePowderStack, blazePowderStack); + if(Wizardry.settings.poisonBombIsCraftable) GameRegistry.addShapelessRecipe(poisonBombStack, bottleStack, gunpowderStack, spiderEyeStack, spiderEyeStack); + if(Wizardry.settings.smokeBombIsCraftable) GameRegistry.addShapelessRecipe(smokeBombStack, bottleStack, gunpowderStack, coalStack, coalStack); + if(Wizardry.settings.useAlternateScrollRecipe){ + GameRegistry.addShapelessRecipe(scrollStack, paperStack, stringStack, magicCrystalStack); + }else{ + GameRegistry.addShapelessRecipe(scrollStack, paperStack, stringStack); + } + + // Mana flask recipes + ItemStack miscWandStack; + + for(Element element : Element.values()){ + for(Tier tier : Tier.values()){ + miscWandStack = new ItemStack(WizardryUtilities.getWand(tier, element), 1, OreDictionary.WILDCARD_VALUE); + GameRegistry.addShapelessRecipe(miscWandStack, miscWandStack, manaFlaskStack); + } + } + + ItemStack miscArmourStack; + + for(Element element : Element.values()){ + for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ + miscArmourStack = new ItemStack(WizardryUtilities.getArmour(element, slot), 1, OreDictionary.WILDCARD_VALUE); + GameRegistry.addShapelessRecipe(miscArmourStack, miscArmourStack, manaFlaskStack); + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java new file mode 100644 index 00000000..d006add1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java @@ -0,0 +1,68 @@ +package electroblob.wizardry.registry; + +import electroblob.wizardry.Wizardry; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +/** + * Class responsible for defining, storing and registering all of wizardry's sound events. For some reason, these + * worked in the beta versions despite not being registered... + * @author Electroblob + * @since Wizardry 2.1 + */ +@Mod.EventBusSubscriber +public final class WizardrySounds { + + // Anything with LOOP in its name is intended to be played in a continuous loop. + public static final SoundEvent SPELL_SPARK = createSound("arc"); + public static final SoundEvent SPELL_CONJURATION = createSound("aura"); + public static final SoundEvent SPELL_SHOCKWAVE = createSound("boom"); + public static final SoundEvent SPELL_LOOP_CRACKLE = createSound("crackle"); + public static final SoundEvent SPELL_SUMMONING = createSound("darkaura"); + public static final SoundEvent SPELL_DEFLECTION = createSound("effect"); + public static final SoundEvent SPELL_LIGHTNING = createSound("electricitya"); + public static final SoundEvent SPELL_LOOP_LIGHTNING = createSound("electricityb"); + public static final SoundEvent SPELL_LOOP_FIRE = createSound("flameray"); + public static final SoundEvent SPELL_FREEZE = createSound("freeze"); + public static final SoundEvent SPELL_LOOP_ICE = createSound("frostray"); + public static final SoundEvent SPELL_HEAL = createSound("heal"); + public static final SoundEvent SPELL_ICE = createSound("ice"); + public static final SoundEvent SPELL_CONJURATION_LARGE = createSound("largeaura"); + public static final SoundEvent SPELL_MAGIC = createSound("magic"); + public static final SoundEvent SPELL_LOOP_SPARKLE = createSound("sparkle"); + public static final SoundEvent SPELL_LOOP_WIND = createSound("wind"); + public static final SoundEvent SPELL_EARTHQUAKE = createSound("rumble"); + public static final SoundEvent SPELL_FORCE = createSound("force"); + + /** Trick borrowed from the Twilight Forest, makes things neater. */ + public static SoundEvent createSound(String name){ + // All the setRegistryName methods delegate to this one, it doesn't matter which you use. + return new SoundEvent(new ResourceLocation(Wizardry.MODID, name)).setRegistryName(name); + } + + @SubscribeEvent + public static void register(RegistryEvent.Register event){ + event.getRegistry().register(SPELL_SPARK); + event.getRegistry().register(SPELL_CONJURATION); + event.getRegistry().register(SPELL_SHOCKWAVE); + event.getRegistry().register(SPELL_LOOP_CRACKLE); + event.getRegistry().register(SPELL_SUMMONING); + event.getRegistry().register(SPELL_DEFLECTION); + event.getRegistry().register(SPELL_LIGHTNING); + event.getRegistry().register(SPELL_LOOP_LIGHTNING); + event.getRegistry().register(SPELL_LOOP_FIRE); + event.getRegistry().register(SPELL_FREEZE); + event.getRegistry().register(SPELL_LOOP_ICE); + event.getRegistry().register(SPELL_HEAL); + event.getRegistry().register(SPELL_ICE); + event.getRegistry().register(SPELL_CONJURATION_LARGE); + event.getRegistry().register(SPELL_MAGIC); + event.getRegistry().register(SPELL_LOOP_SPARKLE); + event.getRegistry().register(SPELL_LOOP_WIND); + event.getRegistry().register(SPELL_EARTHQUAKE); + event.getRegistry().register(SPELL_FORCE); + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryTabs.java b/src/main/java/electroblob/wizardry/registry/WizardryTabs.java new file mode 100644 index 00000000..6eeb9fc6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryTabs.java @@ -0,0 +1,175 @@ +package electroblob.wizardry.registry; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import com.google.common.base.Function; +import com.google.common.collect.Ordering; + +import electroblob.wizardry.item.ItemScroll; +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.spell.Spell; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** + * Class responsible for defining and storing all of wizardry's creative tabs. Also handles sorting of the items. + * @author Electroblob + * @since Wizardry 2.1 + */ +public final class WizardryTabs { + + private static Comparator itemSorter; + private static Comparator spellItemSorter; + + // Creative Tabs + public static final CreativeTabs WIZARDRY = new CreativeTabs("wizardry"){ + + @Override + @SideOnly(Side.CLIENT) + public Item getTabIconItem() { + return WizardryItems.wizard_handbook; + } + + @Override + @SideOnly(Side.CLIENT) + public void displayAllRelevantItems(List items) { + super.displayAllRelevantItems(items); + Collections.sort(items, itemSorter); + } + }; + public static final CreativeTabs SPELLS = new CreativeTabs("wizardryspells"){ + + @Override + @SideOnly(Side.CLIENT) + public Item getTabIconItem() { + return WizardryItems.spell_book; + } + + @Override + @SideOnly(Side.CLIENT) + public void displayAllRelevantItems(List items) { + super.displayAllRelevantItems(items); + Collections.sort(items, spellItemSorter); + } + + @Override + public boolean hasSearchBar() { + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public String getBackgroundImageName() { + return "item_search.png"; + } + }; + + /** Initialises the item sorters for the creative tabs. */ + public static void sort(){ + + List orderedItemList = Arrays.asList( + + Item.getItemFromBlock(WizardryBlocks.arcane_workbench), + Item.getItemFromBlock(WizardryBlocks.crystal_ore), + Item.getItemFromBlock(WizardryBlocks.crystal_block), + Item.getItemFromBlock(WizardryBlocks.crystal_flower), + Item.getItemFromBlock(WizardryBlocks.transportation_stone), + WizardryItems.magic_crystal, + WizardryItems.magic_wand, + WizardryItems.apprentice_wand, + WizardryItems.advanced_wand, + WizardryItems.master_wand, + WizardryItems.arcane_tome, + WizardryItems.wizard_handbook, + WizardryItems.basic_fire_wand, + WizardryItems.basic_ice_wand, + WizardryItems.basic_lightning_wand, + WizardryItems.basic_necromancy_wand, + WizardryItems.basic_earth_wand, + WizardryItems.basic_sorcery_wand, + WizardryItems.basic_healing_wand, + WizardryItems.smoke_bomb, + WizardryItems.firebomb, + WizardryItems.poison_bomb, + WizardryItems.blank_scroll, + WizardryItems.identification_scroll, + WizardryItems.mana_flask, + WizardryItems.storage_upgrade, + WizardryItems.siphon_upgrade, + WizardryItems.condenser_upgrade, + WizardryItems.range_upgrade, + WizardryItems.duration_upgrade, + WizardryItems.cooldown_upgrade, + WizardryItems.blast_upgrade, + WizardryItems.attunement_upgrade, + WizardryItems.magic_silk, + WizardryItems.armour_upgrade, + WizardryItems.wizard_hat, + WizardryItems.wizard_robe, + WizardryItems.wizard_leggings, + WizardryItems.wizard_boots, + WizardryItems.wizard_hat_fire, + WizardryItems.wizard_robe_fire, + WizardryItems.wizard_leggings_fire, + WizardryItems.wizard_boots_fire, + WizardryItems.wizard_hat_ice, + WizardryItems.wizard_robe_ice, + WizardryItems.wizard_leggings_ice, + WizardryItems.wizard_boots_ice, + WizardryItems.wizard_hat_lightning, + WizardryItems.wizard_robe_lightning, + WizardryItems.wizard_leggings_lightning, + WizardryItems.wizard_boots_lightning, + WizardryItems.wizard_hat_necromancy, + WizardryItems.wizard_robe_necromancy, + WizardryItems.wizard_leggings_necromancy, + WizardryItems.wizard_boots_necromancy, + WizardryItems.wizard_hat_earth, + WizardryItems.wizard_robe_earth, + WizardryItems.wizard_leggings_earth, + WizardryItems.wizard_boots_earth, + WizardryItems.wizard_hat_sorcery, + WizardryItems.wizard_robe_sorcery, + WizardryItems.wizard_leggings_sorcery, + WizardryItems.wizard_boots_sorcery, + WizardryItems.wizard_hat_healing, + WizardryItems.wizard_robe_healing, + WizardryItems.wizard_leggings_healing, + WizardryItems.wizard_boots_healing); + + itemSorter = Ordering.explicit(orderedItemList).onResultOf(new Function() { + @Override + public Item apply(ItemStack input) { + return input.getItem(); + } + }); + + spellItemSorter = new Comparator(){ + @Override + public int compare(ItemStack stack1, ItemStack stack2) { + + if((stack1.getItem() instanceof ItemSpellBook && stack2.getItem() instanceof ItemSpellBook) + || (stack1.getItem() instanceof ItemScroll && stack2.getItem() instanceof ItemScroll)){ + + Spell spell1 = Spell.get(stack1.getItemDamage()); + Spell spell2 = Spell.get(stack2.getItemDamage()); + + return spell1.compareTo(spell2); + + }else if(stack1.getItem() instanceof ItemScroll){ + return 1; + }else if(stack2.getItem() instanceof ItemScroll){ + return -1; + } + return 0; + } + }; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Agility.java b/src/main/java/electroblob/wizardry/spell/Agility.java new file mode 100644 index 00000000..db01f4a4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Agility.java @@ -0,0 +1,46 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Agility extends Spell { + + public Agility() { + super(Tier.APPRENTICE, 20, Element.SORCERY, "agility", SpellType.UTILITY, 40, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // 1.10 allows the particles to be completely hidden. + caster.addPotionEffect(new PotionEffect(MobEffects.SPEED, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); + caster.addPotionEffect(new PotionEffect(MobEffects.JUMP_BOOST, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); + + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + if(world.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Arc.java b/src/main/java/electroblob/wizardry/spell/Arc.java new file mode 100644 index 00000000..372911d4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Arc.java @@ -0,0 +1,105 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +// This spell was the 'guinea pig' for damage types, so to speak, so there's a bit of commentary on them here that may +// be useful for future reference. +public class Arc extends Spell { + + public Arc() { + super(Tier.BASIC, 5, Element.LIGHTNING, "arc", SpellType.ATTACK, 15, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 8*modifiers.get(WizardryItems.range_upgrade), 4.0f); + + if(rayTrace != null && rayTrace.entityHit != null && rayTrace.entityHit instanceof EntityLivingBase){ + + Entity target = rayTrace.entityHit; + + if(!world.isRemote){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(caster.posX, caster.posY + 1, caster.posZ, + target.posX, target.posY + target.height/2, target.posZ); + world.spawnEntityInWorld(arc); + }else{ + for(int i=0;i<8;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, target.posX + world.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + world.rand.nextFloat()*2 - 1, target.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, target.posX + world.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + world.rand.nextFloat()*2 - 1, target.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); + } + } + + // This is a lot neater than it was, thanks to the damage type system. + if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ + if(!world.isRemote) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 3.0f * modifiers.get(SpellModifiers.DAMAGE)); + } + + caster.swingArm(hand); + target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); + return true; + } + + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(caster.posX, caster.posY + 1, caster.posZ, + target.posX, target.posY + target.height/2, target.posZ); + world.spawnEntityInWorld(arc); + }else{ + for(int i=0;i<8;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, target.posX + world.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + world.rand.nextFloat()*2 - 1, target.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, target.posX + world.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + world.rand.nextFloat()*2 - 1, target.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); + } + } + + // What's great about the damage type system is that, because I don't need to know if the creature resisted + // the damage here, I can simply call this without having to check for immunities at all. + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 3.0f * modifiers.get(SpellModifiers.DAMAGE)); + + caster.swingArm(hand); + target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java new file mode 100644 index 00000000..30bd9cca --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java @@ -0,0 +1,95 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class ArcaneJammer extends Spell { + + public ArcaneJammer() { + super(Tier.ADVANCED, 30, Element.HEALING, "arcane_jammer", SpellType.ATTACK, 50, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase entity = (EntityLivingBase) rayTrace.entityHit; + if(entity instanceof EntityWizard) caster.addStat(WizardryAchievements.jam_wizard); + + if(!world.isRemote){ + entity.addPotionEffect(new PotionEffect(WizardryPotions.arcane_jammer, (int)(300*modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + } + if(world.isRemote){ + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.9f, 0.3f, 0.7f); + } + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_DEFLECTION, 0.7F, world.rand.nextFloat() * 0.4F + 0.8F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + if(!world.isRemote){ + target.addPotionEffect(new PotionEffect(WizardryPotions.arcane_jammer, (int)(300*modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + + if(world.isRemote){ + + double dx = (target.posX - caster.posX)/caster.getDistanceToEntity(target); + double dy = (target.posY - caster.posY)/caster.getDistanceToEntity(target); + double dz = (target.posZ - caster.posZ)/caster.getDistanceToEntity(target); + + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + + double x1 = caster.posX + dx*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + dz*i/2 + world.rand.nextFloat()/5 - 0.1f; + + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.9f, 0.3f, 0.7f); + } + } + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_DEFLECTION, 0.7F, world.rand.nextFloat() * 0.4F + 0.8F); + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/ArrowRain.java b/src/main/java/electroblob/wizardry/spell/ArrowRain.java new file mode 100644 index 00000000..b8c8f210 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ArrowRain.java @@ -0,0 +1,57 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityArrowRain; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class ArrowRain extends Spell { + + public ArrowRain() { + super(Tier.MASTER, 75, Element.SORCERY, "arrow_rain", SpellType.ATTACK, 300, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(20*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + if(!world.isRemote){ + double x = rayTrace.hitVec.xCoord; + double y = rayTrace.hitVec.yCoord; + double z = rayTrace.hitVec.zCoord; + // Moves the entity back towards the caster a bit, so the area of effect is better centred on the position. + // 3.0d is the distance to move the entity back towards the caster. + double dx = caster.posX - x; + double dz = caster.posZ - z; + double distRatio = 3.0d/Math.sqrt(dx*dx + dz*dz); + x += dx*distRatio; + z += dz*distRatio; + + EntityArrowRain arrowrain = new EntityArrowRain(world, x, y + 5, z, caster, (int)(120*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE)); + arrowrain.rotationYaw = caster.rotationYawHead; + world.spawnEntityInWorld(arrowrain); + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 1.0F, 1.0F); + return true; + } + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Banish.java b/src/main/java/electroblob/wizardry/spell/Banish.java new file mode 100644 index 00000000..8bf92bec --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Banish.java @@ -0,0 +1,159 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class Banish extends Spell { + + public Banish() { + super(Tier.APPRENTICE, 15, Element.NECROMANCY, "banish", SpellType.ATTACK, 40, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase) rayTrace.entityHit; + + double radius = (8 + world.rand.nextDouble()*8) * modifiers.get(WizardryItems.range_upgrade); + double angle = world.rand.nextDouble()*Math.PI*2; + + int x = MathHelper.floor_double(target.posX + Math.sin(angle)*radius); + int z = MathHelper.floor_double(target.posZ - Math.cos(angle)*radius); + int y = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(x, (int)caster.getEntityBoundingBox().minY, z), (int)radius); + + if(world.isRemote){ + for(int i=0;i<10;i++){ + double dx1 = target.posX; + double dy1 = target.getEntityBoundingBox().minY + target.height*world.rand.nextFloat(); + double dz1 = target.posZ; + world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); + } + } + + if(y > -1){ + + // This means stuff like snow layers is ignored, meaning when on snow-covered ground the caster does + // not teleport 1 block above the ground. + if(!world.getBlockState(new BlockPos(x, y, z)).getMaterial().blocksMovement()){ + y--; + } + + if(world.getBlockState(new BlockPos(x, y + 1, z)).getMaterial().blocksMovement() || world.getBlockState(new BlockPos(x, y + 2, z)).getMaterial().blocksMovement()){ + return false; + } + + if(!world.isRemote){ + target.setPositionAndUpdate(x + 0.5, y + 1, z + 0.5); + } + + target.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + } + } + + if(world.isRemote){ + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + + world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.2f, 0.0f, 0.2f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + caster.swingArm(hand); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + double radius = (8 + world.rand.nextDouble()*8) * modifiers.get(WizardryItems.range_upgrade); + double angle = world.rand.nextDouble()*Math.PI*2; + + int x = MathHelper.floor_double(target.posX + Math.sin(angle)*radius); + int z = MathHelper.floor_double(target.posZ - Math.cos(angle)*radius); + int y = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(x, (int)caster.getEntityBoundingBox().minY, z), (int)radius); + + if(world.isRemote){ + + double dx = (target.posX - caster.posX)/caster.getDistanceToEntity(target); + double dy = (target.posY - caster.posY)/caster.getDistanceToEntity(target); + double dz = (target.posZ - caster.posZ)/caster.getDistanceToEntity(target); + + for(int i=1; i<25; i+=2){ + + double x1 = caster.posX + dx*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + dz*i/2 + world.rand.nextFloat()/5 - 0.1f; + + world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.2f, 0.0f, 0.2f); + } + + for(int i=0;i<10;i++){ + double dx1 = target.posX; + double dy1 = target.getEntityBoundingBox().minY + target.height*world.rand.nextFloat(); + double dz1 = target.posZ; + world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); + } + } + + if(y > -1){ + + // This means stuff like snow layers is ignored, meaning when on snow-covered ground the caster does + // not teleport 1 block above the ground. + if(!world.getBlockState(new BlockPos(x, y, z)).getMaterial().blocksMovement()){ + y--; + } + + if(world.getBlockState(new BlockPos(x, y + 1, z)).getMaterial().blocksMovement() || world.getBlockState(new BlockPos(x, y + 2, z)).getMaterial().blocksMovement()){ + return false; + } + + if(!world.isRemote){ + target.setPositionAndUpdate(x + 0.5, y + 1, z + 0.5); + } + + target.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + } + } + + caster.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + caster.swingArm(hand); + return true; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/BlackHole.java b/src/main/java/electroblob/wizardry/spell/BlackHole.java new file mode 100644 index 00000000..3cfcd267 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/BlackHole.java @@ -0,0 +1,66 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityBlackHole; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class BlackHole extends Spell { + + public BlackHole() { + super(Tier.MASTER, 150, Element.SORCERY, "black_hole", SpellType.ATTACK, 400, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(10*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + // This demonstrates beautifully the elegance of BlockPos. In 1.7.10 this required a 50-line long switch + // statement and a flag variable; now it only needs a few lines. + BlockPos pos = new BlockPos(rayTrace.hitVec).offset(rayTrace.sideHit); + + if(world.isAirBlock(pos)){ + + if(!world.isRemote){ + world.spawnEntityInWorld(new EntityBlackHole(world, pos.getX()+0.5, pos.getY()-1+0.5, pos.getZ()+0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE))); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 2.0f, 0.7f); + return true; + } + + }else{ + int x = (int) (Math.floor(caster.posX) + caster.getLookVec().xCoord*8); + int y = (int) (Math.floor(caster.posY) + caster.eyeHeight + caster.getLookVec().yCoord*8); + int z = (int) (Math.floor(caster.posZ) + caster.getLookVec().zCoord*8); + if(!world.isRemote){ + world.spawnEntityInWorld(new EntityBlackHole(world, x, y, z, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE))); + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 2.0f, 0.7f); + return true; + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Blink.java b/src/main/java/electroblob/wizardry/spell/Blink.java new file mode 100644 index 00000000..3353d686 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Blink.java @@ -0,0 +1,134 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class Blink extends Spell { + + public Blink() { + super(Tier.APPRENTICE, 15, Element.SORCERY, "blink", SpellType.UTILITY, 25, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(25*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + // It's worth noting that on the client side, the cast() method only gets called if the server side + // cast method succeeded, so you need not check any conditions for spawning particles. + if(world.isRemote){ + for(int i=0;i<10;i++){ + double dx = caster.posX; + double dy = caster.getEntityBoundingBox().minY + 2*world.rand.nextFloat(); + double dz = caster.posZ; + // For portal particles, velocity is not velocity but the offset where they start, then drift to + // the actual position given. + world.spawnParticle(EnumParticleTypes.PORTAL, dx, dy, dz, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); + } + } + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = rayTrace.getBlockPos(); + + // Can't teleport onto the ceiling. + if(rayTrace.sideHit == EnumFacing.DOWN) return false; + + // This means stuff like snow layers is ignored, meaning when on snow-covered ground the player does + // not teleport 1 block above the ground. + if(rayTrace.sideHit == EnumFacing.UP && !world.getBlockState(pos).getMaterial().blocksMovement()){ + pos = pos.down(); + } + + pos = rayTrace.getBlockPos().offset(rayTrace.sideHit); + + // Prevents the player from teleporting into blocks and suffocating. + if(world.getBlockState(pos).getMaterial().blocksMovement() || world.getBlockState(pos.up()).getMaterial().blocksMovement()){ + return false; + } + + // Plays before and after so it is heard from both positions + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + + if(!world.isRemote) caster.setPositionAndUpdate(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + caster.swingArm(hand); + return true; + } + + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + double angle = Math.atan2(target.posZ - caster.posZ, target.posX - caster.posX) + world.rand.nextDouble()*Math.PI; + double radius = caster.getDistance(target.posX, target.getEntityBoundingBox().minY, target.posZ) + world.rand.nextDouble()*3.0d; + + int x = MathHelper.floor_double(target.posX + Math.sin(angle)*radius); + int z = MathHelper.floor_double(target.posZ - Math.cos(angle)*radius); + int y = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(caster), (int)radius); + + // It's worth noting that on the client side, the cast() method only gets called if the server side + // cast method succeeded, so you need not check any conditions for spawning particles. + + // For some reason, the wizard version spwans the particles where the wizard started + if(world.isRemote){ + for(int i=0;i<10;i++){ + double dx1 = caster.posX; + double dy1 = caster.getEntityBoundingBox().minY + caster.height*world.rand.nextFloat(); + double dz1 = caster.posZ; + world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); + } + } + + if(y > -1){ + + // This means stuff like snow layers is ignored, meaning when on snow-covered ground the caster does + // not teleport 1 block above the ground. + if(!world.getBlockState(new BlockPos(x, y, z)).getMaterial().blocksMovement()){ + y--; + } + + if(world.getBlockState(new BlockPos(x, y + 1, z)).getMaterial().blocksMovement() || world.getBlockState(new BlockPos(x, y + 2, z)).getMaterial().blocksMovement()){ + return false; + } + + // Plays before and after so it is heard from both positions + caster.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + + if(!world.isRemote){ + caster.setPositionAndUpdate(x + 0.5, y + 1, z + 0.5); + } + + caster.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + caster.swingArm(hand); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs() { + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Blizzard.java b/src/main/java/electroblob/wizardry/spell/Blizzard.java new file mode 100644 index 00000000..8f2066db --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Blizzard.java @@ -0,0 +1,75 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityBlizzard; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class Blizzard extends Spell { + + public Blizzard() { + super(Tier.ADVANCED, 40, Element.ICE, "blizzard", SpellType.ATTACK, 100, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(20*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + if(!world.isRemote){ + double x = rayTrace.hitVec.xCoord; + double y = rayTrace.hitVec.yCoord; + double z = rayTrace.hitVec.zCoord; + EntityBlizzard blizzard = new EntityBlizzard(world, x, y+0.5, z, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(blizzard); + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + double x = target.posX; + double y = target.posY; + double z = target.posZ; + EntityBlizzard blizzard = new EntityBlizzard(world, x, y+0.5, z, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(blizzard); + } + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, 1.0F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Bubble.java b/src/main/java/electroblob/wizardry/spell/Bubble.java new file mode 100644 index 00000000..c9c425d1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Bubble.java @@ -0,0 +1,110 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityBubble; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class Bubble extends Spell { + + public Bubble() { + super(Tier.APPRENTICE, 15, Element.EARTH, "bubble", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + EntityLivingBase entity = (EntityLivingBase) rayTrace.entityHit; + if(!world.isRemote){ + entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), 1.0f * modifiers.get(SpellModifiers.DAMAGE)); + // Deprecated in favour of entity riding method + //entity.addPotionEffect(new PotionEffect(Wizardry.bubblePotion, 200, 0)); + EntityBubble entitybubble = new EntityBubble(world, entity.posX, entity.posY, entity.posZ, caster, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), false, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(entitybubble); + entity.startRiding(entitybubble); + } + } + if(world.isRemote){ + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + + world.spawnParticle(EnumParticleTypes.WATER_SPLASH, x1, y1, z1, 0.0d, 0.0d, 0.0d); + Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_BUBBLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0); + } + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_GENERIC_SWIM, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), 1.0f * modifiers.get(SpellModifiers.DAMAGE)); + // Deprecated in favour of entity riding method + //entity.addPotionEffect(new PotionEffect(Wizardry.bubblePotion, 200, 0)); + EntityBubble entitybubble = new EntityBubble(world, target.posX, target.posY, target.posZ, caster, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), false, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(entitybubble); + target.startRiding(entitybubble); + + } + if(world.isRemote){ + + double dx = (target.posX - caster.posX)/caster.getDistanceToEntity(target); + double dy = (target.posY - caster.posY)/caster.getDistanceToEntity(target); + double dz = (target.posZ - caster.posZ)/caster.getDistanceToEntity(target); + + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + + double x1 = caster.posX + dx*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + dz*i/2 + world.rand.nextFloat()/5 - 0.1f; + + world.spawnParticle(EnumParticleTypes.WATER_SPLASH, x1, y1, z1, 0.0d, 0.0d, 0.0d); + Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_BUBBLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0); + } + } + caster.swingArm(hand); + caster.playSound(SoundEvents.ENTITY_GENERIC_SWIM, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + caster.playSound(WizardrySounds.SPELL_ICE, 0.5F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/ChainLightning.java b/src/main/java/electroblob/wizardry/spell/ChainLightning.java new file mode 100644 index 00000000..1b678ba5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ChainLightning.java @@ -0,0 +1,141 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class ChainLightning extends Spell { + + public ChainLightning() { + super(Tier.ADVANCED, 25, Element.LIGHTNING, "chain_lightning", SpellType.ATTACK, 50, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // First shot has range 10 (this is the only range affected by upgrades) and does 5 hearts of damage. + // Chains to up to 5 secondary targets within a range of 5 of the primary target, and then to up to 2 + // tertiary targets per secondary target within a range of 5 of that. Secondary targets are dealt 4 hearts + // of damage; tertiary targets are dealt 3 hearts of damage. + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade), 8.0f); + + // Anything can be attacked with the initial arc, because the player has control over where it goes. If they + // hit a minion or an ally, it's their problem! + if(rayTrace != null && rayTrace.entityHit != null && rayTrace.entityHit instanceof EntityLivingBase){ + + Entity target = rayTrace.entityHit; + + if(!world.isRemote){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(caster.posX, caster.posY + caster.height/2, caster.posZ, + target.posX, target.posY + target.height/2, target.posZ); + world.spawnEntityInWorld(arc); + }else{ + for(int i=0;i<8;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, target.posX + world.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + world.rand.nextFloat()*2 - 1, target.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, target.posX + world.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + world.rand.nextFloat()*2 - 1, target.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); + } + } + + target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); + + if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ + if(!world.isRemote) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 10.0f * modifiers.get(SpellModifiers.DAMAGE)); + } + + // Secondary chaining effect + double seekerRange = 5.0d; + + List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, target.posX, target.posY + target.height/2, target.posZ, world); + + for(int i=0; i tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height/2, secondaryTarget.posZ, world); + + for(int j=0;j targets = WizardryUtilities.getEntitiesWithinRadius(3.0d*modifiers.get(WizardryItems.blast_upgrade), (rayTrace.hitVec.xCoord+0.5), (rayTrace.hitVec.yCoord+0.5), (rayTrace.hitVec.zCoord+0.5), world); + for(int i=0;i targets = WizardryUtilities.getEntitiesWithinRadius(3.0d, target.posX, target.posY, target.posZ, world); + for(int i=0;i targets = WizardryUtilities.getEntitiesWithinRadius(5*modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world, EntityPlayer.class); + + for(EntityPlayer target : targets){ + if(WizardryUtilities.isPlayerAlly(caster, target) || target == caster){ + // Damage multiplier can only ever be 1 or 1.6 for master spells, so there's little point in actually calculating this. + target.addPotionEffect(new PotionEffect(WizardryPotions.font_of_mana, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE) > 1 ? 1 : 0)); + } + } + + if(world.isRemote){ + for(int i=0;i<100*modifiers.get(WizardryItems.blast_upgrade);i++){ + double radius = (1 + world.rand.nextDouble()*4)*modifiers.get(WizardryItems.blast_upgrade); + double angle = world.rand.nextDouble()*Math.PI*2; + float hue = world.rand.nextFloat()*0.4f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX + radius*Math.cos(angle), caster.getEntityBoundingBox().minY, caster.posZ + radius*Math.sin(angle), + 0, 0.03, 0, 50, 1, 1-hue, 0.6f+hue); + + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/FontOfVitality.java b/src/main/java/electroblob/wizardry/spell/FontOfVitality.java new file mode 100644 index 00000000..1056b526 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/FontOfVitality.java @@ -0,0 +1,53 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class FontOfVitality extends Spell { + + public FontOfVitality() { + super(Tier.MASTER, 75, Element.HEALING, "font_of_vitality", SpellType.DEFENCE, 300, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + caster.addPotionEffect(new PotionEffect(MobEffects.ABSORPTION, (int)(1200*modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); + caster.addPotionEffect(new PotionEffect(MobEffects.REGENERATION, (int)(300*modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 0.6f, 0.7f); + + x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 0.8f, 0.3f); + + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/ForceArrow.java b/src/main/java/electroblob/wizardry/spell/ForceArrow.java new file mode 100644 index 00000000..05cd68eb --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ForceArrow.java @@ -0,0 +1,65 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityForceArrow; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class ForceArrow extends Spell { + + public ForceArrow() { + super(Tier.APPRENTICE, 15, Element.SORCERY, "force_arrow", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityForceArrow forceArrow = new EntityForceArrow(world, caster, 1*modifiers.get(WizardryItems.range_upgrade), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(forceArrow); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_FORCE, 1.0f, 1.2f + world.rand.nextFloat()*0.2f); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityForceArrow forceArrow = new EntityForceArrow(world, caster, target, 1*modifiers.get(WizardryItems.range_upgrade), 2, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(forceArrow); + } + + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_FORCE, 1.0f, 1.2f + world.rand.nextFloat()*0.2f); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/ForceOrb.java b/src/main/java/electroblob/wizardry/spell/ForceOrb.java new file mode 100644 index 00000000..30ee52a4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ForceOrb.java @@ -0,0 +1,66 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityForceOrb; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class ForceOrb extends Spell { + + public ForceOrb() { + super(Tier.ADVANCED, 20, Element.SORCERY, "force_orb", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityForceOrb forceOrb = new EntityForceOrb(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + world.spawnEntityInWorld(forceOrb); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityForceOrb forceOrb = new EntityForceOrb(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + forceOrb.directTowards(target, 1.5f); + world.spawnEntityInWorld(forceOrb); + } + + caster.swingArm(hand); + caster.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Forcefield.java b/src/main/java/electroblob/wizardry/spell/Forcefield.java new file mode 100644 index 00000000..0b366bd1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Forcefield.java @@ -0,0 +1,69 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityForcefield; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Forcefield extends Spell { + + public Forcefield() { + super(Tier.ADVANCED, 45, Element.HEALING, "forcefield", SpellType.DEFENCE, 200, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.onGround){ + if(!world.isRemote){ + EntityForcefield forcefield = new EntityForcefield(world, caster.posX, caster.posY, caster.posZ, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(forcefield); + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION_LARGE, 1.0f, 1.0f); + return true; + } + + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + // Wizards can no longer cast forcefield when they are inside one + if(caster.onGround && world.getEntitiesWithinAABB(EntityForcefield.class, caster.getEntityBoundingBox()).isEmpty()){ + if(!world.isRemote){ + EntityForcefield forcefield = new EntityForcefield(world, caster.posX, caster.posY, caster.posZ, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(forcefield); + } + caster.playSound(WizardrySounds.SPELL_CONJURATION_LARGE, 1.0f, 1.0f); + return true; + } + + return false; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/ForestsCurse.java b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java new file mode 100644 index 00000000..68612acd --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java @@ -0,0 +1,64 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class ForestsCurse extends Spell { + + public ForestsCurse() { + super(Tier.MASTER, 75, Element.EARTH, "forests_curse", SpellType.ATTACK, 200, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + List targets = WizardryUtilities.getEntitiesWithinRadius(5.0d*modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + + for(EntityLivingBase target : targets){ + if(WizardryUtilities.isValidTarget(caster, target) && !MagicDamage.isEntityImmune(DamageType.POISON, target)){ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), 4.0f * modifiers.get(SpellModifiers.DAMAGE)); + target.addPotionEffect(new PotionEffect(MobEffects.POISON, (int)(140*modifiers.get(WizardryItems.duration_upgrade)), 2)); + target.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, (int)(140*modifiers.get(WizardryItems.duration_upgrade)), 2)); + target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, (int)(140*modifiers.get(WizardryItems.duration_upgrade)), 2)); + } + } + + if(world.isRemote){ + for(int i=0;i<50*modifiers.get(WizardryItems.blast_upgrade);i++){ + double radius = (1 + world.rand.nextDouble()*4)*modifiers.get(WizardryItems.blast_upgrade); + double angle = world.rand.nextDouble()*Math.PI*2; + float brightness = world.rand.nextFloat()/4; + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, caster.posX + radius*Math.cos(angle), WizardryUtilities.getPlayerEyesPos(caster) + 0.5, caster.posZ + radius*Math.sin(angle), + 0, -0.2, 0, 0, 0.05f+brightness, 0.2f+brightness, 0.0f); + brightness = world.rand.nextFloat()/4; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX + radius*Math.cos(angle), WizardryUtilities.getPlayerEyesPos(caster) + 0.5, caster.posZ + radius*Math.sin(angle), + 0, -0.05, 0, 50, 0.1f+brightness, 0.2f+brightness, 0.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, world, caster.posX + radius*Math.cos(angle), WizardryUtilities.getPlayerEyesPos(caster) + 0.5, caster.posZ + radius*Math.sin(angle), 0, -0.01, 0, 40 + world.rand.nextInt(12)); + + } + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Freeze.java b/src/main/java/electroblob/wizardry/spell/Freeze.java new file mode 100644 index 00000000..01b289cc --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Freeze.java @@ -0,0 +1,158 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityBlazeMinion; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntityBlaze; +import net.minecraft.entity.monster.EntityMagmaCube; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class Freeze extends Spell { + + public Freeze() { + super(Tier.BASIC, 5, Element.ICE, "freeze", SpellType.ATTACK, 10, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // Entity ray trace is done first because block ray trace passes through entities; if it was the other + // way round, entities would only be hit when there were no blocks in range behind them. + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase) rayTrace.entityHit; + + if(target instanceof EntityBlaze || target instanceof EntityMagmaCube || target instanceof EntityBlazeMinion){ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), 3.0f * modifiers.get(SpellModifiers.DAMAGE)); + } + + if(MagicDamage.isEntityImmune(DamageType.FROST, target)){ + if(!world.isRemote) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + target.addPotionEffect(new PotionEffect(WizardryPotions.frost, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), 1)); + } + + if(target.isBurning()){ + target.extinguish(); + } + + if(world.isRemote){ + double dx = target.posX - caster.posX; + double dy = (target.getEntityBoundingBox().minY + target.height/2) - WizardryUtilities.getPlayerEyesPos(caster); + double dz = target.posZ - caster.posZ; + for(int i=1;i<5;i++){ + float brightness = 0.5f + (world.rand.nextFloat()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, -0.02, 0, 40 + world.rand.nextInt(10)); + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.2F); + return true; + + }else{ + rayTrace = WizardryUtilities.rayTrace(10*modifiers.get(WizardryItems.range_upgrade), world, caster, true); + // Gets block the player is looking at and sets to ice or covers with snow as necessary + // Note how the block is set on the server side only (kinda obvious really) but the particles are + // spawned on the client side only. + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = rayTrace.getBlockPos(); + + if(world.getBlockState(pos).getBlock() == Blocks.WATER && !world.isRemote){ + world.setBlockState(pos, Blocks.ICE.getDefaultState()); + }else if(world.getBlockState(pos).getBlock() == Blocks.LAVA && !world.isRemote){ + world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState()); + }else if(world.getBlockState(pos).getBlock() == Blocks.FLOWING_LAVA && !world.isRemote){ + world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState()); + }else if(rayTrace.sideHit == EnumFacing.UP && !world.isRemote && world.isSideSolid(pos, EnumFacing.UP) && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + world.setBlockState(pos.up(), Blocks.SNOW_LAYER.getDefaultState()); + } + + if(world.isRemote){ + + double dx = pos.getX() + 0.5 - caster.posX; + double dy = pos.getY() + 0.5 - WizardryUtilities.getPlayerEyesPos(caster); + double dz = pos.getZ() + 0.5 - caster.posZ; + + for(int i=1;i<5;i++){ + float brightness = 0.5f + (world.rand.nextFloat()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0.0d, 0.0d, 0.0d, 20 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0, 20 + world.rand.nextInt(8), 1.0f, 1.0f, 1.0f); + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.2F); + return true; + } + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(target instanceof EntityBlaze || target instanceof EntityMagmaCube || target instanceof EntityBlazeMinion){ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), 3.0f * modifiers.get(SpellModifiers.DAMAGE)); + } + + if(!world.isRemote && !MagicDamage.isEntityImmune(DamageType.FROST, target)){ + target.addPotionEffect(new PotionEffect(WizardryPotions.frost, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), 1)); + } + + if(target.isBurning()){ + target.extinguish(); + } + + if(world.isRemote){ + double dx = target.posX - caster.posX; + double dy = (target.getEntityBoundingBox().minY + target.height/2) - (caster.posY + caster.getEyeHeight()); + double dz = target.posZ - caster.posZ; + for(int i=1;i<5;i++){ + float brightness = 0.5f + (world.rand.nextFloat()/2); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, caster.posY + caster.getEyeHeight() + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, caster.posY + caster.getEyeHeight() + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, -0.02, 0, 40 + world.rand.nextInt(10)); + } + } + + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.2F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java new file mode 100644 index 00000000..911be3f4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java @@ -0,0 +1,71 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryEnchantments; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemBow; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemSword; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class FreezingWeapon extends Spell { + + /** The NBT tag name for storing the level of frost enchantment in the arrow's tag compound. (There's nothing + * stopping you from using this elsewhere to shoot freezing arrows if you want to...) */ + public static final String FREEZING_ARROW_NBT_KEY = "frostLevel"; + + public FreezingWeapon() { + super(Tier.ADVANCED, 35, Element.ICE, "freezing_weapon", SpellType.UTILITY, 70, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // Won't work if the weapon already has the enchantment + if(WizardData.get(caster) != null && WizardData.get(caster).getImbuementDuration(WizardryEnchantments.freezing_weapon) <= 0){ + + for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(caster)){ + + if(stack != null){ + + if((stack.getItem() instanceof ItemSword || stack.getItem() instanceof ItemBow) && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.freezing_weapon)){ + // The enchantment level as determined by the damage multiplier. The + 0.5f is so that + // weird float processing doesn't incorrectly round it down. + stack.addEnchantment(WizardryEnchantments.freezing_weapon, modifiers.get(SpellModifiers.DAMAGE) == 1.0f ? 1 : (int)((modifiers.get(SpellModifiers.DAMAGE) - 1.0f)/Constants.DAMAGE_INCREASE_PER_TIER + 0.5f)); + + WizardData.get(caster).setImbuementDuration(WizardryEnchantments.freezing_weapon, (int)(900*modifiers.get(WizardryItems.duration_upgrade))); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.9f, 0.7f, 1.0f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + return true; + + } + } + } + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/FrostAxe.java b/src/main/java/electroblob/wizardry/spell/FrostAxe.java new file mode 100644 index 00000000..1d48473e --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/FrostAxe.java @@ -0,0 +1,50 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.item.IConjuredItem; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class FrostAxe extends Spell { + + public FrostAxe() { + super(Tier.ADVANCED, 45, Element.ICE, "frost_axe", SpellType.UTILITY, 50, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + ItemStack frostaxe = new ItemStack(WizardryItems.frost_axe); + + IConjuredItem.setDurationMultiplier(frostaxe, modifiers.get(WizardryItems.duration_upgrade)); + + if(!WizardryUtilities.doesPlayerHaveItem(caster, WizardryItems.frost_axe) && ConjureBow.conjureItemInInventory(caster, frostaxe)){ + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, x1, y1, z1, 0, -0.02d, 0, 40 + world.rand.nextInt(10)); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0f, 1.0f); + return true; + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/FrostRay.java b/src/main/java/electroblob/wizardry/spell/FrostRay.java new file mode 100644 index 00000000..10897960 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/FrostRay.java @@ -0,0 +1,132 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntityBlaze; +import net.minecraft.entity.monster.EntityMagmaCube; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class FrostRay extends Spell { + + public FrostRay() { + super(Tier.APPRENTICE, 5, Element.ICE, "frost_ray", SpellType.ATTACK, 0, EnumAction.NONE, true); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase) rayTrace.entityHit; + + if(target.isBurning()){ + target.extinguish(); + } + + if(MagicDamage.isEntityImmune(DamageType.FROST, target)){ + if(!world.isRemote && ticksInUse == 1) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + // For frost ray the entity can move slightly, unlike freeze. + target.addPotionEffect(new PotionEffect(WizardryPotions.frost, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), 0)); + + float baseDamage = target instanceof EntityBlaze || target instanceof EntityMagmaCube ? 6.0f : 3.0f; + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), baseDamage * modifiers.get(SpellModifiers.DAMAGE)); + + } + } + + if(world.isRemote){ + for(int i=0; i<20; i++){ + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, look.xCoord*modifiers.get(WizardryItems.range_upgrade), look.yCoord*modifiers.get(WizardryItems.range_upgrade), look.zCoord*modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 0.4f, 0.6f, 1.0f); + + x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, look.xCoord*modifiers.get(WizardryItems.range_upgrade), look.yCoord*modifiers.get(WizardryItems.range_upgrade), look.zCoord*modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 1.0f, 1.0f, 1.0f); + } + } + + if(ticksInUse % 12 == 0){ + if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5F, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_ICE, 0.5F, 1.0f); + } + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers) { + + if(target != null){ + + Vec3d vec = new Vec3d(target.posX - caster.posX, target.posY - caster.posY, target.posZ - caster.posZ).normalize(); + + if(target.isBurning()){ + target.extinguish(); + } + + if(!MagicDamage.isEntityImmune(DamageType.FROST, target)){ + // For frost ray the entity can move slightly, unlike freeze. + target.addPotionEffect(new PotionEffect(WizardryPotions.frost, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), 0)); + + float baseDamage = target instanceof EntityBlaze || target instanceof EntityMagmaCube ? 6.0f : 3.0f; + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), baseDamage * modifiers.get(SpellModifiers.DAMAGE)); + + } + + if(world.isRemote){ + for(int i=0; i<20; i++){ + double x1 = caster.posX + vec.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + vec.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, vec.xCoord*modifiers.get(WizardryItems.range_upgrade), vec.yCoord*modifiers.get(WizardryItems.range_upgrade), vec.zCoord*modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 0.4f, 0.6f, 1.0f); + + x1 = caster.posX + vec.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + z1 = caster.posZ + vec.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, vec.xCoord*modifiers.get(WizardryItems.range_upgrade), vec.yCoord*modifiers.get(WizardryItems.range_upgrade), vec.zCoord*modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 1.0f, 1.0f, 1.0f); + } + } + + if(ticksInUse % 12 == 0){ + if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_ICE, 0.5F, 1.0f); + caster.playSound(WizardrySounds.SPELL_LOOP_ICE, 0.5F, 1.0f); + } + + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs() { + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/FrostSigil.java b/src/main/java/electroblob/wizardry/spell/FrostSigil.java new file mode 100644 index 00000000..5423e9e8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/FrostSigil.java @@ -0,0 +1,50 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityFrostSigil; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class FrostSigil extends Spell { + + public FrostSigil() { + super(Tier.APPRENTICE, 10, Element.ICE, "frost_sigil", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(10*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK && rayTrace.sideHit == EnumFacing.UP){ + if(!world.isRemote){ + double x = rayTrace.hitVec.xCoord; + double y = rayTrace.hitVec.yCoord; + double z = rayTrace.hitVec.zCoord; + EntityFrostSigil frostsigil = new EntityFrostSigil(world, x, y, z, caster, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(frostsigil); + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); + return true; + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Glide.java b/src/main/java/electroblob/wizardry/spell/Glide.java new file mode 100644 index 00000000..45fa88d7 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Glide.java @@ -0,0 +1,46 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Glide extends Spell { + + public Glide() { + super(Tier.ADVANCED, 5, Element.EARTH, "glide", SpellType.UTILITY, 0, EnumAction.NONE, true); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.motionY < -0.1 && !caster.isInWater()){ + caster.motionY = -0.1; + if(Math.abs(caster.motionX) < 0.4 && Math.abs(caster.motionZ) < 0.4){ + caster.addVelocity(caster.getLookVec().xCoord/8, 0, caster.getLookVec().zCoord/8); + //entityplayer.moveEntity(entityplayer.motionX*10, 0, entityplayer.motionZ*10); + } + caster.fallDistance = 0.0f; + } + + if(world.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX - 0.25d + world.rand.nextDouble()/2, WizardryUtilities.getPlayerEyesPos(caster) - 1.5f + world.rand.nextDouble(), caster.posZ - 0.25d + world.rand.nextDouble()/2, 0, -0.1F, 0, 15, 1.0f, 1.0f, 1.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, world, caster.posX - 0.25d + world.rand.nextDouble()/2, WizardryUtilities.getPlayerEyesPos(caster) - 1.5f + world.rand.nextDouble(), caster.posZ - 0.25d + world.rand.nextDouble()/2, 0, -0.03, 0, 20); + } + + if(ticksInUse % 24 == 0){ + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ITEM_ELYTRA_FLYING, 0.5F, 1.0f); + } + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/GreaterFireball.java b/src/main/java/electroblob/wizardry/spell/GreaterFireball.java new file mode 100644 index 00000000..93414391 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/GreaterFireball.java @@ -0,0 +1,86 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityLargeFireball; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class GreaterFireball extends Spell { + + public GreaterFireball() { + super(Tier.ADVANCED, 20, Element.FIRE, "greater_fireball", SpellType.ATTACK, 30, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + if(!world.isRemote){ + EntityLargeFireball fireball = new EntityLargeFireball(world, caster, 1, 1, 1); + fireball.setPosition( + caster.posX + look.xCoord, + caster.posY + look.yCoord + 1.3, + caster.posZ + look.zCoord); + fireball.accelerationX = look.xCoord * 0.1; + fireball.accelerationY = look.yCoord * 0.1; + fireball.accelerationZ = look.zCoord * 0.1; + world.spawnEntityInWorld(fireball); + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + caster.swingArm(hand); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + + EntityLargeFireball fireball = new EntityLargeFireball(world, caster, 1, 1, 1); + + double dx = target.posX - caster.posX; + double dy = target.getEntityBoundingBox().minY + (double)(target.height / 2.0F) - (caster.posY + (double)(caster.height / 2.0F)); + double dz = target.posZ - caster.posZ; + + fireball.accelerationX = dx/caster.getDistanceToEntity(target) * 0.1; + fireball.accelerationY = dy/caster.getDistanceToEntity(target) * 0.1; + fireball.accelerationZ = dz/caster.getDistanceToEntity(target) * 0.1; + + fireball.setPosition(caster.posX, caster.posY + caster.getEyeHeight(), caster.posZ); + + world.spawnEntityInWorld(fireball); + } + + caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + caster.swingArm(hand); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/GreaterHeal.java b/src/main/java/electroblob/wizardry/spell/GreaterHeal.java new file mode 100644 index 00000000..df20a7dc --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/GreaterHeal.java @@ -0,0 +1,63 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class GreaterHeal extends Spell { + + public GreaterHeal() { + super(Tier.ADVANCED, 15, Element.HEALING, "greater_heal", SpellType.DEFENCE, 40, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.shouldHeal()){ + caster.heal((int)(8*modifiers.get(SpellModifiers.DAMAGE))); + if(world.isRemote){ + for(int i=0; i<10; i++){ + double dx = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double dy = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double dz = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + } + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(caster.getHealth() < caster.getMaxHealth()){ + caster.heal((int)(8*modifiers.get(SpellModifiers.DAMAGE))); + if(world.isRemote){ + for(int i=0; i<10; i++){ + double dx = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double dy = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); + double dz = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + } + } + caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/GroupHeal.java b/src/main/java/electroblob/wizardry/spell/GroupHeal.java new file mode 100644 index 00000000..939ef998 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/GroupHeal.java @@ -0,0 +1,89 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.ISummonedCreature; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class GroupHeal extends Spell { + + public GroupHeal() { + super(Tier.ADVANCED, 35, Element.HEALING, "group_heal", SpellType.DEFENCE, 150, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + boolean flag = false; + + List targets = WizardryUtilities.getEntitiesWithinRadius(5*modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + + for(EntityLivingBase target : targets){ + + if(target instanceof EntityPlayer){ + + if(WizardryUtilities.isPlayerAlly(caster, (EntityPlayer)target) || target == caster){ + + if(((EntityPlayer)target).shouldHeal()){ + + target.heal((int)(6*modifiers.get(SpellModifiers.DAMAGE))); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double d0 = (double)((float)target.posX + world.rand.nextFloat()*2 - 1.0F); + double d1 = (double)((float)WizardryUtilities.getPlayerEyesPos((EntityPlayer)target) - 0.5F + world.rand.nextFloat()); + double d2 = (double)((float)target.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + flag = true; + } + } + + // Now also works on summoned creatures + }else if(target instanceof ISummonedCreature){ + + EntityLivingBase summoner = ((ISummonedCreature)target).getCaster(); + + if(summoner == caster || (summoner instanceof EntityPlayer && WizardryUtilities.isPlayerAlly(caster, (EntityPlayer)summoner))){ + + if(target.getHealth() < target.getMaxHealth()){ + + target.heal((int)(6*modifiers.get(SpellModifiers.DAMAGE))); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double d0 = (double)((float)target.posX + world.rand.nextFloat()*2 - 1.0F); + double d1 = (double)((float)WizardryUtilities.getPlayerEyesPos((EntityPlayer)target) - 0.5F + world.rand.nextFloat()); + double d2 = (double)((float)target.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + flag = true; + } + } + } + } + + return flag; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/GrowthAura.java b/src/main/java/electroblob/wizardry/spell/GrowthAura.java new file mode 100644 index 00000000..7e52855e --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/GrowthAura.java @@ -0,0 +1,75 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.IGrowable; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemDye; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class GrowthAura extends Spell { + + public GrowthAura() { + super(Tier.APPRENTICE, 20, Element.EARTH, "growth_aura", SpellType.UTILITY, 50, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + boolean flag = false; + + for(int i=-2; i<1; i++){ + + for(int j=-1; j<2; j++){ + + int x = (int)caster.posX + i; + int y = WizardryUtilities.getNearestFloorLevelC(world, new BlockPos(caster.posX + i, caster.posY, caster.posZ + j), 2) - 1; + int z = (int)caster.posZ + j; + + BlockPos pos = new BlockPos(x, y, z); + + if(y > -1 && caster.getDistance(x, y, z) <= 2){ + + IBlockState state = world.getBlockState(pos); + + if(state.getBlock() instanceof IGrowable){ + + IGrowable igrowable = (IGrowable)state.getBlock(); + + if(igrowable.canGrow(world, pos, state, world.isRemote)){ + + if(!world.isRemote){ + if(igrowable.canUseBonemeal(world, world.rand, pos, state)){ + igrowable.grow(world, world.rand, pos, state); + } + }else{ + // Yes, it's meant to be 0, and it automatically changes it to 15. + ItemDye.spawnBonemealParticles(world, pos, 0); + } + + flag = true; + } + } + } + } + } + + if(flag) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return flag; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Hailstorm.java b/src/main/java/electroblob/wizardry/spell/Hailstorm.java new file mode 100644 index 00000000..7dc8ee73 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Hailstorm.java @@ -0,0 +1,57 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityHailstorm; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class Hailstorm extends Spell { + + public Hailstorm() { + super(Tier.MASTER, 75, Element.ICE, "hailstorm", SpellType.ATTACK, 300, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(20*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + if(!world.isRemote){ + double x = rayTrace.hitVec.xCoord; + double y = rayTrace.hitVec.yCoord; + double z = rayTrace.hitVec.zCoord; + // Moves the entity back towards the caster a bit, so the area of effect is better centred on the position. + // 3.0d is the distance to move the entity back towards the caster. + double dx = caster.posX - x; + double dz = caster.posZ - z; + double distRatio = 3.0d/Math.sqrt(dx*dx + dz*dz); + x += dx*distRatio; + z += dz*distRatio; + + EntityHailstorm hailstorm = new EntityHailstorm(world, x, y + 5, z, caster, (int)(120*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE)); + hailstorm.rotationYaw = caster.rotationYawHead; + world.spawnEntityInWorld(hailstorm); + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); + return true; + } + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Heal.java b/src/main/java/electroblob/wizardry/spell/Heal.java new file mode 100644 index 00000000..8a7044e3 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Heal.java @@ -0,0 +1,67 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Heal extends Spell { + + public Heal() { + super(Tier.BASIC, 5, Element.HEALING, "heal", SpellType.DEFENCE, 20, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.shouldHeal()){ + + caster.heal((int)(4*modifiers.get(SpellModifiers.DAMAGE))); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double d0 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + // Apparently the client side spawns the particles 1 block higher than it should... hence the - 0.5F. + double d1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double d2 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(caster.getHealth() < caster.getMaxHealth()){ + caster.heal((int)(4*modifiers.get(SpellModifiers.DAMAGE))); + if(world.isRemote){ + for(int i=0; i<10; i++){ + double dx = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double dy = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); + double dz = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + } + } + caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/HealAlly.java b/src/main/java/electroblob/wizardry/spell/HealAlly.java new file mode 100644 index 00000000..3ab49587 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/HealAlly.java @@ -0,0 +1,54 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class HealAlly extends Spell { + + public HealAlly() { + super(Tier.APPRENTICE, 10, Element.HEALING, "heal_ally", SpellType.DEFENCE, 20, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade), 8.0f); + + if(rayTrace != null && rayTrace.entityHit != null && rayTrace.entityHit instanceof EntityLivingBase){ + EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; + if(target.getHealth() < target.getMaxHealth()){ + target.heal((int)(5*modifiers.get(SpellModifiers.DAMAGE))); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double d0 = (double)((float)target.posX + world.rand.nextFloat()*2 - 1.0F); + // Apparently the client side spawns the particles 1 block higher than it should... hence the - 0.5F. + double d1 = (double)((float)target.getEntityBoundingBox().minY + target.height - 0.5f + world.rand.nextFloat()); + double d2 = (double)((float)target.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + } + } + + caster.swingArm(hand); + target.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/HealingAura.java b/src/main/java/electroblob/wizardry/spell/HealingAura.java new file mode 100644 index 00000000..bcd6ea61 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/HealingAura.java @@ -0,0 +1,62 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityHealAura; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class HealingAura extends Spell { + + public HealingAura() { + super(Tier.ADVANCED, 35, Element.HEALING, "healing_aura", SpellType.DEFENCE, 150, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.onGround){ + if(!world.isRemote){ + EntityHealAura healaura = new EntityHealAura(world, caster.posX, caster.posY, caster.posZ, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(healaura); + } + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers) { + + if(target != null){ + if(caster.onGround && world.getEntitiesWithinAABB(EntityHealAura.class, caster.getEntityBoundingBox()).isEmpty()){ + if(!world.isRemote){ + EntityHealAura healaura = new EntityHealAura(world, caster.posX, caster.posY, caster.posZ, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(healaura); + } + return true; + } + return false; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs() { + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/HomingSpark.java b/src/main/java/electroblob/wizardry/spell/HomingSpark.java new file mode 100644 index 00000000..65ed1d64 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/HomingSpark.java @@ -0,0 +1,63 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntitySpark; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class HomingSpark extends Spell { + + public HomingSpark() { + super(Tier.APPRENTICE, 10, Element.LIGHTNING, "homing_spark", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntitySpark spark = new EntitySpark(world, caster, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(spark); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + } + caster.swingArm(hand); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntitySpark spark = new EntitySpark(world, caster, modifiers.get(SpellModifiers.DAMAGE)); + spark.directTowards(target, 0.5f); + world.spawnEntityInWorld(spark); + caster.playSound(WizardrySounds.SPELL_CONJURATION, 1.0F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + } + caster.swingArm(hand); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/IceAge.java b/src/main/java/electroblob/wizardry/spell/IceAge.java new file mode 100644 index 00000000..8f57ee59 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/IceAge.java @@ -0,0 +1,147 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.tileentity.TileEntityStatue; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntityBlaze; +import net.minecraft.entity.monster.EntityMagmaCube; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class IceAge extends Spell { + + private static final int baseDuration = 1200; + + public IceAge() { + super(Tier.MASTER, 70, Element.ICE, "ice_age", SpellType.ATTACK, 250, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + List targets = WizardryUtilities.getEntitiesWithinRadius(7*modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + + for(EntityLivingBase target : targets){ + if(WizardryUtilities.isValidTarget(caster, target)){ + if(!world.isRemote){ + if(target instanceof EntityBlaze || target instanceof EntityMagmaCube){ + // These have been removed for the time being because they cause the entity to sink into the floor when it breaks out. + //target.attackEntityFrom(WizardryUtilities.causePlayerMagicDamage(entityplayer), 8.0f * modifiers.get(SpellModifiers.DAMAGE)); + }else{ + //target.attackEntityFrom(WizardryUtilities.causePlayerMagicDamage(entityplayer), 4.0f * modifiers.get(SpellModifiers.DAMAGE)); + } + if(target.isBurning()){ + target.extinguish(); + } + + if(target instanceof EntityBlaze) caster.addStat(WizardryAchievements.freeze_blaze, 1); + + if(target instanceof EntityLiving){ + + // Stops the entity looking red while frozen and the resulting z-fighting + target.hurtTime = 0; + + BlockPos pos = new BlockPos(target); + + // Short mobs such as spiders and pigs + if((target.height < 1.2 || target.isChild()) && WizardryUtilities.canBlockBeReplaced(world, pos)){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart((EntityLiving) target, 1, 1); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime((int)(baseDuration*modifiers.get(WizardryItems.duration_upgrade))); + } + target.setDead(); + target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + } + // Normal sized mobs like zombies and skeletons + else if(target.height < 2.5 && WizardryUtilities.canBlockBeReplaced(world, pos) && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart((EntityLiving) target, 1, 2); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime((int)(baseDuration*modifiers.get(WizardryItems.duration_upgrade))); + } + + world.setBlockState(pos.up(), WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart((EntityLiving) target, 2, 2); + } + target.setDead(); + target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + } + // Tall mobs like endermen + else if(WizardryUtilities.canBlockBeReplaced(world, pos) && WizardryUtilities.canBlockBeReplaced(world, pos.up()) && WizardryUtilities.canBlockBeReplaced(world, pos.up(2))){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart((EntityLiving) target, 1, 3); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime((int)(baseDuration*modifiers.get(WizardryItems.duration_upgrade))); + } + + world.setBlockState(pos.up(), WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart((EntityLiving) target, 2, 3); + } + + world.setBlockState(pos.up(2), WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart((EntityLiving) target, 3, 3); + } + target.setDead(); + target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + } + } + } + } + } + if(!world.isRemote){ + for(int i=-7; i<8; i++){ + for(int j=-7; j<8; j++){ + + BlockPos pos = new BlockPos(caster).add(i, 0, j); + + int y = WizardryUtilities.getNearestFloorLevelB(world, new BlockPos(pos), 7); + + pos = new BlockPos(pos.getX(), y, pos.getZ()); + + double dist = caster.getDistance((int)caster.posX + i, y, (int)caster.posZ + j); + + // Randomised with weighting so that the nearer the block the more likely it is to be snowed. + if(y != -1 && world.rand.nextInt((int)dist*2 + 1) < 7 && dist < 8){ + if(world.getBlockState(pos.down()) == Blocks.WATER.getDefaultState()){ + world.setBlockState(pos.down(), Blocks.ICE.getDefaultState()); + }else if(world.getBlockState(pos.down()) == Blocks.LAVA.getDefaultState()){ + world.setBlockState(pos.down(), Blocks.OBSIDIAN.getDefaultState()); + }else if(world.getBlockState(pos.down()) == Blocks.FLOWING_LAVA.getDefaultState()){ + world.setBlockState(pos.down(), Blocks.COBBLESTONE.getDefaultState()); + }else{ + world.setBlockState(pos, Blocks.SNOW_LAYER.getDefaultState()); + } + } + } + } + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.7F, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_WIND, 1.0F, 1.0f); + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/IceCharge.java b/src/main/java/electroblob/wizardry/spell/IceCharge.java new file mode 100644 index 00000000..c419b374 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/IceCharge.java @@ -0,0 +1,66 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityIceCharge; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class IceCharge extends Spell { + + public IceCharge() { + super(Tier.ADVANCED, 20, Element.ICE, "ice_charge", SpellType.ATTACK, 30, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityIceCharge icecharge = new EntityIceCharge(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + world.spawnEntityInWorld(icecharge); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityIceCharge icecharge = new EntityIceCharge(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + icecharge.directTowards(target, 1.5f); + world.spawnEntityInWorld(icecharge); + } + + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/IceLance.java b/src/main/java/electroblob/wizardry/spell/IceLance.java new file mode 100644 index 00000000..dcef7c07 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/IceLance.java @@ -0,0 +1,63 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityIceLance; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class IceLance extends Spell { + + public IceLance() { + super(Tier.ADVANCED, 20, Element.ICE, "ice_lance", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityIceLance iceLance = new EntityIceLance(world, caster, 2*modifiers.get(WizardryItems.range_upgrade), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(iceLance); + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityIceLance iceLance = new EntityIceLance(world, caster, target, 2*modifiers.get(WizardryItems.range_upgrade), 4, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(iceLance); + } + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/IceShard.java b/src/main/java/electroblob/wizardry/spell/IceShard.java new file mode 100644 index 00000000..ddda2a1d --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/IceShard.java @@ -0,0 +1,63 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityIceShard; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class IceShard extends Spell { + + public IceShard() { + super(Tier.APPRENTICE, 10, Element.ICE, "ice_shard", SpellType.ATTACK, 10, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityIceShard iceShard = new EntityIceShard(world, caster, 2*modifiers.get(WizardryItems.range_upgrade), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(iceShard); + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityIceShard iceShard = new EntityIceShard(world, caster, target, 2*modifiers.get(WizardryItems.range_upgrade), 4, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(iceShard); + } + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/IceShroud.java b/src/main/java/electroblob/wizardry/spell/IceShroud.java new file mode 100644 index 00000000..85843dc1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/IceShroud.java @@ -0,0 +1,67 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class IceShroud extends Spell { + + public IceShroud() { + super(Tier.ADVANCED, 40, Element.ICE, "ice_shroud", SpellType.DEFENCE, 250, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // Cannot be cast when it has already been cast + if(!caster.isPotionActive(WizardryPotions.ice_shroud)){ + if(!world.isRemote){ + caster.addPotionEffect(new PotionEffect(WizardryPotions.ice_shroud, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers) { + + if(target != null){ + // Cannot be cast when it has already been cast + if(!caster.isPotionActive(WizardryPotions.ice_shroud)){ + if(!world.isRemote){ + caster.addPotionEffect(new PotionEffect(WizardryPotions.ice_shroud, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); + return true; + } + return false; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs() { + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/IceSpikes.java b/src/main/java/electroblob/wizardry/spell/IceSpikes.java new file mode 100644 index 00000000..95325e0f --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/IceSpikes.java @@ -0,0 +1,108 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityIceSpike; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class IceSpikes extends Spell { + + public IceSpikes() { + super(Tier.ADVANCED, 30, Element.ICE, "ice_spikes", SpellType.ATTACK, 75, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(20*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK && rayTrace.sideHit == EnumFacing.UP){ + + if(!world.isRemote){ + + double x = rayTrace.hitVec.xCoord; + double y = rayTrace.hitVec.yCoord; + double z = rayTrace.hitVec.zCoord; + + for(int i=0; i<(int)(18*modifiers.get(WizardryItems.blast_upgrade)); i++){ + + float angle = (float)(world.rand.nextFloat()*Math.PI*2); + double radius = 0.5 + world.rand.nextDouble()*2*modifiers.get(WizardryItems.blast_upgrade); + + double x1 = x + radius*MathHelper.sin(angle); + double z1 = z + radius*MathHelper.cos(angle); + double y1 = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(MathHelper.floor_double(x1), (int)y, MathHelper.floor_double(z1)), 2) - 1; + + if(y1 > -1){ + EntityIceSpike icespike = new EntityIceSpike(world, x1, y1, z1, caster, 30 + world.rand.nextInt(15), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(icespike); + } + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + + double x = target.posX; + double y = target.posY; + double z = target.posZ; + + for(int i=0; i<(int)(18*modifiers.get(WizardryItems.blast_upgrade)); i++){ + + float angle = (float)(world.rand.nextFloat()*Math.PI*2); + double radius = 0.5 + world.rand.nextDouble()*2*modifiers.get(WizardryItems.blast_upgrade); + + double x1 = x + radius*MathHelper.sin(angle); + double z1 = z + radius*MathHelper.cos(angle); + double y1 = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(MathHelper.floor_double(x1), (int)y, MathHelper.floor_double(z1)), 2) - 1; + + if(y1 > -1){ + EntityIceSpike icespike = new EntityIceSpike(world, x1, y1, z1, caster, 30 + world.rand.nextInt(15), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(icespike); + } + } + } + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, 1.0F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/IceStatue.java b/src/main/java/electroblob/wizardry/spell/IceStatue.java new file mode 100644 index 00000000..1928421a --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/IceStatue.java @@ -0,0 +1,120 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.tileentity.TileEntityStatue; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.monster.EntityBlaze; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class IceStatue extends Spell { + + private static final int baseDuration = 400; + + public IceStatue() { + super(Tier.APPRENTICE, 15, Element.ICE, "ice_statue", SpellType.ATTACK, 40, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLiving && !world.isRemote){ + + EntityLiving target = (EntityLiving) rayTrace.entityHit; + + BlockPos pos = new BlockPos(target); + + if(target.isBurning()){ + target.extinguish(); + } + + // Stops the entity looking red while frozen and the resulting z-fighting + target.hurtTime = 0; + + if(target instanceof EntityBlaze) caster.addStat(WizardryAchievements.freeze_blaze, 1); + + // Short mobs such as spiders and pigs + if((target.height < 1.2 || target.isChild()) && WizardryUtilities.canBlockBeReplaced(world, pos)){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 1); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime((int)(baseDuration*modifiers.get(WizardryItems.duration_upgrade))); + } + target.setDead(); + target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + } + // Normal sized mobs like zombies and skeletons + else if(target.height < 2.5 && WizardryUtilities.canBlockBeReplaced(world, pos) && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 2); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime((int)(baseDuration*modifiers.get(WizardryItems.duration_upgrade))); + } + + world.setBlockState(pos.up(), WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 2); + } + target.setDead(); + target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + } + // Tall mobs like endermen and iron golems + else if(WizardryUtilities.canBlockBeReplaced(world, pos) && WizardryUtilities.canBlockBeReplaced(world, pos.up()) && WizardryUtilities.canBlockBeReplaced(world, pos.up(2))){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 3); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime((int)(baseDuration*modifiers.get(WizardryItems.duration_upgrade))); + } + + world.setBlockState(pos.up(), WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 3); + } + + world.setBlockState(pos.up(2), WizardryBlocks.ice_statue.getDefaultState()); + if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(target, 3, 3); + } + target.setDead(); + target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + } + } + if(world.isRemote){ + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + float brightness = 0.5f + (world.rand.nextFloat()/2); + + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, x1, y1, z1, 0.0d, -0.02d, 0.0d, 20 + world.rand.nextInt(10)); + + } + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.2F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Ignite.java b/src/main/java/electroblob/wizardry/spell/Ignite.java new file mode 100644 index 00000000..2807a570 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Ignite.java @@ -0,0 +1,136 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class Ignite extends Spell { + + public Ignite() { + super(Tier.BASIC, 5, Element.FIRE, "ignite", SpellType.ATTACK, 10, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // Entity ray trace is done first because block ray trace passes through entities; if it was the other + // way round, entities would only be hit when there were no blocks in range behind them. + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase) rayTrace.entityHit; + + if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ + if(!world.isRemote) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + target.setFire((int)(10*modifiers.get(WizardryItems.duration_upgrade))); + } + + if(world.isRemote){ + double dx = target.posX - caster.posX; + double dy = (target.getEntityBoundingBox().minY + target.height/2) - WizardryUtilities.getPlayerEyesPos(caster); + double dz = target.posZ - caster.posZ; + // i starts at 1 so that particles are not spawned in the player's head. + for(int i=1;i<5;i++){ + //WizardryUtilities.spawnParticleAndNotify(world, EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, caster.posY + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0, 0, 0, 0, 0); + //WizardryUtilities.spawnParticleAndNotify(world, EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, caster.posY + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0, 0, 0, 0, 0); + world.spawnParticle(EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0); + world.spawnParticle(EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0); + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ITEM_FLINTANDSTEEL_USE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + + return true; + + }else{ + + rayTrace = WizardryUtilities.rayTrace(10*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + // Gets block the player is looking at and sets the appropriate surrounding air block to fire. + // Note how the block is set on the server side only (kinda obvious really) but the particles are + // spawned on the client side only. + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = rayTrace.getBlockPos().offset(rayTrace.sideHit); + + if(world.isAirBlock(pos)){ + if(!world.isRemote){ + world.setBlockState(pos, Blocks.FIRE.getDefaultState()); + } + + if(world.isRemote){ + + double dx = pos.getX() + 0.5 - caster.posX; + double dy = pos.getY() + 0.5 - WizardryUtilities.getPlayerEyesPos(caster); + double dz = pos.getZ() + 0.5 - caster.posZ; + + for(int i=1;i<5;i++){ + world.spawnParticle(EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0); + world.spawnParticle(EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0); + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ITEM_FLINTANDSTEEL_USE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + return true; + } + } + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)) target.setFire((int)(10*modifiers.get(WizardryItems.duration_upgrade))); + + if(world.isRemote){ + double dx = target.posX - caster.posX; + double dy = (target.getEntityBoundingBox().minY + target.height/2) - (caster.posY + caster.getEyeHeight()); + double dz = target.posZ - caster.posZ; + // i starts at 1 so that particles are not spawned in the player's head. + for(int i=1;i<5;i++){ + //WizardryUtilities.spawnParticleAndNotify(world, EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, caster.posY + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0, 0, 0, 0, 0); + //WizardryUtilities.spawnParticleAndNotify(world, EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, caster.posY + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0, 0, 0, 0, 0); + world.spawnParticle(EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, caster.posY + caster.getEyeHeight() + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0); + world.spawnParticle(EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, caster.posY + caster.getEyeHeight() + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0); + } + } + + caster.swingArm(hand); + caster.playSound(SoundEvents.ITEM_FLINTANDSTEEL_USE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java new file mode 100644 index 00000000..f2dbbcf6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java @@ -0,0 +1,76 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryEnchantments; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemBow; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemSword; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class ImbueWeapon extends Spell { + + public ImbueWeapon() { + super(Tier.APPRENTICE, 20, Element.SORCERY, "imbue_weapon", SpellType.UTILITY, 50, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // Won't work if the weapon already has the enchantment + if(WizardData.get(caster) != null){ + + for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(caster)){ + + if(stack != null){ + + if(stack.getItem() instanceof ItemSword && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.magic_sword) + && WizardData.get(caster).getImbuementDuration(WizardryEnchantments.magic_sword) <= 0){ + // The enchantment level as determined by the damage multiplier. The + 0.5f is so that + // weird float processing doesn't incorrectly round it down. + stack.addEnchantment(WizardryEnchantments.magic_sword, modifiers.get(SpellModifiers.DAMAGE) == 1.0f ? 1 : (int)((modifiers.get(SpellModifiers.DAMAGE) - 1.0f)/Constants.DAMAGE_INCREASE_PER_TIER + 0.5f)); + WizardData.get(caster).setImbuementDuration(WizardryEnchantments.magic_sword, (int)(900*modifiers.get(WizardryItems.duration_upgrade))); + + }else if(stack.getItem() instanceof ItemBow && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.magic_bow) + && WizardData.get(caster).getImbuementDuration(WizardryEnchantments.magic_bow) <= 0){ + // The enchantment level as determined by the damage multiplier. The + 0.5f is so that + // weird float processing doesn't incorrectly round it down. + stack.addEnchantment(WizardryEnchantments.magic_bow, modifiers.get(SpellModifiers.DAMAGE) == 1.0f ? 1 : (int)((modifiers.get(SpellModifiers.DAMAGE) - 1.0f)/Constants.DAMAGE_INCREASE_PER_TIER + 0.5f)); + WizardData.get(caster).setImbuementDuration(WizardryEnchantments.magic_bow, (int)(900*modifiers.get(WizardryItems.duration_upgrade))); + + }else{ + continue; + } + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.9f, 0.7f, 1.0f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + return true; + } + } + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Intimidate.java b/src/main/java/electroblob/wizardry/spell/Intimidate.java new file mode 100644 index 00000000..20e3bbe9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Intimidate.java @@ -0,0 +1,105 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityCreature; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.RandomPositionGenerator; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.pathfinding.PathPoint; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class Intimidate extends Spell { + + /** The NBT tag name for storing the feared entity's UUID in the target's tag compound. Defined here in case + * it changes. */ + public static final String NBT_KEY = "fearedEntity"; + + public Intimidate() { + super(Tier.APPRENTICE, 20, Element.NECROMANCY, "intimidate", SpellType.ATTACK, 100, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + List entities = WizardryUtilities.getEntitiesWithinRadius(8*modifiers.get(WizardryItems.range_upgrade), caster.posX, caster.posY, caster.posZ, world, EntityCreature.class); + + for(EntityCreature target : entities){ + + runAway(target, caster); + + NBTTagCompound entityNBT = target.getEntityData(); + if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID()); + + ((EntityLiving)target).addPotionEffect(new PotionEffect(WizardryPotions.fear, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 0)); + + } + + }else{ + for(int i=0; i<30; i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, caster.posX - 1 + world.rand.nextDouble()*2, + caster.getEntityBoundingBox().minY + 1.5 + world.rand.nextDouble()*0.5, + caster.posZ - 1 + world.rand.nextDouble()*2, + 0, 0, 0, 0, 0.9f, 0.1f, 0.0f); + } + } + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERDRAGON_GROWL, 1.0f, 1.0f); + return true; + } + + /** + * Finds a random position away from the caster and sets the given target's AI path to that location. Defined here + * so it can be used both in the spell itself and in the potion effect (event handler). + * @param target The entity running away + * @param caster The entity that is being run away from + * @return True if a new path was found and set, false if not. + */ + public static boolean runAway(EntityCreature target, EntityLivingBase caster){ + + if(target.getDistanceToEntity(caster) < 16){ + + Vec3d Vec3d = RandomPositionGenerator.findRandomTargetBlockAwayFrom(target, 16, 7, new Vec3d(caster.posX, caster.posY, caster.posZ)); + + if (Vec3d == null){ + return false; + + }else{ + // In both cases it is necessary to check if the entity already has a path so it doesn't change direction + // every tick, unless that path is towards the caster. + //Path path = target.getNavigator().getPathToXYZ(Vec3d.xCoord, Vec3d.yCoord, Vec3d.zCoord); + + boolean flag = true; + + if(!target.getNavigator().noPath()){ + PathPoint point = target.getNavigator().getPath().getFinalPathPoint(); + if(point != null) flag = caster.getDistance(point.xCoord, point.yCoord, point.zCoord) < 16; + } + // Has a built in mind trick effect because for whatever reason this makes it work with skeletons. + target.setAttackTarget(null); + + if(flag) return target.getNavigator().tryMoveToXYZ(Vec3d.xCoord, Vec3d.yCoord, Vec3d.zCoord, 1.25);//target.getEntityAttribute(SharedMonsterAttributes.movementSpeed).getAttributeValue()); + } + } + + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java new file mode 100644 index 00000000..b4cbc77d --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java @@ -0,0 +1,54 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class InvigoratingPresence extends Spell { + + public InvigoratingPresence() { + super(Tier.APPRENTICE, 30, Element.HEALING, "invigorating_presence", SpellType.UTILITY, 60, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + List targets = WizardryUtilities.getEntitiesWithinRadius(5*modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world, EntityPlayer.class); + + for(EntityPlayer target : targets){ + if(WizardryUtilities.isPlayerAlly(caster, target) || target == caster){ + // Strength 2 for 45 seconds. + target.addPotionEffect(new PotionEffect(MobEffects.STRENGTH, (int)(900*modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); + } + } + + if(world.isRemote){ + for(int i=0;i<50*modifiers.get(WizardryItems.blast_upgrade);i++){ + double radius = (1 + world.rand.nextDouble()*4)*modifiers.get(WizardryItems.blast_upgrade); + double angle = world.rand.nextDouble()*Math.PI*2; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX + radius*Math.cos(angle), caster.getEntityBoundingBox().minY, caster.posZ + radius*Math.sin(angle), + 0, 0.03, 0, 50, 1, 0.2f, 0.2f); + + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Invisibility.java b/src/main/java/electroblob/wizardry/spell/Invisibility.java new file mode 100644 index 00000000..a26836d2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Invisibility.java @@ -0,0 +1,72 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Invisibility extends Spell { + + public Invisibility() { + super(Tier.ADVANCED, 35, Element.SORCERY, "invisibility", SpellType.UTILITY, 200, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + caster.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.7f, 1.0f, 1.0f); + } + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(!caster.isPotionActive(MobEffects.INVISIBILITY)){ + + caster.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.7f, 1.0f, 1.0f); + } + } + caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/InvokeWeather.java b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java new file mode 100644 index 00000000..98fd97c6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java @@ -0,0 +1,67 @@ +package electroblob.wizardry.spell; + +import java.util.Random; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class InvokeWeather extends Spell { + + public InvokeWeather() { + super(Tier.ADVANCED, 30, Element.LIGHTNING, "invoke_weather", SpellType.UTILITY, 100, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.dimension == 0){ + + if(!world.isRemote){ + // TODO: Backport these changes. + int standardWeatherTime = (300 + (new Random()).nextInt(600)) * 20; + if(world.isRaining()){ + caster.addChatComponentMessage(new TextComponentTranslation("spell.invoke_weather.sun")); + world.getWorldInfo().setCleanWeatherTime(standardWeatherTime); + world.getWorldInfo().setRainTime(0); + world.getWorldInfo().setThunderTime(0); + world.getWorldInfo().setRaining(false); + world.getWorldInfo().setThundering(false); + }else{ + caster.addChatComponentMessage(new TextComponentTranslation("spell.invoke_weather.rain")); + world.getWorldInfo().setCleanWeatherTime(0); + world.getWorldInfo().setRainTime(standardWeatherTime); + world.getWorldInfo().setThunderTime(standardWeatherTime); + world.getWorldInfo().setRaining(true); + // 1/3 chance for a thunderstorm + world.getWorldInfo().setThundering(world.rand.nextInt(3) == 0); + } + } + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.5f, 0.7f, 1.0f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_LIGHTNING_THUNDER, 0.5F, 1.0f); + return true; + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Ironflesh.java b/src/main/java/electroblob/wizardry/spell/Ironflesh.java new file mode 100644 index 00000000..0997439b --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Ironflesh.java @@ -0,0 +1,73 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Ironflesh extends Spell { + + public Ironflesh() { + super(Tier.ADVANCED, 30, Element.HEALING, "ironflesh", SpellType.DEFENCE, 100, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 2, false, false)); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.4f, 0.5f, 0.6f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(!caster.isPotionActive(MobEffects.RESISTANCE)){ + + caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 2, false, false)); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.4f, 0.5f, 0.6f); + } + } + + caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Leap.java b/src/main/java/electroblob/wizardry/spell/Leap.java new file mode 100644 index 00000000..49c2265c --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Leap.java @@ -0,0 +1,47 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.world.World; + +public class Leap extends Spell { + + public Leap() { + super(Tier.BASIC, 10, Element.EARTH, "leap", SpellType.UTILITY, 20, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.onGround){ + + caster.motionY = 0.65 * modifiers.get(SpellModifiers.DAMAGE); + caster.addVelocity(caster.getLookVec().xCoord*0.3, 0, caster.getLookVec().zCoord*0.3); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x = (double)(caster.posX + world.rand.nextFloat() - 0.5F); + double y = (double)(caster.getEntityBoundingBox().minY); + double z = (double)(caster.posZ + world.rand.nextFloat() - 0.5F); + world.spawnParticle(EnumParticleTypes.CLOUD, x, y, z, 0, 0, 0); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERDRAGON_FLAP, 0.5F, 1.0f); + caster.swingArm(hand); + return true; + } + + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Levitation.java b/src/main/java/electroblob/wizardry/spell/Levitation.java new file mode 100644 index 00000000..4cff7b9e --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Levitation.java @@ -0,0 +1,39 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Levitation extends Spell { + + public Levitation() { + super(Tier.ADVANCED, 10, Element.SORCERY, "levitation", SpellType.UTILITY, 0, EnumAction.BOW, true); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + caster.fallDistance = 0; + + caster.motionY = caster.motionY < 0.5d ? caster.motionY + 0.1d : caster.motionY; + + if(world.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX - 0.25d + world.rand.nextDouble()/2, WizardryUtilities.getPlayerEyesPos(caster) - 1.5f, caster.posZ - 0.25d + world.rand.nextDouble()/2, 0, -0.1F, 0, 15, 0.5f, 1.0f, 0.7f); + } + if(ticksInUse % 24 == 0 && world.isRemote){ + Wizardry.proxy.playMovingSound(caster, WizardrySounds.SPELL_LOOP_SPARKLE, 0.5F, 1.0f, false); + } + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/LifeDrain.java b/src/main/java/electroblob/wizardry/spell/LifeDrain.java new file mode 100644 index 00000000..cd2368b6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/LifeDrain.java @@ -0,0 +1,102 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class LifeDrain extends Spell { + + public LifeDrain() { + super(Tier.APPRENTICE, 10, Element.NECROMANCY, "life_drain", SpellType.ATTACK, 0, EnumAction.NONE, true); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase) rayTrace.entityHit; + + if(ticksInUse % 12 == 0){ + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), 2.0f * modifiers.get(SpellModifiers.DAMAGE)); + caster.heal(1); + } + } + if(world.isRemote){ + for(int i=5; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + //world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); + if(i % 5 == 0){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); + } + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, -0.05*look.xCoord*i, -0.05*look.yCoord*i, -0.05*look.zCoord*i, 8 + world.rand.nextInt(6), 0.5f, 0.0f, 0.0f); + } + } + if(ticksInUse % 18 == 0){ + if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 1.0F, 0.6f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_CRACKLE, 2.0F, 1.0f); + } + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers) { + + Vec3d vec = new Vec3d(target.posX - caster.posX, target.posY - caster.posY, target.posZ - caster.posZ).normalize(); + + if(target != null){ + if(ticksInUse % 12 == 0){ + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), 2.0f * modifiers.get(SpellModifiers.DAMAGE)); + caster.heal(1); + } + } + if(world.isRemote){ + for(int i=5; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! + double x1 = caster.posX + vec.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + vec.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + //world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); + if(i % 5 == 0){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); + } + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, -0.05*vec.xCoord*i, -0.05*vec.yCoord*i, -0.05*vec.zCoord*i, 8 + world.rand.nextInt(6), 0.5f, 0.0f, 0.0f); + } + } + if(ticksInUse % 18 == 0){ + if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_SUMMONING, 1.0F, 0.6f); + caster.playSound(WizardrySounds.SPELL_LOOP_CRACKLE, 2.0F, 1.0f); + } + + return true; + } + + @Override + public boolean canBeCastByNPCs() { + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Light.java b/src/main/java/electroblob/wizardry/spell/Light.java new file mode 100644 index 00000000..96d056c8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Light.java @@ -0,0 +1,77 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.tileentity.TileEntityTimer; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class Light extends Spell { + + public Light() { + super(Tier.BASIC, 5, Element.SORCERY, "light", SpellType.UTILITY, 15, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(4, world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = rayTrace.getBlockPos().offset(rayTrace.sideHit); + + if(world.isAirBlock(pos)){ + + if(!world.isRemote){ + world.setBlockState(pos, WizardryBlocks.magic_light.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityTimer){ + ((TileEntityTimer)world.getTileEntity(pos)).setLifetime((int)(600*modifiers.get(WizardryItems.duration_upgrade))); + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + return true; + } + }else{ + + int x = (int) (Math.floor(caster.posX) + caster.getLookVec().xCoord*4); + int y = (int) (Math.floor(caster.posY) + caster.eyeHeight + caster.getLookVec().yCoord*4); + int z = (int) (Math.floor(caster.posZ) + caster.getLookVec().zCoord*4); + + BlockPos pos = new BlockPos(x, y, z); + + if(world.isAirBlock(pos)){ + //world.playSound(x, y, z, "sound.ambient.cave.cave", 1.0f, 1.5f, false); + if(!world.isRemote){ + world.setBlockState(pos, WizardryBlocks.magic_light.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityTimer){ + ((TileEntityTimer)world.getTileEntity(pos)).setLifetime((int)(600*modifiers.get(WizardryItems.duration_upgrade))); + } + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + return true; + } + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/LightningArrow.java b/src/main/java/electroblob/wizardry/spell/LightningArrow.java new file mode 100644 index 00000000..423fb35e --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/LightningArrow.java @@ -0,0 +1,65 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityLightningArrow; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class LightningArrow extends Spell { + + public LightningArrow() { + super(Tier.APPRENTICE, 15, Element.LIGHTNING, "lightning_arrow", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityLightningArrow lightningArrow = new EntityLightningArrow(world, caster, 2*modifiers.get(WizardryItems.range_upgrade), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(lightningArrow); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, world.rand.nextFloat() * 0.3F + 1.3F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityLightningArrow lightningArrow = new EntityLightningArrow(world, caster, target, 2*modifiers.get(WizardryItems.range_upgrade), 4, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(lightningArrow); + } + + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1.0F, world.rand.nextFloat() * 0.3F + 1.3F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/LightningBolt.java b/src/main/java/electroblob/wizardry/spell/LightningBolt.java new file mode 100644 index 00000000..9adbc736 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/LightningBolt.java @@ -0,0 +1,90 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.effect.EntityLightningBolt; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class LightningBolt extends Spell { + + public LightningBolt() { + super(Tier.ADVANCED, 40, Element.LIGHTNING, "lightning_bolt", SpellType.ATTACK, 80, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(200, world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = rayTrace.getBlockPos(); + + // Not sure why it is up 1 but it has to be for canBlockSeeSky to work properly. + // TODO: Remove this requirement? + if(world.canBlockSeeSky(pos.up())){ + + if(!world.isRemote){ + EntityLightningBolt entitylightning = new EntityLightningBolt(world, pos.getX(), pos.getY(), pos.getZ(), false); + world.addWeatherEffect(entitylightning); + + // Code for eventhandler recognition; for achievements and such like. Left in for future use. + NBTTagCompound entityNBT = entitylightning.getEntityData(); + entityNBT.setUniqueId("summoningPlayer", caster.getUniqueID()); + } + + caster.swingArm(hand); + return true; + } + } + + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + int x = (int)target.posX; + int y = (int)target.posY; + int z = (int)target.posZ; + + // Not sure why it is up 1 but it has to be for canBlockSeeSky to work properly. + // TODO: Remove this requirement? + if(world.canBlockSeeSky(new BlockPos(x, y, z))){ + + if(!world.isRemote){ + EntityLightningBolt entitylightning = new EntityLightningBolt(world, x, y, z, false); + world.addWeatherEffect(entitylightning); + } + + caster.swingArm(hand); + return true; + } + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } +} diff --git a/src/main/java/electroblob/wizardry/spell/LightningDisc.java b/src/main/java/electroblob/wizardry/spell/LightningDisc.java new file mode 100644 index 00000000..fe0d5f18 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/LightningDisc.java @@ -0,0 +1,65 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityLightningDisc; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class LightningDisc extends Spell { + + public LightningDisc() { + super(Tier.ADVANCED, 25, Element.LIGHTNING, "lightning_disc", SpellType.ATTACK, 60, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityLightningDisc lightningdisc = new EntityLightningDisc(world, caster, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(lightningdisc); + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, world.rand.nextFloat() * 0.3F + 0.8F); + caster.swingArm(hand); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityLightningDisc lightningdisc = new EntityLightningDisc(world, caster, modifiers.get(SpellModifiers.DAMAGE)); + lightningdisc.directTowards(target, 1.2f); + world.spawnEntityInWorld(lightningdisc); + } + + caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1.0F, world.rand.nextFloat() * 0.3F + 0.8F); + caster.swingArm(hand); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/LightningHammer.java b/src/main/java/electroblob/wizardry/spell/LightningHammer.java new file mode 100644 index 00000000..a7408c2e --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/LightningHammer.java @@ -0,0 +1,61 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityHammer; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class LightningHammer extends Spell { + + public LightningHammer() { + super(Tier.MASTER, 100, Element.LIGHTNING, "lightning_hammer", SpellType.ATTACK, 300, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(40*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = rayTrace.getBlockPos(); + + // Not sure why it is +1 but it has to be to work properly. + if(world.canBlockSeeSky(pos.up())){ + + if(!world.isRemote){ + + EntityHammer hammer = new EntityHammer(world, pos.getX()+0.5, pos.getY()+50, pos.getZ()+0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE)); + + hammer.motionX = 0; + hammer.motionY = -2; + hammer.motionZ = 0; + + world.spawnEntityInWorld(hammer); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 3.0f, 1.0f); + return true; + } + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/LightningPulse.java b/src/main/java/electroblob/wizardry/spell/LightningPulse.java new file mode 100644 index 00000000..f180b10d --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/LightningPulse.java @@ -0,0 +1,80 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityLightningPulse; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.EnumAction; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +public class LightningPulse extends Spell { + + public LightningPulse() { + super(Tier.ADVANCED, 25, Element.LIGHTNING, "lightning_pulse", SpellType.ATTACK, 75, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.onGround){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(3.0d*modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + + for(EntityLivingBase target : targets){ + if(WizardryUtilities.isValidTarget(caster, target)){ + // Damage is 4 hearts no matter where the target is. + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 8 * modifiers.get(SpellModifiers.DAMAGE)); + + if(!world.isRemote){ + + double dx = target.posX - caster.posX; + double dz = target.posZ - caster.posZ; + // Normalises the velocity. + double vectorLength = MathHelper.sqrt_double(dx*dx + dz*dz); + dx /= vectorLength; + dz /= vectorLength; + + target.motionX = 0.8 * dx; + target.motionY = 0; + target.motionZ = 0.8 * dz; + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + } + } + } + if(!world.isRemote){ + EntityLightningPulse lightningpulse = new EntityLightningPulse(world, caster.posX, caster.getEntityBoundingBox().minY, caster.posZ, caster, 7, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(lightningpulse); + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0f, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 2.0f, 1.0f); + return true; + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/LightningRay.java b/src/main/java/electroblob/wizardry/spell/LightningRay.java new file mode 100644 index 00000000..b956bd49 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/LightningRay.java @@ -0,0 +1,143 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class LightningRay extends Spell { + + public LightningRay() { + super(Tier.APPRENTICE, 5, Element.LIGHTNING, "lightning_ray", SpellType.ATTACK, 0, EnumAction.NONE, true); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade), 2.0f); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + Entity target = rayTrace.entityHit; + if(!world.isRemote){ + // This statement means the arc only spawns every other tick. + if(ticksInUse % 2 == 0){ + + EntityArc arc = new EntityArc(world); + // The look vec stuff performs a translation on the start point to line it up with the wand. + // EDIT: removed due to 1st/3rd person render differences. + arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, + target.posX, target.posY + target.height/2, target.posZ); + + arc.lifetime = 1; + + world.spawnEntityInWorld(arc); + } + + if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ + if(!world.isRemote && ticksInUse == 1) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 3.0f * modifiers.get(SpellModifiers.DAMAGE)); + } + + }else{ + for(int i=0;i<5;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, target.posX + world.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + world.rand.nextFloat()*2 - 1, target.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + } + } + + if(ticksInUse == 1){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); + }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); + } + + return true; + + }else{ + if(!world.isRemote){ + // This statement means the arc only spawns every other tick. + if(ticksInUse % 2 == 0){ + + EntityArc arc = new EntityArc(world); + + arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, + caster.posX + caster.getLookVec().xCoord * 8, caster.posY + caster.eyeHeight + caster.getLookVec().yCoord * 8, caster.posZ + caster.getLookVec().zCoord * 8); + + arc.lifetime = 1; + + world.spawnEntityInWorld(arc); + } + } + + if(ticksInUse == 1){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); + }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); + } + + return true; + } + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + if(!world.isRemote){ + // This statement means the arc only spawns every other tick. + if(ticksInUse % 2 == 0){ + + EntityArc arc = new EntityArc(world); + // The look vec stuff performs a translation on the start point to line it up with the wand. + // EDIT: removed due to 1st/3rd person render differences. + arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, + target.posX, target.posY + target.height/2, target.posZ); + + arc.lifetime = 1; + + world.spawnEntityInWorld(arc); + } + + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 3.0f * modifiers.get(SpellModifiers.DAMAGE)); + + }else{ + for(int i=0;i<5;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, target.posX + world.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + world.rand.nextFloat()*2 - 1, target.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + } + } + + if(ticksInUse == 1){ + caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); + }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ + caster.playSound(WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); + } + + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/LightningSigil.java b/src/main/java/electroblob/wizardry/spell/LightningSigil.java new file mode 100644 index 00000000..831a1189 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/LightningSigil.java @@ -0,0 +1,52 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityLightningSigil; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class LightningSigil extends Spell { + + public LightningSigil() { + super(Tier.APPRENTICE, 10, Element.LIGHTNING, "lightning_sigil", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(10*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK && rayTrace.sideHit == EnumFacing.UP){ + + if(!world.isRemote){ + double x = rayTrace.hitVec.xCoord; + double y = rayTrace.hitVec.yCoord; + double z = rayTrace.hitVec.zCoord; + EntityLightningSigil lightningsigil = new EntityLightningSigil(world, x, y, z, caster, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(lightningsigil); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0F, 0.3F); + return true; + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/LightningWeb.java b/src/main/java/electroblob/wizardry/spell/LightningWeb.java new file mode 100644 index 00000000..3b654be1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/LightningWeb.java @@ -0,0 +1,193 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class LightningWeb extends Spell { + + public LightningWeb() { + super(Tier.MASTER, 15, Element.LIGHTNING, "lightning_web", SpellType.ATTACK, 0, EnumAction.NONE, true); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade), 2.0f); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + + Entity target = rayTrace.entityHit; + + if(!world.isRemote){ + + // This statement means the arc only spawns every other tick. + if(ticksInUse % 2 == 0){ + EntityArc arc = new EntityArc(world); + // The look vec stuff performs a translation on the start point to line it up with the wand. + // EDIT: removed due to 1st/3rd person render differences. + arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, + target.posX, target.posY + target.height/2, target.posZ); + arc.lifetime = 1; + world.spawnEntityInWorld(arc); + } + + if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ + if(!world.isRemote && ticksInUse == 1) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + // This motion stuff removes knockback, which is desirable for continuous spells. + double motionX = target.motionX; + double motionY = target.motionY; + double motionZ = target.motionZ; + + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 5.0f * modifiers.get(SpellModifiers.DAMAGE)); + + target.motionX = motionX; + target.motionY = motionY; + target.motionZ = motionZ; + } + }else{ + for(int i=0;i<5;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, target.posX + world.rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height/2 + world.rand.nextFloat()*2 - 1, target.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + } + } + + // Secondary chaining effect + double seekerRange = 5.0d; + + List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, target.posX, target.posY + target.height/2, target.posZ, world); + // This is a MUCH better way of filtering the secondary targets! + secondaryTargets.remove(target); + if(secondaryTargets.size() > 5) secondaryTargets = secondaryTargets.subList(0, 5); + + for(EntityLivingBase secondaryTarget : secondaryTargets){ + + if(WizardryUtilities.isValidTarget(caster, secondaryTarget)){ + + if(!world.isRemote){ + // This statement means the arc only spawns every other tick. + if(ticksInUse % 2 == 0){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(target.posX, target.posY + 1.2, target.posZ, + secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height/2, secondaryTarget.posZ); + arc.lifetime = 1; + world.spawnEntityInWorld(arc); + } + + if(MagicDamage.isEntityImmune(DamageType.SHOCK, secondaryTarget)){ + if(!world.isRemote && ticksInUse == 1) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", secondaryTarget.getName(), this.getNameForTranslationFormatted())); + }else{ + // This motion stuff removes knockback, which is desirable for continuous spells. + double motionX = secondaryTarget.motionX; + double motionY = secondaryTarget.motionY; + double motionZ = secondaryTarget.motionZ; + + secondaryTarget.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 4.0f * modifiers.get(SpellModifiers.DAMAGE)); + + secondaryTarget.motionX = motionX; + secondaryTarget.motionY = motionY; + secondaryTarget.motionZ = motionZ; + } + }else{ + for(int i=0;i<5;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, secondaryTarget.posX + world.rand.nextFloat() - 0.5, secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height/2 + world.rand.nextFloat()*2 - 1, secondaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + } + } + + // Tertiary chaining effect + + List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height/2, secondaryTarget.posZ, world); + tertiaryTargets.remove(target); + tertiaryTargets.removeAll(secondaryTargets); + if(tertiaryTargets.size() > 2) tertiaryTargets = tertiaryTargets.subList(0, 2); + + for(EntityLivingBase tertiaryTarget : tertiaryTargets){ + + if(WizardryUtilities.isValidTarget(caster, tertiaryTarget)){ + + if(!world.isRemote){ + // This statement means the arc only spawns every other tick. + if(ticksInUse % 2 == 0){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(secondaryTarget.posX, secondaryTarget.posY + 1.2, secondaryTarget.posZ, + tertiaryTarget.posX, tertiaryTarget.posY + tertiaryTarget.height/2, tertiaryTarget.posZ); + arc.lifetime = 1; + world.spawnEntityInWorld(arc); + } + + if(MagicDamage.isEntityImmune(DamageType.SHOCK, tertiaryTarget)){ + if(!world.isRemote && ticksInUse == 1) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", tertiaryTarget.getName(), this.getNameForTranslationFormatted())); + }else{ + // This motion stuff removes knockback, which is desirable for continuous spells. + double motionX = tertiaryTarget.motionX; + double motionY = tertiaryTarget.motionY; + double motionZ = tertiaryTarget.motionZ; + + tertiaryTarget.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 3.0f * modifiers.get(SpellModifiers.DAMAGE)); + + tertiaryTarget.motionX = motionX; + tertiaryTarget.motionY = motionY; + tertiaryTarget.motionZ = motionZ; + } + }else{ + for(int i=0;i<5;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, tertiaryTarget.posX + world.rand.nextFloat() - 0.5, tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height/2 + world.rand.nextFloat()*2 - 1, tertiaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + } + } + } + } + } + } + + if(ticksInUse == 1){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); + }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); + } + + return true; + + }else{ + if(!world.isRemote){ + // This statement means the arc only spawns every other tick. + if(ticksInUse % 2 == 0){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, + caster.posX + caster.getLookVec().xCoord * 8, caster.posY + caster.eyeHeight + caster.getLookVec().yCoord * 8, caster.posZ + caster.getLookVec().zCoord * 8); + arc.lifetime = 1; + //arc.setOffset(entityplayer.getLookVec().zCoord * 0.5, entityplayer.getLookVec().xCoord * 0.5); + world.spawnEntityInWorld(arc); + } + } + + if(ticksInUse == 1){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); + }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); + } + + return true; + } + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/MagicMissile.java b/src/main/java/electroblob/wizardry/spell/MagicMissile.java new file mode 100644 index 00000000..9cb083e3 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/MagicMissile.java @@ -0,0 +1,67 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityMagicMissile; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class MagicMissile extends Spell { + + public MagicMissile() { + super(Tier.BASIC, 5, Element.MAGIC, "magic_missile", SpellType.ATTACK, 10, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityMagicMissile magicMissile = new EntityMagicMissile(world, caster, 2*modifiers.get(WizardryItems.range_upgrade), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(magicMissile); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_MAGIC, 1.0F, world.rand.nextFloat() * 0.4F + 1.2F); + + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityMagicMissile magicMissile = new EntityMagicMissile(world, caster, target, 2*modifiers.get(WizardryItems.range_upgrade), 4, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(magicMissile); + } + + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_MAGIC, 1.0F, world.rand.nextFloat() * 0.4F + 1.2F); + + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java new file mode 100644 index 00000000..abfceedc --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java @@ -0,0 +1,132 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntityCaveSpider; +import net.minecraft.entity.monster.EntityMagmaCube; +import net.minecraft.entity.monster.EntityPigZombie; +import net.minecraft.entity.monster.EntitySkeleton; +import net.minecraft.entity.monster.EntitySlime; +import net.minecraft.entity.monster.EntitySpider; +import net.minecraft.entity.monster.SkeletonType; +import net.minecraft.entity.passive.EntityBat; +import net.minecraft.entity.passive.EntityChicken; +import net.minecraft.entity.passive.EntityCow; +import net.minecraft.entity.passive.EntityMooshroom; +import net.minecraft.entity.passive.EntityPig; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class Metamorphosis extends Spell { + + public Metamorphosis() { + super(Tier.APPRENTICE, 15, Element.NECROMANCY, "metamorphosis", SpellType.UTILITY, 30, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.entityHit != null && rayTrace.entityHit instanceof EntityLivingBase){ + + Entity entityHit = rayTrace.entityHit; + double xPos = entityHit.posX; + double yPos = entityHit.posY; + double zPos = entityHit.posZ; + + EntityLiving newEntity = null; + boolean flag = false; + + if(entityHit instanceof EntityPig){ + newEntity = new EntityPigZombie(world); + } + else if(entityHit instanceof EntityPigZombie){ + newEntity = new EntityPig(world); + } + else if(entityHit instanceof EntitySkeleton){ + // IDEA: Interaction with husks/strays? + if(((EntitySkeleton)entityHit).getSkeletonType() == SkeletonType.NORMAL){ + ((EntitySkeleton)entityHit).setSkeletonType(SkeletonType.WITHER); + }else{ + ((EntitySkeleton)entityHit).setSkeletonType(SkeletonType.NORMAL); + } + flag = true; + } + else if(entityHit instanceof EntityCow && !(entityHit instanceof EntityMooshroom)){ + newEntity = new EntityMooshroom(world); + } + else if(entityHit instanceof EntityMooshroom){ + newEntity = new EntityCow(world); + } + else if(entityHit instanceof EntityChicken){ + newEntity = new EntityBat(world); + } + else if(entityHit instanceof EntityBat){ + newEntity = new EntityChicken(world); + } + else if(entityHit instanceof EntitySlime && !(entityHit instanceof EntityMagmaCube)){ + newEntity = new EntityMagmaCube(world); + } + else if(entityHit instanceof EntityMagmaCube){ + newEntity = new EntitySlime(world); + } + else if(entityHit instanceof EntitySpider && !(entityHit instanceof EntityCaveSpider)){ + newEntity = new EntityCaveSpider(world); + } + else if(entityHit instanceof EntityCaveSpider){ + newEntity = new EntitySpider(world); + } + + if(newEntity != null || flag){ + + if(!world.isRemote && newEntity != null){ + //Transfers attributes from the old entity to the new one. + newEntity.setHealth(((EntityLiving)entityHit).getHealth()); + //newEntity.writeToNBT(entityHit.getEntityData()); + + entityHit.setDead(); + newEntity.setPosition(xPos, yPos, zPos); + world.spawnEntityInWorld(newEntity); + } + + if(world.isRemote){ + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + //world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.2f, 0.0f, 0.1f); + } + for(int i=0;i<5;i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, xPos, yPos, zPos, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_DEFLECTION, 0.5F, 0.8f); + return true; + } + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Meteor.java b/src/main/java/electroblob/wizardry/spell/Meteor.java new file mode 100644 index 00000000..af6c4aa3 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Meteor.java @@ -0,0 +1,55 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.EntityMeteor; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class Meteor extends Spell { + + public Meteor() { + super(Tier.MASTER, 100, Element.FIRE, "meteor", SpellType.ATTACK, 200, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(40*modifiers.get(WizardryItems.range_upgrade), world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = rayTrace.getBlockPos(); + + // Not sure why it is +1 but it has to be to work properly. + if(world.canBlockSeeSky(pos.up())){ + + if(!world.isRemote){ + EntityMeteor meteor = new EntityMeteor(world, pos.getX(), pos.getY() + 50, pos.getZ(), modifiers.get(WizardryItems.blast_upgrade)); + world.spawnEntityInWorld(meteor); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 3.0f, 1.0f); + return true; + } + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/MindControl.java b/src/main/java/electroblob/wizardry/spell/MindControl.java new file mode 100644 index 00000000..0cb6c6a2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/MindControl.java @@ -0,0 +1,169 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.INpc; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class MindControl extends Spell { + + /** The NBT tag name for storing the controlling entity's UUID in the target's tag compound. Defined here in case + * it changes. */ + public static final String NBT_KEY = "controllingEntity"; + + public MindControl() { + super(Tier.ADVANCED, 40, Element.NECROMANCY, "mind_control", SpellType.ATTACK, 150, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 8*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.entityHit != null && rayTrace.entityHit instanceof EntityLivingBase){ + + Entity target = rayTrace.entityHit; + + if(!world.isRemote){ + if(target instanceof EntityPlayer || !target.isNonBoss() || target instanceof INpc){ + // Adds a message saying that the player/boss entity/wizard resisted mind control + if(!world.isRemote) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + + }else if(target instanceof EntityLiving){ + + if(!MindControl.findMindControlTarget((EntityLiving)target, caster, world)){ + // If no valid target was found, this just acts like mind trick. + ((EntityLiving)target).setAttackTarget(null); + } + + NBTTagCompound entityNBT = target.getEntityData(); + if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID()); + + ((EntityLiving)target).addPotionEffect(new PotionEffect(WizardryPotions.mind_control, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + }else{ + for(int i=0; i<10; i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble()*0.5, + target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble()*0.5, + target.posZ - 0.25 + world.rand.nextDouble()*0.5, + 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble()*0.5, + target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble()*0.5, + target.posZ - 0.25 + world.rand.nextDouble()*0.5, + 0, 0, 0, 0, 0.2f, 0.04f, 0.25f); + } + } + target.playSound(WizardrySounds.SPELL_SUMMONING, 1.0f, 1.0f); + caster.swingArm(hand); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers) { + + if(target != null){ + if(!world.isRemote){ + if(target instanceof EntityLiving && target.isNonBoss() + && !(target instanceof EntityWizard)){ + + if(!MindControl.findMindControlTarget((EntityLiving)target, caster, world)){ + // If no valid target was found, this just acts like mind trick. + ((EntityLiving)target).setAttackTarget(null); + } + + NBTTagCompound entityNBT = target.getEntityData(); + if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID()); + + ((EntityLiving)target).addPotionEffect(new PotionEffect(WizardryPotions.mind_control, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + }else{ + for(int i=0; i<10; i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble()*0.5, + target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble()*0.5, + target.posZ - 0.25 + world.rand.nextDouble()*0.5, + 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble()*0.5, + target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble()*0.5, + target.posZ - 0.25 + world.rand.nextDouble()*0.5, + 0, 0, 0, 0, 0.2f, 0.04f, 0.25f); + } + } + target.playSound(WizardrySounds.SPELL_SUMMONING, 1.0f, 1.0f); + caster.swingArm(hand); + return true; + } + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + + /** + * Finds the nearest creature to the given target which it is allowed to attack according to the given caster + * and sets it as the target's attack target. Handles both new and old AI and takes follow range into account. + * Defined here so it can be used both in the spell itself and in the potion effect (event handler). + * @param target The entity being mind controlled + * @param caster The entity doing the controlling + * @param world The world to look for targets in + * @return True if a new target was found and set, false if not. + */ + public static boolean findMindControlTarget(EntityLiving target, EntityLivingBase caster, World world){ + + // As of 1.1, this now uses the creature's follow range, like normal targeting. It also + // no longer lasts until the creature dies; instead it is a potion effect which continues to + // set the target until it wears off. + List possibleTargets = WizardryUtilities.getEntitiesWithinRadius( + ((EntityLiving)target).getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).getAttributeValue(), + target.posX, target.posY, target.posZ, world); + + possibleTargets.remove(target); + + EntityLivingBase newAITarget = null; + + for(EntityLivingBase possibleTarget : possibleTargets){ + if(WizardryUtilities.isValidTarget(caster, possibleTarget) && (newAITarget == null + || target.getDistanceToEntity(possibleTarget) < target.getDistanceToEntity(newAITarget))){ + newAITarget = possibleTarget; + } + } + + if(newAITarget != null){ + // From 1.7.10 - this seems not to work quite right; the entity appears to continue attacking this target + // after it gets killed (not noticeable in survival since it will target the player again immediately.) + ((EntityLiving)target).setAttackTarget(newAITarget); + + return true; + } + + return false; + + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/MindTrick.java b/src/main/java/electroblob/wizardry/spell/MindTrick.java new file mode 100644 index 00000000..2771e47a --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/MindTrick.java @@ -0,0 +1,100 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class MindTrick extends Spell { + + public MindTrick() { + super(Tier.BASIC, 10, Element.NECROMANCY, "mind_trick", SpellType.ATTACK, 40, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 8*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.entityHit != null && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; + + if(!world.isRemote){ + + if(target instanceof EntityPlayer){ + + target.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, (int)(300*modifiers.get(WizardryItems.duration_upgrade)), 0)); + + }else if(target instanceof EntityLiving){ + + ((EntityLiving)target).setAttackTarget(null); + target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, (int)(300*modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + }else{ + for(int i=0; i<10; i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble()*0.5, + target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble()*0.5, + target.posZ - 0.25 + world.rand.nextDouble()*0.5, + 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); + } + } + + target.playSound(WizardrySounds.SPELL_DEFLECTION, 0.7F, world.rand.nextFloat() * 0.4F + 0.8F); + caster.swingArm(hand); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers) { + + if(target != null){ + if(!world.isRemote){ + if(target instanceof EntityPlayer){ + + target.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, (int)(300*modifiers.get(WizardryItems.duration_upgrade)), 0)); + + }else if(target instanceof EntityLiving){ + + ((EntityLiving)target).setAttackTarget(null); + target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, (int)(300*modifiers.get(WizardryItems.duration_upgrade)), 0)); + + } + }else{ + for(int i=0; i<10; i++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble()*0.5, + target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble()*0.5, + target.posZ - 0.25 + world.rand.nextDouble()*0.5, + 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); + } + } + + target.playSound(WizardrySounds.SPELL_DEFLECTION, 0.7F, world.rand.nextFloat() * 0.4F + 0.8F); + caster.swingArm(hand); + return true; + } + return false; + } + + @Override + public boolean canBeCastByNPCs() { + return true; + } +} diff --git a/src/main/java/electroblob/wizardry/spell/None.java b/src/main/java/electroblob/wizardry/spell/None.java new file mode 100644 index 00000000..12566e04 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/None.java @@ -0,0 +1,32 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +/** This class represents a blank spell used to fill empty slots on wands. It is unobtainable in-game, except via + * commands, and does nothing when the player attempts to cast it. Its instance can be referenced directly using + * {@link electroblob.wizardry.registry.Spells#none WizardryRegistry.none}*/ +public class None extends Spell { + + public None() { + super(Tier.BASIC, 0, Element.MAGIC, "none", SpellType.UTILITY, 0, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Oakflesh.java b/src/main/java/electroblob/wizardry/spell/Oakflesh.java new file mode 100644 index 00000000..cb2f5fd6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Oakflesh.java @@ -0,0 +1,73 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Oakflesh extends Spell { + + public Oakflesh() { + super(Tier.APPRENTICE, 20, Element.HEALING, "oakflesh", SpellType.DEFENCE, 50, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.5f, 0.4f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(!caster.isPotionActive(MobEffects.RESISTANCE)){ + + caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.5f, 0.4f); + } + } + + caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Petrify.java b/src/main/java/electroblob/wizardry/spell/Petrify.java new file mode 100644 index 00000000..4dd4cf24 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Petrify.java @@ -0,0 +1,114 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.tileentity.TileEntityStatue; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class Petrify extends Spell { + + private static final int baseDuration = 900; + + /** The NBT tag name for storing the petrified flag in the target's tag compound. Defined here in case it changes. */ + public static final String NBT_KEY = "petrified"; + + public Petrify() { + super(Tier.ADVANCED, 40, Element.SORCERY, "petrify", SpellType.ATTACK, 100, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLiving && !world.isRemote){ + + EntityLiving target = (EntityLiving) rayTrace.entityHit; + + if(target.deathTime > 0) return false; + + BlockPos pos = new BlockPos(target); + + target.extinguish(); + + //Short mobs such as spiders and pigs + if((target.height < 1.2 || target.isChild()) && WizardryUtilities.canBlockBeReplaced(world, pos)){ + world.setBlockState(pos, WizardryBlocks.petrified_stone.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 1); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime((int)(baseDuration*modifiers.get(WizardryItems.duration_upgrade))); + } + target.getEntityData().setBoolean(NBT_KEY, true); + target.setDead(); + } + //Normal sized mobs like zombies and skeletons + else if(target.height < 2.5 && WizardryUtilities.canBlockBeReplaced(world, pos) && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + world.setBlockState(pos, WizardryBlocks.petrified_stone.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 2); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime((int)(baseDuration*modifiers.get(WizardryItems.duration_upgrade))); + } + + world.setBlockState(pos.up(), WizardryBlocks.petrified_stone.getDefaultState()); + if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 2); + } + target.getEntityData().setBoolean(NBT_KEY, true); + target.setDead(); + } + //Tall mobs like endermen + else if(WizardryUtilities.canBlockBeReplaced(world, pos) && WizardryUtilities.canBlockBeReplaced(world, pos.up()) && WizardryUtilities.canBlockBeReplaced(world, pos.up(2))){ + world.setBlockState(pos, WizardryBlocks.petrified_stone.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 3); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime((int)(baseDuration*modifiers.get(WizardryItems.duration_upgrade))); + } + + world.setBlockState(pos.up(), WizardryBlocks.petrified_stone.getDefaultState()); + if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 3); + } + + world.setBlockState(pos.up(2), WizardryBlocks.petrified_stone.getDefaultState()); + if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(target, 3, 3); + } + target.getEntityData().setBoolean(NBT_KEY, true); + target.setDead(); + } + } + if(world.isRemote){ + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + //world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.1f, 0.1f); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.2f, 0.2f, 0.2f); + } + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/PhaseStep.java b/src/main/java/electroblob/wizardry/spell/PhaseStep.java new file mode 100644 index 00000000..a99034ce --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/PhaseStep.java @@ -0,0 +1,80 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class PhaseStep extends Spell { + + public PhaseStep() { + super(Tier.ADVANCED, 35, Element.SORCERY, "phase_step", SpellType.UTILITY, 40, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // Phase step does not gain range from range multiplier, instead it increases the thickness + // of the wall you can teleport through. + RayTraceResult rayTrace = WizardryUtilities.rayTrace(5, world, caster, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = new BlockPos(rayTrace.getBlockPos().getX(), (int)caster.posY, rayTrace.getBlockPos().getZ()); + + // The maximum wall thickness as determined by the range multiplier. The + 0.5f is so that + // weird float processing doesn't incorrectly round it down. + int maxThickness = 1 + (int)((modifiers.get(WizardryItems.range_upgrade) - 1)/Constants.RANGE_INCREASE_PER_LEVEL + 0.5f); + + if(rayTrace.sideHit.getAxis().isHorizontal()){ + + // i represents how far the player needs to teleport to get through the wall + for(int i = 0; i <= maxThickness; i++){ + + BlockPos pos1 = pos.offset(rayTrace.sideHit.getOpposite(), i); + + // Prevents the player from teleporting through unbreakable blocks, so they cannot cheat in other mods' mazes and dungeons. + if((WizardryUtilities.isBlockUnbreakable(world, pos1) || WizardryUtilities.isBlockUnbreakable(world, pos1.up())) && !Wizardry.settings.teleportThroughUnbreakableBlocks) return false; + + if(!world.getBlockState(pos1).getMaterial().blocksMovement() && !world.getBlockState(pos1.up()).getMaterial().blocksMovement()){ + + if(!world.isRemote){ + caster.setPositionAndUpdate(pos1.getX() + 0.5, caster.posY, pos1.getZ() + 0.5); + } + + caster.swingArm(hand); + return true; + } + } + } + } + + // This is here because the conditions are false on the client for whatever reason. (see the Javadoc for cast() + // for an explanation) + if(world.isRemote){ + for(int i=0;i<10;i++){ + double dx1 = caster.posX; + double dy1 = WizardryUtilities.getPlayerEyesPos(caster) - 1.5 + 2*world.rand.nextFloat(); + double dz1 = caster.posZ; + world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); + } + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + } + + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java new file mode 100644 index 00000000..252868a7 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java @@ -0,0 +1,72 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.world.World; + +public class PlagueOfDarkness extends Spell { + + public PlagueOfDarkness() { + super(Tier.MASTER, 75, Element.NECROMANCY, "plague_of_darkness", SpellType.ATTACK, 200, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + List targets = WizardryUtilities.getEntitiesWithinRadius(5.0d*modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + + for(EntityLivingBase target : targets){ + if(WizardryUtilities.isValidTarget(caster, target) && !MagicDamage.isEntityImmune(DamageType.WITHER, target)){ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), 8.0f * modifiers.get(SpellModifiers.DAMAGE)); + target.addPotionEffect(new PotionEffect(MobEffects.WITHER, (int)(140*modifiers.get(WizardryItems.duration_upgrade)), 2)); + } + } + if(world.isRemote){ + double particleX, particleZ; + for(int i=0;i<40*modifiers.get(WizardryItems.blast_upgrade);i++){ + particleX = caster.posX - 1.0d + 2*world.rand.nextDouble(); + particleZ = caster.posZ - 1.0d + 2*world.rand.nextDouble(); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, particleX, WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, + particleX - caster.posX, 0, particleZ - caster.posZ, 0, 0.1f, 0.0f, 0.0f); + particleX = caster.posX - 1.0d + 2*world.rand.nextDouble(); + particleZ = caster.posZ - 1.0d + 2*world.rand.nextDouble(); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, particleX, WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, + particleX - caster.posX, 0, particleZ - caster.posZ, 30, 0.1f, 0.0f, 0.05f); + particleX = caster.posX - 1.0d + 2*world.rand.nextDouble(); + particleZ = caster.posZ - 1.0d + 2*world.rand.nextDouble(); + + IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster); + + if(block != null){ + world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY, particleZ, + particleX - caster.posX, 0, particleZ - caster.posZ, Block.getStateId(block)); + } + } + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_DEATH, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/PocketFurnace.java b/src/main/java/electroblob/wizardry/spell/PocketFurnace.java new file mode 100644 index 00000000..76f70f58 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/PocketFurnace.java @@ -0,0 +1,72 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.world.World; + +public class PocketFurnace extends Spell { + + public PocketFurnace() { + super(Tier.APPRENTICE, 30, Element.FIRE, "pocket_furnace", SpellType.UTILITY, 40, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + int usesLeft = 5; + + ItemStack stack, result; + + for(int i=0; i 0; i++){ + + stack = caster.inventory.getStackInSlot(i); + + if(stack != null){ + + result = FurnaceRecipes.instance().getSmeltingResult(stack); + + if(result != null){ + if(stack.stackSize <= usesLeft){ + ItemStack stack2 = new ItemStack(result.getItem(), stack.stackSize, result.getItemDamage()); + if(WizardryUtilities.doesPlayerHaveItem(caster, result.getItem())){ + caster.inventory.addItemStackToInventory(stack2); + caster.inventory.setInventorySlotContents(i, null); + }else{ + caster.inventory.setInventorySlotContents(i, stack2); + } + usesLeft -= stack.stackSize; + }else{ + caster.inventory.decrStackSize(i, usesLeft); + caster.inventory.addItemStackToInventory(new ItemStack(result.getItem(), usesLeft, result.getItemDamage())); + usesLeft = 0; + } + } + } + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_FURNACE_FIRE_CRACKLE, 1, 0.75f); + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + world.spawnParticle(EnumParticleTypes.FLAME, x1, y1, z1, 0, 0.01F, 0); + } + } + + return usesLeft < 5; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java b/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java new file mode 100644 index 00000000..bcb5ce53 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java @@ -0,0 +1,40 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.WizardryGuiHandler; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class PocketWorkbench extends Spell { + + public PocketWorkbench() { + super(Tier.APPRENTICE, 30, Element.SORCERY, "pocket_workbench", SpellType.UTILITY, 40, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // TODO: Investigate possible item duplication bug with this spell. So far I have been unable to recreate it. + if(!world.isRemote){ + caster.openGui(Wizardry.instance, WizardryGuiHandler.PORTABLE_CRAFTING, world, (int)caster.posX, (int)caster.posY, (int)caster.posZ); + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1); + + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Poison.java b/src/main/java/electroblob/wizardry/spell/Poison.java new file mode 100644 index 00000000..9a69bc38 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Poison.java @@ -0,0 +1,108 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class Poison extends Spell { + + public Poison() { + super(Tier.APPRENTICE, 10, Element.EARTH, "poison", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + EntityLivingBase target = (EntityLivingBase) rayTrace.entityHit; + // Has no effect on undead or spiders. + if(MagicDamage.isEntityImmune(DamageType.POISON, target)){ + if(!world.isRemote) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), 1.0f * modifiers.get(SpellModifiers.DAMAGE)); + target.addPotionEffect(new PotionEffect(MobEffects.POISON, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), 1)); + } + } + + if(world.isRemote){ + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + //world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.3f, 0.7f, 0.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.1f, 0.4f, 0.0f); + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + // Has no effect on undead or spiders. + if(!MagicDamage.isEntityImmune(DamageType.POISON, target) && !world.isRemote){ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), 1.0f * modifiers.get(SpellModifiers.DAMAGE)); + target.addPotionEffect(new PotionEffect(MobEffects.POISON, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), 1)); + } + + if(world.isRemote){ + + double dx = (target.posX - caster.posX)/caster.getDistanceToEntity(target); + double dy = (target.posY - caster.posY)/caster.getDistanceToEntity(target); + double dz = (target.posZ - caster.posZ)/caster.getDistanceToEntity(target); + + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + + double x1 = caster.posX + dx*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + dz*i/2 + world.rand.nextFloat()/5 - 0.1f; + + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.3f, 0.7f, 0.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.1f, 0.4f, 0.0f); + } + } + + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/PoisonBomb.java b/src/main/java/electroblob/wizardry/spell/PoisonBomb.java new file mode 100644 index 00000000..3ee00729 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/PoisonBomb.java @@ -0,0 +1,66 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityPoisonBomb; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class PoisonBomb extends Spell { + + public PoisonBomb() { + super(Tier.APPRENTICE, 15, Element.EARTH, "poison_bomb", SpellType.ATTACK, 25, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityPoisonBomb poisonbomb = new EntityPoisonBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + world.spawnEntityInWorld(poisonbomb); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityPoisonBomb poisonbomb = new EntityPoisonBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + poisonbomb.directTowards(target, 1.5f); + world.spawnEntityInWorld(poisonbomb); + } + + caster.swingArm(hand); + caster.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java new file mode 100644 index 00000000..bf9983a6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java @@ -0,0 +1,44 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class ReplenishHunger extends Spell { + + public ReplenishHunger() { + super(Tier.APPRENTICE, 10, Element.HEALING, "replenish_hunger", SpellType.UTILITY, 30, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.getFoodStats().needFood()){ + int foodAmount = (int)(6*modifiers.get(SpellModifiers.DAMAGE)); + // Fixed issue #6: Changed to addStats, since setFoodLevel is client-side only + caster.getFoodStats().addStats(foodAmount, foodAmount*0.1f); + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 0.7f, 0.3f); + } + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/RingOfFire.java b/src/main/java/electroblob/wizardry/spell/RingOfFire.java new file mode 100644 index 00000000..e4f1bd84 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/RingOfFire.java @@ -0,0 +1,68 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityFireRing; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class RingOfFire extends Spell { + + public RingOfFire() { + super(Tier.ADVANCED, 30, Element.FIRE, "ring_of_fire", SpellType.ATTACK, 100, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(caster.onGround){ + if(!world.isRemote){ + EntityFireRing firering = new EntityFireRing(world, caster.posX, caster.posY, caster.posZ, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(firering); + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + if(caster.onGround && world.getEntitiesWithinAABB(EntityFireRing.class, caster.getEntityBoundingBox()).isEmpty()){ + if(!world.isRemote){ + EntityFireRing firering = new EntityFireRing(world, caster.posX, caster.posY, caster.posZ, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(firering); + } + + caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + return true; + } + return false; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/ShadowWard.java b/src/main/java/electroblob/wizardry/spell/ShadowWard.java new file mode 100644 index 00000000..b521db6e --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ShadowWard.java @@ -0,0 +1,39 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.world.World; + +public class ShadowWard extends Spell { + + public ShadowWard() { + super(Tier.ADVANCED, 10, Element.NECROMANCY, "shadow_ward", SpellType.DEFENCE, 0, EnumAction.BLOCK, true); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(world.isRemote){ + double dx = -1 + 2*world.rand.nextFloat(); + double dy = -1 + world.rand.nextFloat(); + double dz = -1 + 2*world.rand.nextFloat(); + world.spawnParticle(EnumParticleTypes.PORTAL, caster.posX, WizardryUtilities.getPlayerEyesPos(caster), caster.posZ, dx, dy, dz); + } + + if(ticksInUse % 50 == 0){ + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_PORTAL_AMBIENT, 0.6f, 1.5f); + } + + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Shield.java b/src/main/java/electroblob/wizardry/spell/Shield.java new file mode 100644 index 00000000..518cbe22 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Shield.java @@ -0,0 +1,42 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.EntityShield; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Shield extends Spell { + + public Shield() { + super(Tier.APPRENTICE, 5, Element.HEALING, "shield", SpellType.DEFENCE, 0, EnumAction.BLOCK, true); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, 10, 0, false, false)); + + if(WizardData.get(caster).shield == null){ + WizardData.get(caster).shield = new EntityShield(world, caster); + if(!world.isRemote){ + world.spawnEntityInWorld(WizardData.get(caster).shield); + } + } + if(ticksInUse == 0){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + } + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Shockwave.java b/src/main/java/electroblob/wizardry/spell/Shockwave.java new file mode 100644 index 00000000..1f48a728 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Shockwave.java @@ -0,0 +1,99 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.EnumAction; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.world.World; + +public class Shockwave extends Spell { + + public Shockwave() { + super(Tier.MASTER, 65, Element.SORCERY, "shockwave", SpellType.ATTACK, 150, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + List targets = WizardryUtilities.getEntitiesWithinRadius(5.0d*modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + + for(EntityLivingBase target : targets){ + if(WizardryUtilities.isValidTarget(caster, target)){ + // Damage increases closer to player up to a maximum of 4 hearts (at 1 block distance). + float damage = Math.min(8.0f/target.getDistanceToEntity(caster), 8.0f); + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.BLAST), damage * modifiers.get(SpellModifiers.DAMAGE)); + + if(!world.isRemote){ + + // Entity speed increases closer to the player to a maximum of 3 (at 1 block distance). + // This is the entity's speed compared to its distance from the player. Used for a similar triangles + // based x, y and z speed calculation. + double velocityFactor = Math.min(5/target.getDistanceSqToEntity(caster), 3.0d); + + double dx = target.posX - caster.posX; + double dy = target.posY + 1 - caster.posY; + double dz = target.posZ - caster.posZ; + + target.motionX = velocityFactor * dx; + target.motionY = velocityFactor * dy; + target.motionZ = velocityFactor * dz; + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + } + } + } + if(world.isRemote){ + + double particleX, particleZ; + for(int i=0;i<40;i++){ + particleX = caster.posX - 1.0d + 2*world.rand.nextDouble(); + particleZ = caster.posZ - 1.0d + 2*world.rand.nextDouble(); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, particleX, WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, + particleX - caster.posX, 0, particleZ - caster.posZ, 30, 0.8f, 0.8f, 1.0f); + particleX = caster.posX - 1.0d + 2*world.rand.nextDouble(); + particleZ = caster.posZ - 1.0d + 2*world.rand.nextDouble(); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, particleX, WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, + particleX - caster.posX, 0, particleZ - caster.posZ, 30, 0.9f, 0.9f, 0.9f); + particleX = caster.posX - 1.0d + 2*world.rand.nextDouble(); + particleZ = caster.posZ - 1.0d + 2*world.rand.nextDouble(); + + IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster); + + if(block != null){ + world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY, particleZ, + particleX - caster.posX, 0, particleZ - caster.posZ, Block.getStateId(block)); + } + } + + world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, caster.posX, caster.getEntityBoundingBox().minY + 0.1, caster.posZ, 0, 0, 0); + + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 1.0f, 0.7f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 2.0f, 0.3f); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/SilverfishSwarm.java b/src/main/java/electroblob/wizardry/spell/SilverfishSwarm.java new file mode 100644 index 00000000..bd7ae7bc --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SilverfishSwarm.java @@ -0,0 +1,47 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntitySilverfishMinion; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SilverfishSwarm extends Spell { + + public SilverfishSwarm() { + super(Tier.MASTER, 80, Element.EARTH, "silverfish_swarm", SpellType.MINION, 300, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + for(int i=0;i<20;i++){ + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); + // The spell instantly fails if no space was found (see javadoc for the above method). + if(pos == null) return false; + + EntitySilverfishMinion silverfish = new EntitySilverfishMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(silverfish); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + // Can't possibly get this far if nothing was spawned. + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SixthSense.java b/src/main/java/electroblob/wizardry/spell/SixthSense.java new file mode 100644 index 00000000..f6505a75 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SixthSense.java @@ -0,0 +1,41 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class SixthSense extends Spell { + + public SixthSense() { + super(Tier.APPRENTICE, 20, Element.EARTH, "sixth_sense", SpellType.UTILITY, 100, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // Cannot be cast when it has already been cast + if(!world.isRemote){ + caster.addPotionEffect(new PotionEffect(WizardryPotions.sixth_sense, (int)(400*modifiers.get(WizardryItems.duration_upgrade)), (int)((modifiers.get(WizardryItems.range_upgrade)-1f)/Constants.RANGE_INCREASE_PER_LEVEL))); + } + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Slime.java b/src/main/java/electroblob/wizardry/spell/Slime.java new file mode 100644 index 00000000..6d9d5346 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Slime.java @@ -0,0 +1,117 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityMagicSlime; +import electroblob.wizardry.registry.WizardryAchievements; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntitySkeleton; +import net.minecraft.entity.monster.EntitySlime; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class Slime extends Spell { + + public Slime() { + super(Tier.ADVANCED, 20, Element.EARTH, "slime", SpellType.ATTACK, 50, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 8*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.entityHit != null && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; + + if(target instanceof EntitySlime){ + if(!world.isRemote) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else if(!(target instanceof EntityMagicSlime)){ + + if(target instanceof EntitySkeleton) caster.addStat(WizardryAchievements.slime_skeleton); + + if(!world.isRemote){ + EntityMagicSlime slime = new EntityMagicSlime(world, caster, target, (int)(200*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(slime); + } + } + } + + if(world.isRemote){ + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + + world.spawnParticle(EnumParticleTypes.SLIME, x1, y1, z1, 0.0d, 0.0d, 0.0d); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.2f, 0.8f, 0.1f); + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SLIME_ATTACK, 1.0F, 0.5F); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null && !(target instanceof EntitySlime) && !(target instanceof EntityMagicSlime)){ + + if(!world.isRemote){ + EntityMagicSlime slime = new EntityMagicSlime(world, caster, target, (int)(200*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(slime); + } + + if(world.isRemote){ + + double dx = (target.posX - caster.posX)/caster.getDistanceToEntity(target); + double dy = (target.posY - caster.posY)/caster.getDistanceToEntity(target); + double dz = (target.posZ - caster.posZ)/caster.getDistanceToEntity(target); + + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + + double x1 = caster.posX + dx*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + dz*i/2 + world.rand.nextFloat()/5 - 0.1f; + + world.spawnParticle(EnumParticleTypes.SLIME, x1, y1, z1, 0.0d, 0.0d, 0.0d); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.2f, 0.8f, 0.1f); + } + } + + caster.swingArm(hand); + caster.playSound(SoundEvents.ENTITY_SLIME_ATTACK, 1.0F, 0.5F); + caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, 1.0F); + return true; + + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SmokeBomb.java b/src/main/java/electroblob/wizardry/spell/SmokeBomb.java new file mode 100644 index 00000000..6a71a532 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SmokeBomb.java @@ -0,0 +1,66 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntitySmokeBomb; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class SmokeBomb extends Spell { + + public SmokeBomb() { + super(Tier.BASIC, 10, Element.FIRE, "smoke_bomb", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntitySmokeBomb smokebomb = new EntitySmokeBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + world.spawnEntityInWorld(smokebomb); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntitySmokeBomb smokebomb = new EntitySmokeBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + smokebomb.directTowards(target, 1.5f); + world.spawnEntityInWorld(smokebomb); + } + + caster.swingArm(hand); + caster.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Snare.java b/src/main/java/electroblob/wizardry/spell/Snare.java new file mode 100644 index 00000000..6d1b4815 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Snare.java @@ -0,0 +1,66 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.tileentity.TileEntityPlayerSave; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class Snare extends Spell { + + public Snare() { + super(Tier.BASIC, 10, Element.EARTH, "snare", SpellType.ATTACK, 10, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.rayTrace(10*modifiers.get(WizardryItems.range_upgrade), world, caster, true); + + // Gets block the player is looking at and places snare + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = rayTrace.getBlockPos(); + + if(rayTrace.sideHit == EnumFacing.UP && world.isSideSolid(pos, EnumFacing.UP) && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + + if(!world.isRemote){ + world.setBlockState(pos.up(), WizardryBlocks.snare.getDefaultState()); + ((TileEntityPlayerSave)world.getTileEntity(pos.up())).setCaster(caster); + } + + double dx = pos.getX() + 0.5 - caster.posX; + double dy = pos.getY() + 1.5 - (caster.posY + caster.height/2); + double dz = pos.getZ() + 0.5 - caster.posZ; + + if(world.isRemote){ + for(int i=1;i<5;i++){ + float brightness = world.rand.nextFloat()/4; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0.0d, 0.0d, 0.0d, 20 + world.rand.nextInt(8), brightness, brightness + 0.1f, 0.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, world, caster.posX + (i*(dx/5)) + world.rand.nextFloat()/5, WizardryUtilities.getPlayerEyesPos(caster) + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + (i*(dz/5)) + world.rand.nextFloat()/5, 0, -0.01, 0, 40 + world.rand.nextInt(10)); + } + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_GRASS_PLACE, 1.0F, world.rand.nextFloat() * 0.4F + 1.2F); + return true; + } + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Snowball.java b/src/main/java/electroblob/wizardry/spell/Snowball.java new file mode 100644 index 00000000..c5aed5ab --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Snowball.java @@ -0,0 +1,41 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntitySnowball; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Snowball extends Spell { + + public Snowball() { + super(Tier.BASIC, 1, Element.ICE, "snowball", SpellType.ATTACK, 1, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntitySnowball snowball = new EntitySnowball(world, caster); + snowball.setHeadingFromThrower(caster, caster.rotationPitch, caster.rotationYaw, 0.0f, 1.5f, 1.0f); + world.spawnEntityInWorld(snowball); + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + caster.swingArm(hand); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/SparkBomb.java b/src/main/java/electroblob/wizardry/spell/SparkBomb.java new file mode 100644 index 00000000..e0c55295 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SparkBomb.java @@ -0,0 +1,66 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntitySparkBomb; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class SparkBomb extends Spell { + + public SparkBomb() { + super(Tier.APPRENTICE, 15, Element.LIGHTNING, "spark_bomb", SpellType.ATTACK, 25, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntitySparkBomb sparkBomb = new EntitySparkBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + world.spawnEntityInWorld(sparkBomb); + } + + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntitySparkBomb sparkBomb = new EntitySparkBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), modifiers.get(WizardryItems.blast_upgrade)); + sparkBomb.directTowards(target, 1.5f); + world.spawnEntityInWorld(sparkBomb); + } + + caster.swingArm(hand); + caster.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SpectralPathway.java b/src/main/java/electroblob/wizardry/spell/SpectralPathway.java new file mode 100644 index 00000000..f544ffb3 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpectralPathway.java @@ -0,0 +1,80 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.tileentity.TileEntityTimer; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumFacing.AxisDirection; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SpectralPathway extends Spell { + + public SpectralPathway() { + super(Tier.ADVANCED, 40, Element.SORCERY, "spectral_pathway", SpellType.UTILITY, 300, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // Won't work if caster is airborne or if they are already on a bridge (prevents infinite bridges) + if(WizardryUtilities.getBlockEntityIsStandingOn(caster).getBlock() == Blocks.AIR + || WizardryUtilities.getBlockEntityIsStandingOn(caster).getBlock() == WizardryBlocks.spectral_block){ + return false; + } + + EnumFacing direction = caster.getHorizontalFacing(); + + boolean flag = false; + + if(!world.isRemote){ + + int baseLength = 15; + + // Gets the coordinates of the nearest block intersection to the player's feet. + // Remember that a block always takes the coordinates of its northwestern corner. + BlockPos origin = new BlockPos(Math.round(caster.posX), (int)caster.getEntityBoundingBox().minY-1, Math.round(caster.posZ)); + + int startPoint = direction.getAxisDirection() == AxisDirection.POSITIVE ? -1 : 0; + + for(int i=0; i<(int)(baseLength*modifiers.get(WizardryItems.range_upgrade)); i++){ + // If either a block gets placed or one has already been placed, flag is set to true. + flag = placePathwayBlockIfPossible(world, origin.offset(direction, startPoint + i), modifiers.get(WizardryItems.duration_upgrade)) || flag; + flag = placePathwayBlockIfPossible(world, origin.offset(direction, startPoint + i) + // Moves the BlockPos minus one block perpendicular to direction. + .offset(EnumFacing.getFacingFromAxis(AxisDirection.NEGATIVE, direction.rotateY().getAxis())), modifiers.get(WizardryItems.duration_upgrade)) || flag; + } + } + // TODO: There may be some client/server discrepancies here. + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION_LARGE, 1.0f, 1.0f); + + return flag; + } + + private static boolean placePathwayBlockIfPossible(World world, BlockPos pos, float durationMultiplier){ + if(WizardryUtilities.canBlockBeReplacedB(world, pos)){ + world.setBlockState(pos, WizardryBlocks.spectral_block.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityTimer){ + ((TileEntityTimer)world.getTileEntity(pos)).setLifetime((int)(1200*durationMultiplier)); + } + return true; + } + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Spell.java b/src/main/java/electroblob/wizardry/spell/Spell.java new file mode 100644 index 00000000..594f1ef2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Spell.java @@ -0,0 +1,424 @@ +package electroblob.wizardry.spell; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.registry.IForgeRegistry; +import net.minecraftforge.fml.common.registry.IForgeRegistryEntry; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** + * Generic spell class which is the superclass to all spells in wizardry. When extending this class, you must do + * the following: + *

    + * - Have a constructor which passes all necessary constants into the super constructor. I define the constants here + * so that the constructor for an individual spell has no parameters, but you may prefer to pass in the parameters when + * the spell is registered, so all the mana costs etc. are in one place like a sort of sandbox. + *

    + * - Implement the {@link Spell#cast(World, EntityPlayer, EnumHand, int, SpellModifiers)} method, in which you should + * execute the code that makes the spell work, and return true or false depending on whether the spell succeeded and + * therefore whether mana should be used up. + *

    + * - Register the spell using {@link RegistryEvent.Register}, with {@link Spell} as the type parameter. Each spell + * should have a single instance, like blocks and items. + * As of Wizardry 2.1, spells use the Forge registry system. Related methods such as {@link Spell#id()} and + * {@link Spell#get(int)} have been re-routed to use this system, leaving minimal external changes. Note also that + * the constructor automatically sets the registry name for you, though you may change it afterwards if necessary. + *

    + * Also note that you can override some other methods from this class. For example, to add a + * specific kind of formatting to a spell name or description, you can override {@link Spell#getDisplayName()}, + * {@link Spell#getDisplayNameWithFormatting()} or {@link Spell#getDescription()} and append the formatting code (though + * you will have to call super() to get the name itself, since the unlocalised name is private). See + * {@link SummonShadowWraith#getDescription()} for an example. + *


    + * This class is also home to some useful static methods for interacting with the spell registry:

    + * {@link Spell#get(int)} gets a spell instance from its integer id, which corresponds to the metadata of its spell book.
    + * {@link Spell#get(String)} gets a spell instance from its unlocalised name.
    + * {@link Spell#getSpells(Predicate)} returns a list of spell instances the match the given {@link Predicate}.
    + * {@link Spell#getTotalSpellCount()} returns the total number of registered spells. + *


    + * Spell implements the {@link Comparable} interface, and as such, any collection of spells can be sorted. Spells are + * sorted by increasing tier (see {@link Tier}), from novice to master. Within each tier, spells are sorted by element, + * the order of which is as defined in {@link Element} (i.e. magic, fire, ice, lightning, necromancy, earth, sorcery, healing). + *
    + * @since Wizardry 1.0 + * @see electroblob.wizardry.item.ItemSpellBook ItemSpellBook + * @see electroblob.wizardry.item.ItemScroll ItemScroll + * @see Spells + */ +public abstract class Spell extends IForgeRegistryEntry.Impl implements Comparable { + + /** Forge registry-based replacement for the internal spells list. */ + public static IForgeRegistry registry; + + /** The tier this spell belongs to. */ + public final Tier tier; + /** Mana cost of the spell. If it is a continuous spell the cost is per second. */ + public final int cost; + /** The element this spell belongs to. */ + public final Element element; + /** The unlocalised name of the spell. */ + private final String unlocalisedName; + /** The type of spell this is classified as. */ + public final SpellType type; + /** Cooldown for the spell in ticks */ + public final int cooldown; + /** The action the player does when this spell is cast. */ + public final EnumAction action; + /** Whether or not the spell is continuous (keeps going as long as the mouse button is held) */ + public final boolean isContinuous; + + /** ResourceLocation of the spell icon. */ + private final ResourceLocation icon; + /** Mod ID of the mod that added this spell; defaults to {@link Wizardry#MODID} if not specified. */ + private final String modID; + + /** False if the spell has been disabled in the config file, true otherwise. This is now encapsulated to stop it + * being fiddled with. */ + private boolean isEnabled = true; + + /** + * This constructor should be called from any subclasses, either feeding in the constants directly or through + * their own constructor from wherever the spell is registered. This is the constructor for wizardry's own spells; + * spells added by other mods should use {@link Spell#Spell(Tier, int, Element, String, SpellType, int, EnumAction, boolean, String)}. + * @param tier The tier this spell belongs to. + * @param cost The amount of mana used to cast the spell. If this is a continuous spell, it represents mana cost + * per second and should be a multiple of 5. + * @param element The element this spell belongs to. + * @param name The registry name of the spell. This will also be the name of the icon file. The spell's + * unlocalised name will be a resource location with the format [modid]:[name]. + * @param cooldown The cooldown time for this spell in ticks. + * @param action The vanilla usage action to be displayed when casting this spell. + * @param isContinuous Whether this spell is continuous, meaning you cast it for a length of time by holding the + * right mouse button. + */ + public Spell(Tier tier, int cost, Element element, String name, SpellType type, int cooldown, EnumAction action, boolean isContinuous){ + this(tier, cost, element, name, type, cooldown, action, isContinuous, Wizardry.MODID); + } + + /** + * This constructor should be called from any subclasses, either feeding in the constants directly or through + * their own constructor from wherever the spell is registered. + * @param tier The tier this spell belongs to. + * @param cost The amount of mana used to cast the spell. If this is a continuous spell, it represents mana cost + * per second and should be a multiple of 5. + * @param element The element this spell belongs to. + * @param name The registry name of the spell, excluding the mod id. This will also be the name of the icon + * file. The spell's unlocalised name will be a resource location with the format [modid]:[name]. + * @param cooldown The cooldown time for this spell in ticks. + * @param action The vanilla usage action to be displayed when casting this spell (see {@link}EnumAction) + * @param isContinuous Whether this spell is continuous, meaning you cast it for a length of time by holding the + * right mouse button. + * @param modID The mod id of the mod that added this spell. This allows wizardry to use the correct file + * path for the spell icon, and also more generally to distinguish between original and addon spells. + */ + public Spell(Tier tier, int cost, Element element, String name, SpellType type, int cooldown, EnumAction action, boolean isContinuous, String modID){ + this.tier = tier; + this.cost = cost; + this.element = element; + this.type = type; + this.cooldown = cooldown; + this.action = action; + this.isContinuous = isContinuous; + this.modID = modID; + this.setRegistryName(modID, name); + this.unlocalisedName = this.getRegistryName().toString(); + this.icon = new ResourceLocation(this.modID, "textures/spells/" + name + ".png"); + } + + /** + * Casts the spell. Each subclass must override this method and within it execute the code to make the spell work. + * Returns a boolean so that the main onItemRightClick or onUsingItemTick method can check if the spell + * was actually cast or whether a spell specific condition caused it not to be (for example, heal won't work if the player is on + * full health), preventing unfair drain of mana. + *

    + * Each spell must return true when it works or the spell will not use up mana. Note that (!world.isRemote) does not count + * as a condition; return true should be outside it - in other words, return a value on both the client and the server. + *

    + * It's worth noting that on the client side, this method only gets called if the server side + * cast() method succeeded, so you can put any particle spawning code outside of any success conditions if there + * are discrepancies between client and server. + * @param world A reference to the world object. Again this is for convenience, you can also use caster.worldObj. + * @param caster The EntityPlayer that cast the spell. + * @param hand The hand that is holding the item used to cast the spell. If no item was used, this will be the main hand. + * @param ticksInUse The number of ticks the spell has already been cast for. For all non-continuous spells, this is 0 and + * is not used. For continuous spells, it is passed in as the maximum use duration of the item minus the count parameter in + * onUsingItemTick and therefore it increases by 1 each tick. + * @param modifiers A {@link SpellModifiers} object containing the modifiers that have been applied to the spell. See + * the javadoc for that class for more information. If no modifiers are required, pass in {@code new SpellModifiers()}. + * @return True if the spell succeeded and mana should be used up, false if not. + */ + public abstract boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers); + + /** Casts the spell, but with an EntityLiving as the caster. Each subclass can optionally override this method and + * within it execute the code to make the spell work. Returns a boolean to allow whatever calls this method to check if the spell + * was actually cast or whether a spell specific condition caused it not to be (for example, heal won't work if the caster is on + * full health). + *

    + * This method is intended for use by NPCs (see {@link EntityWizard}) so that they can cast spells. Override it if you want + * a spell to be cast by wizards. Note that you must also override {@link Spell#canBeCastByNPCs()} to return true to allow wizards + * to select the spell. For some spells, this method may well be exactly the same as the regular cast method; for + * others it won't be - for example, projectile-based spells are normally done using the player's look vector, but + * NPCs need to use a target-based method instead. + *

    + * Each spell must return true when it works. Note that (!world.isRemote) does not count as a condition; return true should be outside + * it - in other words, return a value on both the client and the server. + *

    + * It's worth noting that on the client side, this method only gets called if the server side + * cast() method succeeded, so you can put any particle spawning code outside of any success conditions if there + * are discrepancies between client and server. + * @param world A reference to the world object. This is for convenience, you can also use caster.worldObj. + * @param caster The EntityLiving that cast the spell. + * @param hand The hand that is holding the item used to cast the spell. This will almost certainly be the main hand. + * @param ticksInUse The number of ticks the spell has already been cast for. For all non-continuous spells, this is 0 and + * is not used. + * @param target The EntityLivingBase that is targeted by the spell. May be null in some cases. + * @param modifiers A {@link SpellModifiers} object containing the modifiers that have been applied to the spell. See + * the javadoc for that class for more information. If no modifiers are required, pass in {@code new SpellModifiers()}. + * @return True if the spell succeeded, false if not. Returns false by default. + */ + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + return false; + } + + /** Whether NPCs such as wizards can cast this spell. If you have overridden {@link Spell#cast(World, EntityLiving, EnumHand, int, EntityLivingBase, SpellModifiers)}, + * you should override this to return true. */ + public boolean canBeCastByNPCs(){ + return false; + } + + /** Whether this spell requires a packet to be sent when it is cast. Returns true by default, but can be overridden + * to return false if the spell's cast() method does not use any code that must be executed client-side (i.e. + * particle spawning). Does nothing for continuous spells, because they never need to send packets. + *

    + * If in doubt, leave this method as is; it is purely an optimisation. + * @return false if the spell code should only be run on the server and the client of the player casting it
    + * true if the spell code should be run on the server and all clients in the dimension */ + // Edit: Turns out that swingItem() actually sends packets to all nearby clients, but not the client doing the swinging. + // Also, now I think about it, this method isn't going to make the slightest bit of difference to the item usage + // actions since setItemInUse() is called in ItemWand, not the spell class - so the only thing that matters here is + // the particles. + public boolean doesSpellRequirePacket(){ + return true; + } + + /** Returns this spell's id number, which now corresponds to its position in the spell registry. + * Returns -1 if the spell has not been registered. */ + // This is final so nothing can override it, because that would cause all kinds of problems! + public final int id(){ + return registry.getValues().indexOf(this); + } + + /** Returns the mod ID for this spell, which should be the ID of the mod that added it. The mod ID is + * used to tell wizardry which filepath to use for the spell's icon. As of Wizardry 1.2, the field itself is + * private, but this getter is provided for external use (though it is never called in the main Wizardry mod). */ + public final String getModID(){ + return modID; + } + + /** Returns the ResourceLocation for this spell's icon. */ + public final ResourceLocation getIcon(){ + return icon; + } + + /** Returns the unlocalised name of the spell, without any prefixes or suffixes, e.g. "flame_ray". This should + * only be used for translation purposes. */ + public final String getUnlocalisedName(){ + return unlocalisedName; + } + + /* The general idea with translation is to use net.minecraft.client.resources.I18n directly on the client side (and + * just prepend formatting codes where necessary), and to use TextComponentTranslation on the server (setting the + * style as necessary). TextComponentTranslation effectively stores what needs to be translated, without actually + * translating it. If, for whatever reason, you need to supply an ITextComponent but don't want it translated + * (perhaps a name?), you can use TextComponentString, which will simply keep the raw string it is given. */ + + /** Returns the translated display name of the spell, without formatting (i.e. not coloured). Client-side only! + * On the server side, use {@link TextComponentTranslation} (see {@link Spell#getNameForTranslation()}). */ + @SideOnly(Side.CLIENT) + public String getDisplayName(){ + return net.minecraft.client.resources.I18n.format("spell." + unlocalisedName); + } + + /** Returns a {@code TextComponentTranslation} which will be translated to the display name of the spell, without + * formatting (i.e. not coloured). */ + public TextComponentTranslation getNameForTranslation(){ + return new TextComponentTranslation("spell." + unlocalisedName); + } + + /** Returns the translated display name of the spell, with formatting (i.e. coloured). Client-side only! + * On the server side, use {@link TextComponentTranslation} (see {@link Spell#getNameForTranslationFormatted()}). */ + @SideOnly(Side.CLIENT) + public String getDisplayNameWithFormatting(){ + return this.element.getFormattingCode() + net.minecraft.client.resources.I18n.format("spell." + unlocalisedName); + } + + /** Returns a {@code TextComponentTranslation} which will be translated to the display name of the spell, with + * formatting (i.e. coloured). */ + public ITextComponent getNameForTranslationFormatted(){ + return new TextComponentTranslation("spell." + unlocalisedName).setStyle(this.element.getColour()); + } + + /** Returns the translated description of the spell, without formatting. Client-side only! You should not + * need to use this on the server side. */ + @SideOnly(Side.CLIENT) + public String getDescription(){ + return net.minecraft.client.resources.I18n.format("spell." + unlocalisedName + ".desc"); + } + + /** Returns whether the spell is enabled in the config. */ + public final boolean isEnabled() { + return isEnabled; + } + + /** Sets whether the spell is enabled or not. */ + public final void setEnabled(boolean isEnabled) { + this.isEnabled = isEnabled; + } + + // Spells are sorted according to tier and element. Where several spells have the same tier and element, + // they will remain in the order they were registered. + @Override + public final int compareTo(Spell spell){ + + if(this.tier.ordinal() > spell.tier.ordinal()){ + return 1; + }else if(this.tier.ordinal() < spell.tier.ordinal()){ + return -1; + }else{ + if(this.element.ordinal() > spell.element.ordinal()){ + return 1; + }else if(this.element.ordinal() < spell.element.ordinal()){ + return -1; + }else{ + return 0; + } + } + } + + // ================================================ Static methods ================================================== + + /** Returns the total number of registered spells, excluding the 'None' spell. Returns the same number that would + * be returned by Spell.getSpells(Spell.allSpells).size(), but this method is more efficient. */ + public static int getTotalSpellCount(){ + return registry.getValues().size() - 1; + } + + /** Gets a spell instance from its integer id, which now corresponds to its id in the spell registry. + * If the given id has no spell (i.e. is less than 0 or greater than the total number of spells - 1) + * then it will return the {@link None} spell. + *

    + * If you are calling this from inside a loop in which you are iterating through the spells, there is + * probably a better way; see {@link Spell#getSpells(Predicate)}. */ + public static Spell get(int id){ + if(id < 0 || id >= registry.getValues().size()){ + return Spells.none; + } + Spell spell = registry.getValues().get(id); + return spell == null ? Spells.none : spell; + } + + /** Returns the spell with the given registry name, or null if no such spell exists. + * @param name The registry name of the spell, in the form [mod id]:[spell name]. If no mod id is specified, it + * defaults to {@link Wizardry#MODID}. */ + public static Spell get(String name){ + ResourceLocation key = new ResourceLocation(name); + if(key.getResourceDomain().equals("minecraft")) key = new ResourceLocation(Wizardry.MODID, name); + return registry.getValue(key); + } + + /** Returns a list of all registered spells' registry names, excluding the 'none' spell. Used in commands. */ + public static String[] getSpellNames(){ + // Maybe it would be better to store all of this statically? + Set keys = new HashSet(registry.getKeys()); + keys.remove(registry.getKey(Spells.none)); + // Streams! + return keys.stream().map(ResourceLocation::toString).toArray(String[]::new); + } + + /** + * Returns a list containing all spells matching the given {@link Predicate}. The returned list is separate from the + * internal spells list; any changes you make to the returned list will have no effect on wizardry since the + * returned list is local to this method. Never includes the {@link None} spell. For convenience, there are some + * predefined predicates in the Spell class (some of these really aren't shortcuts any more): + *

    + * {@link Spell#allSpells} will allow all spells to be returned
    + * {@link Spell#enabledSpells} will filter out any spells that are disabled in the config
    + * {@link Spell#npcSpells} will only allow enabled spells that can be cast by NPCs (see {@link Spell#canBeCastByNPCs()})
    + * {@link Spell#nonContinuousSpells} will filter out continuous spells but not disabled spells
    + * {@link Spell.TierElementFilter} will only allow enabled spells of the specified tier and element + * + * @param filter A Predicate<Spell> that the returned spells must satisfy. + * + * @return A local, modifiable list of spells matching the given predicate. Note that this list may be empty. + * */ + public static List getSpells(Predicate filter){ + + ArrayList spells = new ArrayList(1); + + for(Spell spell : registry.getValues()){ + if(filter.test(spell) && spell != Spells.none) spells.add(spell); + } + + return spells; + } + + /** Predicate which allows all spells. */ + public static Predicate allSpells = s -> true; + + /** Predicate which allows all enabled spells. */ + public static Predicate enabledSpells = Spell::isEnabled; + + /** Predicate which allows all non-continuous spells, even those that have been disabled. */ + public static Predicate nonContinuousSpells = s -> !s.isContinuous; + + /** Predicate which allows all enabled spells for which {@link Spell#canBeCastByNPCs()} returns true. */ + public static Predicate npcSpells = s -> s.isEnabled() && s.canBeCastByNPCs(); + + /** Predicate which allows all enabled spells of the given tier and element (create an instance of this class + * each time you want to use it). This is somewhat useless now that Wizardry uses Java 8, but it is more readable + * than a lambda expression and you don't need to remember to check that the spell is enabled every time. */ + public static class TierElementFilter implements Predicate { + + private Tier tier; + private Element element; + + /** + * Creates a new TierElementFilter that checks for the given tier and element. Does not allow spells that have + * been disabled in the config. + * @param tier The EnumTier to check for. Pass in null to allow all tiers. + * @param element The EnumElement to check for. Pass in null to allow all elements. + */ + public TierElementFilter(Tier tier, Element element){ + this.tier = tier; + this.element = element; + } + + @Override + public boolean test(Spell spell) { + return spell.isEnabled() && (this.tier == null || spell.tier == this.tier) + && (this.element == null || spell.element == this.element); + } + }; +} diff --git a/src/main/java/electroblob/wizardry/spell/SpiderSwarm.java b/src/main/java/electroblob/wizardry/spell/SpiderSwarm.java new file mode 100644 index 00000000..a7c6a90a --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpiderSwarm.java @@ -0,0 +1,72 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntitySpiderMinion; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SpiderSwarm extends Spell { + + public SpiderSwarm() { + super(Tier.ADVANCED, 45, Element.EARTH, "spider_swarm", SpellType.MINION, 200, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + for(int i=0;i<5;i++){ + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); + // The spell instantly fails if no space was found (see javadoc for the above method). + if(pos == null) return false; + + EntitySpiderMinion spider = new EntitySpiderMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(spider); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + // Can't possibly get this far if nothing was spawned. + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers) { + + if(!world.isRemote){ + for(int i=0;i<5;i++){ + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); + // The spell instantly fails if no space was found (see javadoc for the above method). + if(pos == null) return false; + + EntitySpiderMinion spider = new EntitySpiderMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(spider); + } + } + + caster.playSound(SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + // Can't possibly get this far if nothing was spawned. + return true; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } +} diff --git a/src/main/java/electroblob/wizardry/spell/StaticAura.java b/src/main/java/electroblob/wizardry/spell/StaticAura.java new file mode 100644 index 00000000..851c260f --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/StaticAura.java @@ -0,0 +1,67 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class StaticAura extends Spell { + + public StaticAura() { + super(Tier.ADVANCED, 40, Element.LIGHTNING, "static_aura", SpellType.DEFENCE, 250, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + // Cannot be cast when it has already been cast + if(!caster.isPotionActive(WizardryPotions.static_aura)){ + if(!world.isRemote){ + caster.addPotionEffect(new PotionEffect(WizardryPotions.static_aura, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers) { + + if(target != null){ + // Cannot be cast when it has already been cast + if(!caster.isPotionActive(WizardryPotions.static_aura)){ + if(!world.isRemote){ + caster.addPotionEffect(new PotionEffect(WizardryPotions.static_aura, (int)(600*modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + caster.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); + return true; + } + return false; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs() { + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonBlaze.java b/src/main/java/electroblob/wizardry/spell/SummonBlaze.java new file mode 100644 index 00000000..3882eae8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonBlaze.java @@ -0,0 +1,67 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityBlazeMinion; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonBlaze extends Spell { + + public SummonBlaze() { + super(Tier.ADVANCED, 40, Element.FIRE, "summon_blaze", SpellType.MINION, 200, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityBlazeMinion blaze = new EntityBlazeMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(blaze); + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityBlazeMinion blaze = new EntityBlazeMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(blaze); + } + + caster.playSound(SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java b/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java new file mode 100644 index 00000000..26e986f8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java @@ -0,0 +1,51 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityIceGiant; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonIceGiant extends Spell { + + public SummonIceGiant() { + super(Tier.MASTER, 100, Element.ICE, "summon_ice_giant", SpellType.MINION, 400, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + if(!world.isRemote){ + + EntityIceGiant icegiant = new EntityIceGiant(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(icegiant); + } + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)pos.getX() + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)pos.getY() + 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)pos.getZ() + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0, 0, 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.1F + 0.2F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonIceWraith.java b/src/main/java/electroblob/wizardry/spell/SummonIceWraith.java new file mode 100644 index 00000000..6f914344 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonIceWraith.java @@ -0,0 +1,66 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityIceWraith; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonIceWraith extends Spell { + + public SummonIceWraith() { + super(Tier.ADVANCED, 40, Element.ICE, "summon_ice_wraith", SpellType.MINION, 200, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityIceWraith iceWraith = new EntityIceWraith(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(iceWraith); + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityIceWraith iceWraith = new EntityIceWraith(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(iceWraith); + } + caster.playSound(SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java new file mode 100644 index 00000000..4f510f4d --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java @@ -0,0 +1,50 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.monster.EntityIronGolem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonIronGolem extends Spell { + + public SummonIronGolem() { + super(Tier.MASTER, 175, Element.SORCERY, "summon_iron_golem", SpellType.MINION, 400, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + if(!world.isRemote){ + EntityIronGolem golem = new EntityIronGolem(world); + golem.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + world.spawnEntityInWorld(golem); + } + + for(int i=0; i<10; i++){ + double x1 = (double)((float)pos.getX() + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)pos.getY() + 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)pos.getZ() + world.rand.nextFloat()*2 - 1.0F); + if(world.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0, 0, 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); + } + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonLightningWraith.java b/src/main/java/electroblob/wizardry/spell/SummonLightningWraith.java new file mode 100644 index 00000000..6c74adf1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonLightningWraith.java @@ -0,0 +1,65 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityLightningWraith; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonLightningWraith extends Spell { + + public SummonLightningWraith() { + super(Tier.ADVANCED, 40, Element.LIGHTNING, "summon_lightning_wraith", SpellType.MINION, 200, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityLightningWraith lightningWraith = new EntityLightningWraith(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(lightningWraith); + } + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityLightningWraith lightningWraith = new EntityLightningWraith(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(lightningWraith); + } + caster.playSound(SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonPhoenix.java b/src/main/java/electroblob/wizardry/spell/SummonPhoenix.java new file mode 100644 index 00000000..5dc24a07 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonPhoenix.java @@ -0,0 +1,46 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityPhoenix; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonPhoenix extends Spell { + + public SummonPhoenix() { + super(Tier.MASTER, 150, Element.FIRE, "summon_phoenix", SpellType.MINION, 400, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityPhoenix phoenix = new EntityPhoenix(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, + (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(phoenix); + } + + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java b/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java new file mode 100644 index 00000000..621cfeab --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java @@ -0,0 +1,51 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityShadowWraith; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class SummonShadowWraith extends Spell { + + public SummonShadowWraith() { + super(Tier.MASTER, 100, Element.NECROMANCY, "summon_shadow_wraith", SpellType.MINION, 400, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityShadowWraith shadowWraith = new EntityShadowWraith(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(shadowWraith); + } + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @SideOnly(Side.CLIENT) + @Override + public String getDescription(){ + return "\u00A7k" + super.getDescription(); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java b/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java new file mode 100644 index 00000000..7c086e9f --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java @@ -0,0 +1,72 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntitySkeletonMinion; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonSkeleton extends Spell { + + public SummonSkeleton() { + super(Tier.APPRENTICE, 15, Element.NECROMANCY, "summon_skeleton", SpellType.MINION, 50, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); + skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); + world.spawnEntityInWorld(skeleton); + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); + skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); + world.spawnEntityInWorld(skeleton); + } + caster.playSound(WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); + return true; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java b/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java new file mode 100644 index 00000000..69a373ff --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java @@ -0,0 +1,75 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntitySkeletonMinion; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.init.SoundEvents; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonSkeletonLegion extends Spell { + + public SummonSkeletonLegion() { + super(Tier.MASTER, 100, Element.NECROMANCY, "summon_skeleton_legion", SpellType.MINION, 400, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + // Archers + for(int i=0;i<3;i++){ + // This is all so much neater now thanks to this method. + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); + // The spell instantly fails if no space was found (see javadoc for the above method). + if(pos == null) return false; + + EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(1200*modifiers.get(WizardryItems.duration_upgrade))); + skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); + skeleton.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(Items.CHAINMAIL_HELMET)); + skeleton.setItemStackToSlot(EntityEquipmentSlot.CHEST, new ItemStack(Items.CHAINMAIL_CHESTPLATE)); + skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); + skeleton.setDropChance(EntityEquipmentSlot.HEAD, 0.0f); + skeleton.setDropChance(EntityEquipmentSlot.CHEST, 0.0f); + world.spawnEntityInWorld(skeleton); + } + // Swordsmen + for(int i=0;i<3;i++){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); + // The spell instantly fails if no space was found (see javadoc for the above method). + if(pos == null) return false; + + EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(1200*modifiers.get(WizardryItems.duration_upgrade))); + skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.IRON_SWORD)); + skeleton.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(Items.CHAINMAIL_HELMET)); + skeleton.setItemStackToSlot(EntityEquipmentSlot.CHEST, new ItemStack(Items.CHAINMAIL_CHESTPLATE)); + skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); + skeleton.setDropChance(EntityEquipmentSlot.HEAD, 0.0f); + skeleton.setDropChance(EntityEquipmentSlot.CHEST, 0.0f); + world.spawnEntityInWorld(skeleton); + } + } + + // Can't possibly get this far if nothing was spawned. + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java new file mode 100644 index 00000000..7867c74a --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java @@ -0,0 +1,48 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.monster.EntitySnowman; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonSnowGolem extends Spell { + + public SummonSnowGolem() { + super(Tier.APPRENTICE, 15, Element.ICE, "summon_snow_golem", SpellType.MINION, 20, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + if(!world.isRemote){ + EntitySnowman snowman = new EntitySnowman(world); + snowman.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + world.spawnEntityInWorld(snowman); + } + for(int i=0; i<10; i++){ + double x1 = (double)((float)pos.getX() + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)pos.getY() + 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)pos.getZ() + world.rand.nextFloat()*2 - 1.0F); + if(world.isRemote){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); + } + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java b/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java new file mode 100644 index 00000000..277bc15c --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java @@ -0,0 +1,53 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntitySpiritHorse; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonSpiritHorse extends Spell { + + public SummonSpiritHorse() { + super(Tier.ADVANCED, 50, Element.EARTH, "summon_spirit_horse", SpellType.MINION, 150, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + WizardData properties = WizardData.get(caster); + + if(!properties.hasSpiritHorse){ + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntitySpiritHorse horse = new EntitySpiritHorse(world); + horse.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + horse.setTamedBy(caster); + horse.setHorseSaddled(true); + world.spawnEntityInWorld(horse); + } + properties.hasSpiritHorse = true; + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + return false; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java b/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java new file mode 100644 index 00000000..a7285484 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java @@ -0,0 +1,52 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntitySpiritWolf; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonSpiritWolf extends Spell { + + public SummonSpiritWolf() { + super(Tier.APPRENTICE, 25, Element.EARTH, "summon_spirit_wolf", SpellType.MINION, 100, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + WizardData properties = WizardData.get(caster); + + if(!properties.hasSpiritWolf){ + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntitySpiritWolf wolf = new EntitySpiritWolf(world); + wolf.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + wolf.setTamed(true); + wolf.setOwnerId(caster.getUniqueID()); + world.spawnEntityInWorld(wolf); + } + properties.hasSpiritWolf = true; + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonStormElemental.java b/src/main/java/electroblob/wizardry/spell/SummonStormElemental.java new file mode 100644 index 00000000..2e61aa45 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonStormElemental.java @@ -0,0 +1,42 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityStormElemental; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonStormElemental extends Spell { + + public SummonStormElemental() { + super(Tier.MASTER, 100, Element.LIGHTNING, "summon_storm_elemental", SpellType.MINION, 400, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityStormElemental stormElemental = new EntityStormElemental(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(stormElemental); + } + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java b/src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java new file mode 100644 index 00000000..d8b6c22a --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java @@ -0,0 +1,75 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntitySkeletonMinion; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.SkeletonType; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonWitherSkeleton extends Spell { + + public SummonWitherSkeleton() { + super(Tier.ADVANCED, 35, Element.NECROMANCY, "summon_wither_skeleton", SpellType.MINION, 150, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + skeleton.setSkeletonType(SkeletonType.WITHER); + skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.STONE_SWORD)); + skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); + world.spawnEntityInWorld(skeleton); + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + skeleton.setSkeletonType(SkeletonType.WITHER); + skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.STONE_SWORD)); + skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); + world.spawnEntityInWorld(skeleton); + } + caster.playSound(WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); + return true; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonZombie.java b/src/main/java/electroblob/wizardry/spell/SummonZombie.java new file mode 100644 index 00000000..21718a87 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonZombie.java @@ -0,0 +1,64 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.EntityZombieMinion; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SummonZombie extends Spell { + + public SummonZombie() { + super(Tier.BASIC, 10, Element.NECROMANCY, "summon_zombie", SpellType.MINION, 40, EnumAction.BOW, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + EntityZombieMinion zombie = new EntityZombieMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(zombie); + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(!world.isRemote){ + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntityZombieMinion zombie = new EntityZombieMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, (int)(600*modifiers.get(WizardryItems.duration_upgrade))); + world.spawnEntityInWorld(zombie); + } + caster.playSound(WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); + return true; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Telekinesis.java b/src/main/java/electroblob/wizardry/spell/Telekinesis.java new file mode 100644 index 00000000..d46608ea --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Telekinesis.java @@ -0,0 +1,114 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class Telekinesis extends Spell { + + public Telekinesis() { + super(Tier.BASIC, 5, Element.SORCERY, "telekinesis", SpellType.UTILITY, 5, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 8*modifiers.get(WizardryItems.range_upgrade), 3.0f); + + if(rayTrace != null && rayTrace.entityHit != null){ + + if(rayTrace.entityHit instanceof EntityItem){ + + Entity entityHit = rayTrace.entityHit; + entityHit.motionX = (caster.posX - entityHit.posX)/6; + entityHit.motionY = (caster.posY + caster.eyeHeight - entityHit.posY)/6; + entityHit.motionZ = (caster.posZ - entityHit.posZ)/6; + entityHit.playSound(WizardrySounds.SPELL_CONJURATION, 1.0F, 1.0f); + caster.swingArm(hand); + return true; + + }else if(rayTrace.entityHit instanceof EntityPlayer && Wizardry.settings.telekineticDisarmament){ + + EntityPlayer target = (EntityPlayer)rayTrace.entityHit; + + if(target.getHeldItemMainhand() != null){ + + if(!world.isRemote){ + EntityItem item = target.entityDropItem(target.getHeldItemMainhand(), 0.0f); + // Makes the item move towards the caster + item.motionX = (caster.posX - target.posX)/20; + item.motionZ = (caster.posZ - target.posZ)/20; + } + + target.setHeldItem(EnumHand.MAIN_HAND, null); + + target.playSound(WizardrySounds.SPELL_CONJURATION, 1.0F, 1.0f); + caster.swingArm(hand); + return true; + } + } + } + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + IBlockState blockstate = world.getBlockState(new BlockPos(rayTrace.getBlockPos())); + + if(blockstate.getBlock().onBlockActivated(world, rayTrace.getBlockPos(), blockstate, caster, hand, null, rayTrace.sideHit, 0, 0, 0)){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0F, 1.0f); + caster.swingArm(hand); + return true; + } + } + return false; + } + + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target instanceof EntityPlayer && target.getHeldItemMainhand() != null){ + + // IDEA: Disarm the offhand if the mainhand is empty or otherwise harmless? + + if(!world.isRemote){ + EntityItem item = target.entityDropItem(target.getHeldItemMainhand(), 0.0f); + // Makes the item move towards the caster + item.motionX = (caster.posX - target.posX)/20; + item.motionZ = (caster.posZ - target.posZ)/20; + } + + target.setHeldItem(EnumHand.MAIN_HAND, null); + + target.playSound(WizardrySounds.SPELL_CONJURATION, 1.0F, 1.0f); + caster.swingArm(hand); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Thunderbolt.java b/src/main/java/electroblob/wizardry/spell/Thunderbolt.java new file mode 100644 index 00000000..a146975f --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Thunderbolt.java @@ -0,0 +1,65 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.projectile.EntityThunderbolt; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Thunderbolt extends Spell { + + public Thunderbolt() { + super(Tier.BASIC, 10, Element.LIGHTNING, "thunderbolt", SpellType.ATTACK, 15, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(!world.isRemote){ + EntityThunderbolt thunderbolt = new EntityThunderbolt(world, caster, modifiers.get(SpellModifiers.DAMAGE)); + world.spawnEntityInWorld(thunderbolt); + } + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.8F, world.rand.nextFloat() * 0.2F + 0.8F); + caster.swingArm(hand); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + EntityThunderbolt thunderbolt = new EntityThunderbolt(world, caster, modifiers.get(SpellModifiers.DAMAGE)); + thunderbolt.directTowards(target, 2.5f); + world.spawnEntityInWorld(thunderbolt); + } + + caster.playSound(WizardrySounds.SPELL_ICE, 0.8F, world.rand.nextFloat() * 0.2F + 0.8F); + caster.swingArm(hand); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Thunderstorm.java b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java new file mode 100644 index 00000000..b1992941 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java @@ -0,0 +1,119 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.EntityArc; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.effect.EntityLightningBolt; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class Thunderstorm extends Spell { + + public Thunderstorm() { + super(Tier.MASTER, 100, Element.LIGHTNING, "thunderstorm", SpellType.ATTACK, 250, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + if(world.canBlockSeeSky(new BlockPos(caster))){ + + for(int r=0; r<10; r++){ + + double radius = 4 + world.rand.nextDouble()*6*modifiers.get(WizardryItems.blast_upgrade); + double angle = world.rand.nextDouble()*Math.PI*2; + + double x = caster.posX + radius*Math.cos(angle); + double z = caster.posZ + radius*Math.sin(angle); + double y = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(x, caster.posY, z), 10); + + if(!world.isRemote){ + EntityLightningBolt entitylightning = new EntityLightningBolt(world, x, y, z, false); + world.addWeatherEffect(entitylightning); + } + + // Code for eventhandler recognition; for achievements and such like. Left in for future use. + //NBTTagCompound entityNBT = entitylightning.getEntityData(); + //entityNBT.setInteger("summoningPlayer", entityplayer.entityId); + + // Secondary chaining effect + double seekerRange = 10.0d; + + List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, x, y+1, z, world); + + // For this spell there is no limit to the amount of secondary targets! + for(EntityLivingBase secondaryTarget : secondaryTargets){ + + if(WizardryUtilities.isValidTarget(caster, secondaryTarget)){ + + if(!world.isRemote){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(x, y+1, z, + secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height/2, secondaryTarget.posZ); + world.spawnEntityInWorld(arc); + }else{ + for(int j=0;j<8;j++){ + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, secondaryTarget.posX + world.rand.nextFloat() - 0.5, secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height/2 + world.rand.nextFloat()*2 - 1, secondaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); + world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, secondaryTarget.posX + world.rand.nextFloat() - 0.5, secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height/2 + world.rand.nextFloat()*2 - 1, secondaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); + } + } + + secondaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); + + secondaryTarget.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), 10.0f * modifiers.get(SpellModifiers.DAMAGE)); + + //Tertiary chaining effect + + List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height/2, secondaryTarget.posZ, world); + + for(int j=0; j 2 && world.getBlockState(pos).getBlock() != WizardryBlocks.ice_statue){ + + pos = pos.offset(rayTrace.sideHit); + + if(WizardryUtilities.canBlockBeReplaced(world, pos)){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + } + + // Builds a 2 block high wall if it hits the ground + if(rayTrace.sideHit == EnumFacing.UP){ + pos = pos.offset(rayTrace.sideHit); + + if(WizardryUtilities.canBlockBeReplaced(world, pos)){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + } + } + } + } + + for(int i=0; i<20; i++){ + + if(world.isRemote){ + + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, look.xCoord*modifiers.get(WizardryItems.range_upgrade), look.yCoord*modifiers.get(WizardryItems.range_upgrade), look.zCoord*modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 0.4f, 0.6f, 1.0f); + + x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, look.xCoord*modifiers.get(WizardryItems.range_upgrade), look.yCoord*modifiers.get(WizardryItems.range_upgrade), look.zCoord*modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 1.0f, 1.0f, 1.0f); + } + } + + if(ticksInUse % 12 == 0){ + if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5F, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_ICE, 0.5F, 1.0f); + } + + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/WaterBreathing.java b/src/main/java/electroblob/wizardry/spell/WaterBreathing.java new file mode 100644 index 00000000..c132a85b --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/WaterBreathing.java @@ -0,0 +1,42 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class WaterBreathing extends Spell { + + public WaterBreathing() { + super(Tier.ADVANCED, 30, Element.EARTH, "water_breathing", SpellType.UTILITY, 250, EnumAction.BOW, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + caster.addPotionEffect(new PotionEffect(MobEffects.WATER_BREATHING, (int)(1200*modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat()*2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat()*2 - 1.0F); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.3f, 0.3f, 1.0f); + } + } + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); + return true; + } + + +} diff --git a/src/main/java/electroblob/wizardry/spell/Whirlwind.java b/src/main/java/electroblob/wizardry/spell/Whirlwind.java new file mode 100644 index 00000000..9a76561c --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Whirlwind.java @@ -0,0 +1,99 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.EnumAction; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class Whirlwind extends Spell { + + public Whirlwind() { + super(Tier.APPRENTICE, 10, Element.EARTH, "whirlwind", SpellType.DEFENCE, 15, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.entityHit instanceof EntityLivingBase){ + EntityLivingBase target = (EntityLivingBase) rayTrace.entityHit; + + if(!world.isRemote){ + + target.motionX = caster.getLookVec().xCoord * 2; + target.motionY = caster.getLookVec().yCoord * 2 + 1; + target.motionZ = caster.getLookVec().zCoord * 2; + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + } + + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x2 = (double)(caster.posX + world.rand.nextFloat() - 0.5F + caster.getLookVec().xCoord*caster.getDistanceToEntity(target)*0.5); + double y2 = (double)(WizardryUtilities.getPlayerEyesPos(caster) + world.rand.nextFloat() - 0.5F + caster.getLookVec().yCoord*caster.getDistanceToEntity(target)*0.5); + double z2 = (double)(caster.posZ + world.rand.nextFloat() - 0.5F + caster.getLookVec().zCoord*caster.getDistanceToEntity(target)*0.5); + world.spawnParticle(EnumParticleTypes.CLOUD, x2, y2, z2, caster.getLookVec().xCoord, caster.getLookVec().yCoord, caster.getLookVec().zCoord); + //Minecraft.getMinecraft().effectRenderer.addEffect(new EntitySparkleFX(world, x2, y2, z2, entityplayer.getLookVec().xCoord, entityplayer.getLookVec().yCoord, entityplayer.getLookVec().zCoord, null, 1.0f, 1.0f, 0.8f, 10)); + } + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.8F, world.rand.nextFloat() * 0.2F + 0.6F); + return true; + } + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + target.motionX = caster.getLookVec().xCoord * 2; + target.motionY = caster.getLookVec().yCoord * 2 + 1; + target.motionZ = caster.getLookVec().zCoord * 2; + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + } + if(world.isRemote){ + for(int i=0; i<10; i++){ + double x2 = (double)(caster.posX + world.rand.nextFloat() - 0.5F + caster.getLookVec().xCoord*caster.getDistanceToEntity(target)*0.5); + double y2 = (double)(caster.posY + caster.getEyeHeight() + world.rand.nextFloat() - 0.5F + caster.getLookVec().yCoord*caster.getDistanceToEntity(target)*0.5); + double z2 = (double)(caster.posZ + world.rand.nextFloat() - 0.5F + caster.getLookVec().zCoord*caster.getDistanceToEntity(target)*0.5); + world.spawnParticle(EnumParticleTypes.CLOUD, x2, y2, z2, caster.getLookVec().xCoord, caster.getLookVec().yCoord, caster.getLookVec().zCoord); + } + } + caster.swingArm(hand); + caster.playSound(WizardrySounds.SPELL_ICE, 0.8F, world.rand.nextFloat() * 0.2F + 0.6F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Wither.java b/src/main/java/electroblob/wizardry/spell/Wither.java new file mode 100644 index 00000000..878cf0bb --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Wither.java @@ -0,0 +1,113 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class Wither extends Spell { + + public Wither() { + super(Tier.APPRENTICE, 10, Element.NECROMANCY, "wither", SpellType.ATTACK, 20, EnumAction.NONE, false); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, 10*modifiers.get(WizardryItems.range_upgrade)); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase) rayTrace.entityHit; + + // Has no effect on withers or wither skeletons. + if(MagicDamage.isEntityImmune(DamageType.WITHER, target)){ + if(!world.isRemote) caster.addChatComponentMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), 1.0f * modifiers.get(SpellModifiers.DAMAGE)); + target.addPotionEffect(new PotionEffect(MobEffects.WITHER, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), 1)); + } + } + if(world.isRemote){ + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! + // This is a test for lining up the ray with the wand tip. Not sure if I like it or not. + /* + Vec3d origin = Wizardry.proxy.getWandTipPosition(caster); + double x1 = origin.xCoord + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = origin.yCoord + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = origin.zCoord + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + */ + double x1 = caster.posX + look.xCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.yCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + look.zCoord*i/2 + world.rand.nextFloat()/5 - 0.1f; + //world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.1f, 0.0f, 0.05f); + } + } + caster.swingArm(hand); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_HURT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + // Has no effect on withers or wither skeletons. + if(!MagicDamage.isEntityImmune(DamageType.WITHER, target) && !world.isRemote){ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), 1.0f * modifiers.get(SpellModifiers.DAMAGE)); + target.addPotionEffect(new PotionEffect(MobEffects.WITHER, (int)(200*modifiers.get(WizardryItems.duration_upgrade)), 1)); + } + + if(world.isRemote){ + + double dx = (target.posX - caster.posX)/caster.getDistanceToEntity(target); + double dy = (target.posY - caster.posY)/caster.getDistanceToEntity(target); + double dz = (target.posZ - caster.posZ)/caster.getDistanceToEntity(target); + + for(int i=1; i<(int)(25*modifiers.get(WizardryItems.range_upgrade)); i+=2){ + + double x1 = caster.posX + dx*i/2 + world.rand.nextFloat()/5 - 0.1f; + double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy*i/2 + world.rand.nextFloat()/5 - 0.1f; + double z1 = caster.posZ + dz*i/2 + world.rand.nextFloat()/5 - 0.1f; + + Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); + Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.1f, 0.0f, 0.05f); + } + } + caster.swingArm(hand); + caster.playSound(SoundEvents.ENTITY_WITHER_HURT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/WitherSkull.java b/src/main/java/electroblob/wizardry/spell/WitherSkull.java new file mode 100644 index 00000000..ce0f642e --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/WitherSkull.java @@ -0,0 +1,85 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityWitherSkull; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class WitherSkull extends Spell { + + public WitherSkull() { + super(Tier.ADVANCED, 20, Element.NECROMANCY, "wither_skull", SpellType.ATTACK, 30, EnumAction.NONE, false); + } + + @Override + public boolean doesSpellRequirePacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers) { + + Vec3d look = caster.getLookVec(); + + if(!world.isRemote){ + EntityWitherSkull witherskull = new EntityWitherSkull(world, caster, 1, 1, 1); + witherskull.setPosition( + caster.posX + look.xCoord, + caster.posY + look.yCoord + 1.3, + caster.posZ + look.zCoord); + witherskull.accelerationX = look.xCoord * 0.1; + witherskull.accelerationY = look.yCoord * 0.1; + witherskull.accelerationZ = look.zCoord * 0.1; + world.spawnEntityInWorld(witherskull); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + } + caster.swingArm(hand); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + + EntityWitherSkull witherskull = new EntityWitherSkull(world, caster, 1, 1, 1); + + double dx = target.posX - caster.posX; + double dy = target.getEntityBoundingBox().minY + (double)(target.height / 2.0F) - (caster.posY + (double)(caster.height / 2.0F)); + double dz = target.posZ - caster.posZ; + + witherskull.accelerationX = dx/caster.getDistanceToEntity(target) * 0.1; + witherskull.accelerationY = dy/caster.getDistanceToEntity(target) * 0.1; + witherskull.accelerationZ = dz/caster.getDistanceToEntity(target) * 0.1; + + witherskull.setPosition(caster.posX, caster.posY + caster.getEyeHeight(), caster.posZ); + + world.spawnEntityInWorld(witherskull); + caster.playSound(SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + } + + caster.swingArm(hand); + return true; + } + + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java b/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java new file mode 100644 index 00000000..fdfa4f89 --- /dev/null +++ b/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java @@ -0,0 +1,265 @@ +package electroblob.wizardry.tileentity; + +import java.util.HashSet; +import java.util.Set; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemArcaneTome; +import electroblob.wizardry.item.ItemArmourUpgrade; +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.item.ItemWizardArmour; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.WandHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +public class ContainerArcaneWorkbench extends Container { + + public TileEntityArcaneWorkbench tileEntityArcaneWorkbench; + + public static final ResourceLocation EMPTY_SLOT_CRYSTAL = new ResourceLocation(Wizardry.MODID, "gui/empty_slot_crystal"); + public static final ResourceLocation EMPTY_SLOT_UPGRADE = new ResourceLocation(Wizardry.MODID, "gui/empty_slot_upgrade"); + + public static final int CRYSTAL_SLOT = 8; + public static final int WAND_SLOT = 9; + public static final int UPGRADE_SLOT = 10; + private static final int[][][] SPELL_BOOK_SLOT_COORDS = { + {{80, 22}, {121, 51}, {106, 98}, {54, 98}, {39, 51}, {-999, -999}, {-999, -999}, {-999, -999}}, + {{80, 22}, {117, 43}, {117, 85}, {80, 106}, {43, 85}, {43, 43}, {-999, -999}, {-999, -999}}, + {{80, 22}, {113, 38}, {121, 74}, {98, 102}, {62, 102}, {39, 74}, {47, 38}, {-999, -999}}, + {{80, 22}, {111, 33}, {122, 64}, {111, 95}, {80, 106}, {49, 95}, {38, 64}, {49, 33}} + }; + + public ContainerArcaneWorkbench(IInventory inventory, TileEntityArcaneWorkbench tileentity){ + + this.tileEntityArcaneWorkbench = tileentity; + + ItemStack wand = tileentity.getStackInSlot(WAND_SLOT); + + for(int i=0; i<8; i++){ + this.addSlotToContainer(new SlotItemList(tileentity, i, -999, -999, 1, WizardryItems.spell_book)); + } + + this.addSlotToContainer(new SlotItemList(tileentity, CRYSTAL_SLOT, 8, 88, 64, WizardryItems.magic_crystal)) + .setBackgroundName(EMPTY_SLOT_CRYSTAL.toString()); + + this.addSlotToContainer(new SlotWandArmour(tileentity, WAND_SLOT, 80, 64, this)); + + Set upgrades = new HashSet(WandHelper.getSpecialUpgrades()); + upgrades.add(WizardryItems.arcane_tome); + upgrades.add(WizardryItems.armour_upgrade); + + this.addSlotToContainer(new SlotItemList(tileentity, UPGRADE_SLOT, 8, 106, 1, upgrades.toArray(new Item[0]))) + .setBackgroundName(EMPTY_SLOT_UPGRADE.toString()); + + for(int x = 0; x < 9; x++){ + this.addSlotToContainer(new Slot(inventory, x, 8 + x * 18, 196)); + } + + for(int y = 0; y < 3; y++){ + for(int x = 0; x < 9; x++){ + this.addSlotToContainer(new Slot(inventory, 9 + x + y * 9, 8 + x * 18, 138 + y * 18)); + } + } + + this.onSlotChanged(WAND_SLOT, wand, null); + } + + @Override + public boolean canInteractWith(EntityPlayer par1EntityPlayer) + { + return this.tileEntityArcaneWorkbench.isUseableByPlayer(par1EntityPlayer); + } + + /** + * Called from the central wand/armour slot when its item is changed or removed. + */ + // I wrote this! + public void onSlotChanged(int slotNumber, ItemStack stack, EntityPlayer player){ + + if(slotNumber == WAND_SLOT){ + + if(stack == null || (!(stack.getItem() instanceof ItemWand) && stack.getItem() != WizardryItems.blank_scroll)){ + // If the stack has been removed + for(int i=0; i

    + * In the future, there is scope for an entirely standalone mod based on this idea. Perhaps 'Elemental Damage' could be + * a config-only mod which allows its users to define any number of specific damage types, then give any creature a + * resistance, immunity or vulnerability to each, as well as being able to specify the sources for each type, such as + * enchantments, potions, specific items, certain entities, even particular situations and string damagesource names + * from other mods. + * + * @see IndirectMagicDamage + * @see IElementalDamage + * @since Wizardry 1.1 + * @author Electroblob */ +public class MagicDamage extends EntityDamageSource implements IElementalDamage { + + /** The name of the damagesource for direct magic damage from the wizardry mod. */ + public static final String DIRECT_MAGIC_DAMAGE = "wizardryMagic"; + /** The name of the damagesource for indirect magic damage from the wizardry mod. */ + public static final String INDIRECT_MAGIC_DAMAGE = "indirectWizardryMagic"; + // Technically, I don't need to specify that the classes in this map must extend entity, but it's good practice to. + private static final Map, DamageType[]> immunityMapping = new HashMap, DamageType[]>(); + + private final DamageType type; + private final boolean isRetaliatory; + + /** A simple set of constants for the types of damage. The names are deliberately different to those in EnumElement + * to avoid confusion. All types are classified as magic damage in the vanilla system, so witches are resistant to them. */ + public enum DamageType { + /** Generic magic damage from the wizardry mod. Like vanilla magic damage, except it doesn't bypass armour. */ + MAGIC, + /** Fire damage from the wizardry mod. Counts as fire damage in the vanilla system, so is blocked by any mobs that + * are immune to fire and entities with the fire resistance effect. */ + FIRE, + /** Frost (ice) damage from the wizardry mod. Snow golems, ice wraiths and ice giants are immune. */ + FROST, + /** Shock (lightning) damage from the wizardry mod. Lightning wraiths and storm elementals are immune. */ + SHOCK, + /** Wither damage from the wizardry mod. Withers, wither skeletons and shadow wraiths are immune. */ + WITHER, + /** Poison damage from the wizardry mod. Spiders, cave spiders and undead mobs are immune. */ + POISON, + /** [NYI] Force damage from the wizardry mod. Insubstantial creatures (ghast, shadow wraith, etc.) are immune. */ + FORCE, + /** Blast damage from the wizardry mod. Affected by the blast protection enchantment. */ + BLAST, + /** [NYI] Radiant damage from the wizardry mod. */ + RADIANT; + } + + static { + // Of course, the entities that are immune to fire already are since there's a vanilla system for that, but + // they're included here anyway for completeness and in case anyone wants to check if an entity is immune to + // an unspecified element for reasons other than dealing damage. + setEntityImmunities(EntityPhoenix.class, DamageType.FIRE); + setEntityImmunities(EntityBlaze.class, DamageType.FIRE); + setEntityImmunities(EntityBlazeMinion.class, DamageType.FIRE); + setEntityImmunities(EntityPigZombie.class, DamageType.FIRE, DamageType.POISON); + setEntityImmunities(EntityMagmaCube.class, DamageType.FIRE); + setEntityImmunities(EntityGhast.class, DamageType.FIRE); + setEntityImmunities(EntityDragon.class, DamageType.FIRE); + setEntityImmunities(EntityStormElemental.class, DamageType.FIRE, DamageType.SHOCK); + setEntityImmunities(EntityWither.class, DamageType.FIRE, DamageType.WITHER); + setEntityImmunities(EntitySnowman.class, DamageType.FROST); + setEntityImmunities(EntityIceWraith.class, DamageType.FROST); + setEntityImmunities(EntityIceGiant.class, DamageType.FROST); + setEntityImmunities(EntityLightningWraith.class, DamageType.SHOCK); + setEntityImmunities(EntityShadowWraith.class, DamageType.WITHER); + setEntityImmunities(EntitySpider.class, DamageType.POISON); + setEntityImmunities(EntitySpiderMinion.class, DamageType.POISON); + setEntityImmunities(EntityCaveSpider.class, DamageType.POISON); + setEntityImmunities(EntityZombie.class, DamageType.POISON); + setEntityImmunities(EntitySkeleton.class, DamageType.POISON); + setEntityImmunities(EntityZombieMinion.class, DamageType.POISON); + setEntityImmunities(EntitySkeletonMinion.class, DamageType.POISON); + } + + public MagicDamage(String name, Entity caster, DamageType type, boolean isRetaliatory){ + super(name, caster); + this.type = type; + this.isRetaliatory = isRetaliatory; + this.setMagicDamage(); + if(type == DamageType.FIRE) this.setFireDamage(); + if(type == DamageType.BLAST) this.setExplosion(); + } + + /** Returns true if the given entity is immune to the given damage type according to the entity immunity mappings, + * false otherwise. When you want to check for resistances, check this method rather than just checking the result + * of attackEntityFrom, since that could return false for all sorts of reasons besides immunities. However, if you + * don't need to know whether the damage succeeded or not, there's no point in checking this method. A common use + * of this method is to check for immunity and if so display the "[mob] resisted [spell]" chat message. See + * {@link electroblob.wizardry.spell.Arc Arc} for a good example of this, and also of when not to use it. */ + public static boolean isEntityImmune(DamageType type, Entity entity){ + // Because Mojang, in their infinite wisdom, did not make wither skeletons their own separate class (despite the + // fact that cave spiders are), I have to test for this manually. Realistically, no mod author would be stupid + // enough to put two entities in one class, so this should be the only time I ever have to do this. + if(type == DamageType.WITHER && entity instanceof EntitySkeleton + // Don't need to check EntitySkeletonMinion separately any more because it now extends EntitySkeleton. + && ((EntitySkeleton)entity).getSkeletonType() == SkeletonType.WITHER){ + return true; + } + + if(type == DamageType.FIRE && entity.isImmuneToFire()) return true; + + DamageType[] immunities = MagicDamage.immunityMapping.get(entity.getClass()); + + return immunities != null && Arrays.asList(immunities).contains(type); + } + + /** Registers the given type of entity as immune to all of the passed in damage types. */ + public static void setEntityImmunities(Class entityType, DamageType... immunities){ + immunityMapping.put(entityType, immunities); + } + + /** Adds the passed in damage type to the list of damage types to which the given entity is immune. */ + public static void addEntityImmunity(Class entityType, DamageType immunity){ + List immunities = Arrays.asList(immunityMapping.get(entityType)); + immunities.add(immunity); + // Apparently putting 0 here works just fine. + immunityMapping.put(entityType, immunities.toArray(new DamageType[0])); + } + + /** + * Returns a DamageSource called "wizardryMagic" with the given entity as the caster. Use in preference to vanilla + * types to allow things to distinguish between magic and regular melee/swords. Unlike DamageSource.magic, it does + * not bypass armour and has a player as the source (rather than nothing). It is still classed as magic damage (for + * the record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway). + * isRetaliatory defaults to false. + *

    + * Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire + * mod just to get rid of this method and use the constructor instead. + * @param caster The player or other living entity causing the damage + * @param type The type that this damage belongs to; used for resistances and wand perks. Use + * {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element + * even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might + * reasonably affect creatures that are ususally immune to wither effects). + * @return A damagesource object of type EntityDamageSource + */ + public static DamageSource causeDirectMagicDamage(Entity caster, DamageType type){ + return causeDirectMagicDamage(caster, type, false); + } + + /** + * Returns a DamageSource called "wizardryMagic" with the given entity as the caster. Use in preference to vanilla + * types to allow things to distinguish between magic and regular melee/swords. Unlike DamageSource.magic, it does + * not bypass armour and has a player as the source (rather than nothing). It is still classed as magic damage (for + * the record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway). + *

    + * Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire + * mod just to get rid of this method and use the constructor instead. + * @param caster The player or other living entity causing the damage + * @param type The type that this damage belongs to; used for resistances and wand perks. Use + * {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element + * even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might + * reasonably affect creatures that are ususally immune to wither effects). + * @param isRetaliatory whether this damage source came from a retaliatory attack; prevents infinite loops + * occurring when two entities damage each other with retaliatory effects. + * @return A damagesource object of type EntityDamageSource + */ + public static DamageSource causeDirectMagicDamage(Entity caster, DamageType type, boolean isRetaliatory){ + return new MagicDamage(DIRECT_MAGIC_DAMAGE, caster, type, isRetaliatory); + } + + /** + * Returns a DamageSource called "indirectWizardryMagic" with the player as the caster. Use in preference to vanilla + * types to allow things to distinguish between magic and regular arrows/throwables. Unlike + * DamageSource.causeIndirectMagicDamage, it does not bypass armour. It is still classed as magic damage (for the + * record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway). + * isRetaliatory defaults to false. + *

    + * Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire + * mod just to get rid of this method and use the constructor instead. + * @param magic The entity that actually caused the damage + * @param caster The player or other living entity that cast the spell originally + * @param type The type that this damage belongs to; used for resistances and wand perks. Use + * {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element + * even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might + * reasonably affect creatures that are ususally immune to wither effects). + * @return A damagesource object of type EntityDamageSourceIndirect + */ + public static DamageSource causeIndirectMagicDamage(Entity magic, Entity caster, DamageType type){ + return causeIndirectMagicDamage(magic, caster, type, false); + } + + /** + * Returns a DamageSource called "indirectWizardryMagic" with the player as the caster. Use in preference to vanilla + * types to allow things to distinguish between magic and regular arrows/throwables. Unlike + * DamageSource.causeIndirectMagicDamage, it does not bypass armour. It is still classed as magic damage (for the + * record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway). + *

    + * Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire + * mod just to get rid of this method and use the constructor instead. + * @param magic The entity that actually caused the damage + * @param caster The player or other living entity that cast the spell originally + * @param type The type that this damage belongs to; used for resistances and wand perks. Use + * {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element + * even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might + * reasonably affect creatures that are ususally immune to wither effects). + * @param isRetaliatory whether this damage source came from a retaliatory attack; prevents infinite loops + * occurring when two entities damage each other with retaliatory effects. + * @return A damagesource object of type EntityDamageSourceIndirect + */ + public static DamageSource causeIndirectMagicDamage(Entity magic, Entity caster, DamageType type, boolean isRetaliatory){ + return new IndirectMagicDamage(INDIRECT_MAGIC_DAMAGE, magic, caster, type, isRetaliatory); + } + + @Override + public DamageType getType(){ + return type; + } + + @Override + public boolean isRetaliatory(){ + return isRetaliatory; + } + +} diff --git a/src/main/java/electroblob/wizardry/util/MinionDamage.java b/src/main/java/electroblob/wizardry/util/MinionDamage.java new file mode 100644 index 00000000..987baf88 --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/MinionDamage.java @@ -0,0 +1,32 @@ +package electroblob.wizardry.util; + +import electroblob.wizardry.util.MagicDamage.DamageType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; + +/** + * DamageSource specifically for summoned creatures. Despite being for melee attacks, this is actually an indirect + * damage source, because it allows the minion to be the 'projectile'. This class also overrides getDeathMessage to + * display the minion's name rather than the caster's. The event handler deals with all damage dealt by summoned + * creatures, so it's very unlikely that this will be needed anywhere else. If for some reason it is, note that + * knockback has to be removed and re-applied after the damage is dealt. + * @author Electroblob + * @since Wizardry 1.2 + * @see IndirectMinionDamage + */ +public class MinionDamage extends IndirectMagicDamage { + + public MinionDamage(String name, Entity minion, Entity caster, DamageType type, boolean isRetaliatory) { + super(name, minion, caster, type, isRetaliatory); + } + + @Override + public ITextComponent getDeathMessage(EntityLivingBase victim) { + ITextComponent itextcomponent = this.damageSourceEntity.getDisplayName(); + String key = "death.attack." + this.damageType; + return new TextComponentTranslation(key, victim.getDisplayName(), itextcomponent); + } + +} diff --git a/src/main/java/electroblob/wizardry/util/SpellModifiers.java b/src/main/java/electroblob/wizardry/util/SpellModifiers.java new file mode 100644 index 00000000..39f97c63 --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/SpellModifiers.java @@ -0,0 +1,141 @@ +package electroblob.wizardry.util; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import io.netty.buffer.ByteBuf; +import net.minecraft.item.Item; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fml.common.network.ByteBufUtils; + +/** + * Object that wraps any number of spell multipliers into one, allowing for expandability within the Spell#cast + * methods. This class is essentially a glorified {@link Map} which can be written to and read from a {@link ByteBuf}. + * It is possible to calculate spell multipliers from wand NBT within the cast methods, but this is cumbersome and does + * not allow the multipliers to be sent to the client, which is sometimes necessary (for example, detonate needs to know + * about range multipliers on the client side or the particles wouldn't show outside of the base range). + *

    + * Most external interaction with SpellModifiers objects will be in SpellCastEvent.Pre, where you can add additional + * multipliers to them if desired for use with your own spells, or modify the existing ones. If you have added a wand + * upgrade, this is not done automatically for you; you will have to do it yourself (for the simple reason that + * not all wand upgrades affect spells). + *

    + * To use a SpellModifiers object within the Spell.cast methods, simply retrieve the desired multiplier + * using {@link SpellModifiers#get(Item)} for wand upgrades, or {@link SpellModifiers#get(String)} if the multiplier + * is not from a wand upgrade. + * @author Electroblob + * @since Wizardry 1.2 + * @see WandHelper + */ +// I have made the decision that the USERS of this class must decide whether the multipliers need syncing or not, on a +// case-by-case basis. Why? Because assigning keys to either sync or not sync would be unnecessarily restrictive, and +// would mean they have to be registered, and part of the point of SpellModifiers is that they can be added to on the +// fly. +public final class SpellModifiers { + + /** Constant string identifier for the damage multiplier. All the other multipliers in Wizardry have items. */ + public static final String DAMAGE = "damage"; + + private Map multiplierMap; + private Map syncedMultiplierMap; + + /** Creates an empty SpellModifiers object. All calls to get(...) on an empty SpellModifiers object + * will return a value of 1. */ + public SpellModifiers(){ + multiplierMap = new HashMap(); + syncedMultiplierMap = new HashMap(); + } + + /** + * Adds the given multiplier to this SpellModifiers object, using the string identifier that the given wand + * upgrade item was registered with. + * @throws IllegalArgumentException if the given item is not a registered special wand upgrade. + * @param upgrade The upgrade item the multiplier corresponds to. + * @param multiplier The multiplier value, with 1 being default. Usage of multipliers is up to individual spells to + * implement. + * @param needsSyncing Whether this multiplier should be synchronised with the client via packets. Only set this + * to true if particles will be spawned which need to know the value of the multiplier. + * @return The SpellModifiers object, allowing this method to be chained onto the constructor. + */ + public SpellModifiers set(Item upgrade, float multiplier, boolean needsSyncing){ + this.set(WandHelper.getIdentifier(upgrade), multiplier, needsSyncing); + return this; + } + + /** + * Adds the given multiplier to this SpellModifiers object, using the given string key. In most cases, the + * multiplier will correspond to a wand upgrade, in which case use {@link SpellModifiers#set(Item, float, boolean)} + * instead. + * @param key The key used to identify the multiplier. + * @param multiplier The multiplier value, with 1 being default. Usage of multipliers is up to individual spells to + * implement. + * @param needsSyncing Whether this multiplier should be synchronised with the client via packets. Only set this + * to true if particles will be spawned which depend on the multiplier. + * @return The SpellModifiers object, allowing this method to be chained onto the constructor. + */ + public SpellModifiers set(String key, float multiplier, boolean needsSyncing){ + multiplierMap.put(key, multiplier); + if(needsSyncing) syncedMultiplierMap.put(key, multiplier); + return this; + } + + /** Returns the multiplier corresponding to the given wand upgrade item, or 1 if no multiplier was stored. + * @throws IllegalArgumentException if the given item is not a registered special wand upgrade. */ + public float get(Item upgrade){ + return get(WandHelper.getIdentifier(upgrade)); + } + + /** Returns the multiplier corresponding to the given string key, or 1 if no multiplier was stored. In most cases, + * the multiplier will correspond to a wand upgrade, in which case use {@link SpellModifiers#get(Item)} + * instead. */ + public float get(String key){ + Float value = multiplierMap.get(key); + // Must check for null before unboxing, and if it is null, return the default 1. + return value == null ? 1 : value; + } + + /** Returns an unmodifiable map of the modifiers stored in this SpellModifiers object. Useful for iterating through + * the modifiers. */ + public Map getModifiers(){ + return Collections.unmodifiableMap(this.multiplierMap); + } + + /** Removes all modifiers from this SpellModifiers object, effectively resetting them all to 1. */ + public void reset(){ + this.multiplierMap.clear(); + this.syncedMultiplierMap.clear(); + } + + /** Reads this SpellModifiers object from the given ByteBuf. */ + public void read(ByteBuf buf){ + int entryCount = buf.readInt(); + for(int i=0; i entry : syncedMultiplierMap.entrySet()){ + ByteBufUtils.writeUTF8String(buf, entry.getKey()); + buf.writeFloat(entry.getValue()); + } + } + + /** Creates a new SpellModifiers object from the given NBTTagCompound. The NBTTagCompound should have 1 or more + * float tags, which will be stored as modifiers under the same name as the tag. For example, the following NBT + * tag (in command syntax) will create a SpellModifiers object with a damage modifier of 1.5 and a range modifier of + * 2:

    {damage:1.5, range:2}

    + * Note that needsSyncing is set to true for all returned modifiers. */ + public static SpellModifiers fromNBT(NBTTagCompound nbt){ + SpellModifiers modifiers = new SpellModifiers(); + for(String key : nbt.getKeySet()){ + modifiers.set(key, nbt.getFloat(key), true); + } + return modifiers; + } + +} diff --git a/src/main/java/electroblob/wizardry/util/WandHelper.java b/src/main/java/electroblob/wizardry/util/WandHelper.java new file mode 100644 index 00000000..436f220f --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/WandHelper.java @@ -0,0 +1,290 @@ +package electroblob.wizardry.util; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Set; + +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.spell.Spell; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +/** Much like {@link net.minecraft.enchantment.EnchantmentHelper EnchantmentHelper}, this class has some static methods + * which allow cleaner and more concise interaction with the wand NBT data, which is quite a complex structure. Such + * interaction previously resulted in rather verbose and repetitive code which was hard to read and even harder to debug! + * For example, this class allowed {@link electroblob.wizardry.item.ItemWand ItemWand} to be shortened by about 80 lines. + * In addition, by having all the various null checks and array size checks in one place, the chance of accidental errors + * due to forgetting to check these things is greatly reduced. + *

    + * Note that these methods contain no game logic at all; they are purely for interacting with the NBT data. Conversely, + * you should never need to access the wand's NBT data directly when using this class, but the keys are public in the + * unlikely case that this is necessary. + *

    + * Also note that none of the methods in this class actually check that the given ItemStack contains an ItemWand; you + * can, for example, pass in a stack of snowballs without causing problems, but that is of course pointless! + *

    + * All get methods in this class return some kind of default if the passed-in wand stack has no nbt data. + * See individual method descriptions for more details.
    + * All set methods in this class create a new nbt data for the passed-in wand if it has none, before doing + * whatever else they do. + * @see electroblob.wizardry.item.ItemWand ItemWand + * @see electroblob.wizardry.packet.PacketControlInput PacketControlInput + * @since Wizardry 1.1 */ +public final class WandHelper { + + // NBT tag keys + public static final String SPELL_ARRAY_KEY = "spells"; + public static final String SELECTED_SPELL_KEY = "selectedSpell"; + public static final String COOLDOWN_ARRAY_KEY = "cooldown"; + public static final String UPGRADES_KEY = "upgrades"; + + private static final HashMap upgradeMap = new HashMap(); + + static { + upgradeMap.put(WizardryItems.condenser_upgrade, "condenser"); + upgradeMap.put(WizardryItems.storage_upgrade, "storage"); + upgradeMap.put(WizardryItems.siphon_upgrade, "siphon"); + upgradeMap.put(WizardryItems.range_upgrade, "range"); + upgradeMap.put(WizardryItems.duration_upgrade, "duration"); + upgradeMap.put(WizardryItems.cooldown_upgrade, "cooldown"); + upgradeMap.put(WizardryItems.blast_upgrade, "blast"); + upgradeMap.put(WizardryItems.attunement_upgrade, "attunement"); + } + + /** Returns an array containing the spells currently bound to the given wand. As of Wizardry 1.1, this array is not + * always the same size; it can be anywhere between 5 and 8 (inclusive) in length. If the wand has no spell data, + * returns an array of length 0. */ + public static Spell[] getSpells(ItemStack wand){ + + Spell[] spells = new Spell[0]; + + if(wand.getTagCompound() != null){ + + int[] spellIDs = wand.getTagCompound().getIntArray(SPELL_ARRAY_KEY); + + spells = new Spell[spellIDs.length]; + + for(int i=0; i= numberOfSpells - 1){ + selectedSpell = 0; + }else{ + selectedSpell++; + } + + wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, selectedSpell); + + } + } + + /** Selects the previous spell in this wand's list of spells. */ + public static void selectPreviousSpell(ItemStack wand){ + + // 5 here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades + if(getSpells(wand).length < 0) setSpells(wand, new Spell[5]); + // This cannot possibly be null here, and yet I am getting an NPE... + if(wand.getTagCompound() != null){ + + int numberOfSpells = getSpells(wand).length; + int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY); + + if(selectedSpell <= 0){ + selectedSpell = numberOfSpells - 1; + }else{ + selectedSpell--; + } + + wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, selectedSpell); + } + } + + /** Returns an array of the cooldowns for each spell bound to the given wand. As of Wizardry 1.1, this array is not + * always the same size; it can be anywhere between 5 and 8 (inclusive) in length. If the wand has no cooldown data, + * returns an array of length 0. */ + public static int[] getCooldowns(ItemStack wand){ + + int[] cooldowns = new int[0]; + + if(wand.getTagCompound() != null){ + + return wand.getTagCompound().getIntArray(COOLDOWN_ARRAY_KEY); + } + + return cooldowns; + } + + /** Sets the given wand's cooldown array. The array can be anywhere between 5 and 8 (inclusive) in length. */ + public static void setCooldowns(ItemStack wand, int[] cooldowns){ + + if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound())); + + wand.getTagCompound().setIntArray(COOLDOWN_ARRAY_KEY, cooldowns); + } + + /** Decrements the cooldown for each spell bound to the given wand by 1, if that cooldown is greater than 0. */ + public static void decrementCooldowns(ItemStack wand){ + + int[] cooldowns = getCooldowns(wand); + + // If there are no cooldowns, it is assumed that they are all zero and therefore nothing needs to be done. + if(cooldowns.length == 0) return; + + for(int i=0; i 0) cooldowns[i]--; + } + + setCooldowns(wand, cooldowns); + } + + /** Returns the given wand's cooldown for the currently selected spell, or 0 if the wand has no cooldown data. */ + public static int getCurrentCooldown(ItemStack wand){ + + int[] cooldowns = getCooldowns(wand); + + if(cooldowns.length == 0) return 0; + // Don't need to check if the tag compound is null since the above check is equivalent. + return cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)]; + } + + /** Sets the given wand's cooldown for the currently selected spell. */ + public static void setCurrentCooldown(ItemStack wand, int cooldown){ + + if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound())); + + int[] cooldowns = getCooldowns(wand); + + // The length of the spells array must be greater than 0 since this method can only be called if a spell is + // cast, which is impossible if there are no spells. + if(cooldowns.length == 0) cooldowns = new int[getSpells(wand).length]; + + cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)] = cooldown; + + setCooldowns(wand, cooldowns); + } + + /** Returns the number of upgrades of the given type that have been applied to the given wand, or 0 if the wand has + * no upgrade data or the given item is not a valid wand upgrade. */ + public static int getUpgradeLevel(ItemStack wand, Item upgrade){ + + String key = upgradeMap.get(upgrade); + + if(wand.getTagCompound() != null && wand.getTagCompound().hasKey(UPGRADES_KEY) && key != null){ + return wand.getTagCompound().getCompoundTag(UPGRADES_KEY).getInteger(key); + } + + return 0; + + } + + /** Returns the total number of upgrades that have been applied to the given wand, or 0 if the wand has no upgrade + * data. */ + public static int getTotalUpgrades(ItemStack wand){ + + int totalUpgrades = 0; + + for(Item item : upgradeMap.keySet()){ + totalUpgrades += getUpgradeLevel(wand, item); + } + + return totalUpgrades; + } + + /** Applies the given upgrade to the given wand, or in other words increases the level for that upgrade by 1. This + * does not account for the individual or total upgrade stack limits. */ + public static void applyUpgrade(ItemStack wand, Item upgrade){ + + if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound())); + + if(!wand.getTagCompound().hasKey(UPGRADES_KEY)) wand.getTagCompound().setTag(UPGRADES_KEY, new NBTTagCompound()); + + NBTTagCompound upgrades = wand.getTagCompound().getCompoundTag(UPGRADES_KEY); + + String key = upgradeMap.get(upgrade); + + if(key != null) upgrades.setInteger(key, upgrades.getInteger(key) + 1); + + wand.getTagCompound().setTag(UPGRADES_KEY, upgrades); + } + + /** Returns true if the given item is a valid special wand upgrade. */ + public static boolean isWandUpgrade(Item upgrade){ + return upgradeMap.containsKey(upgrade); + } + + /** Returns an unmodifiable set of all the items which are valid special wand upgrades. */ + public static Set getSpecialUpgrades(){ + return Collections.unmodifiableSet(WandHelper.upgradeMap.keySet()); + } + + /** Package-protected getter for the identifier that corresponds to the given item, used only in the + * {@link SpellModifiers} class. Internal to Wizardry. + * @throws IllegalArgumentException if the given item is not a registered special wand upgrade.*/ + static String getIdentifier(Item upgrade){ + if(!isWandUpgrade(upgrade)) throw new IllegalArgumentException("Tried to get a wand upgrade key for an item" + + "that is not a registered special wand upgrade."); + return upgradeMap.get(upgrade); + } + + /** Registers a special upgrade with wizardry. Not used in the base mod, but I've put it here to make it easy + * for add-ons to add new wand upgrades. + * @param upgrade The wand upgrade item + * @param identifier A unique string, used as a key for wand nbt tags + * @throws IllegalArgumentException if the passed in identifier is already used for another wand upgrade */ + public static void registerSpecialUpgrade(Item upgrade, String identifier){ + // Throwing an exception is the best thing to do here, since if a duplicate was allowed weird things would + // happen later with wand NBT. + if(upgradeMap.containsValue(identifier)) throw new IllegalArgumentException("Duplicate wand upgrade identifier: " + identifier); + upgradeMap.put(upgrade, identifier); + } +} diff --git a/src/main/java/electroblob/wizardry/util/WizardryParticleType.java b/src/main/java/electroblob/wizardry/util/WizardryParticleType.java new file mode 100644 index 00000000..53093f2c --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/WizardryParticleType.java @@ -0,0 +1,19 @@ +package electroblob.wizardry.util; + +/** Enum constants representing the different types of particle added by wizardry. This was renamed from the previous + * EnumParticleType in the 1.10.2 port to avoid confusion with the vanilla version, EnumParticleTypes. */ +public enum WizardryParticleType { + BLIZZARD, + BRIGHT_DUST, + DARK_MAGIC, + DUST, + ICE, + LEAF, + MAGIC_BUBBLE, + MAGIC_FIRE, + PATH, + SNOW, + SPARK, + SPARKLE, + SPARKLE_ROTATING +} diff --git a/src/main/java/electroblob/wizardry/util/WizardryPathFinder.java b/src/main/java/electroblob/wizardry/util/WizardryPathFinder.java new file mode 100644 index 00000000..8c5c2d9d --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/WizardryPathFinder.java @@ -0,0 +1,136 @@ +package electroblob.wizardry.util; + +import java.util.Set; + +import javax.annotation.Nullable; + +import com.google.common.collect.Sets; + +import net.minecraft.entity.EntityLiving; +import net.minecraft.pathfinding.NodeProcessor; +import net.minecraft.pathfinding.Path; +import net.minecraft.pathfinding.PathHeap; +import net.minecraft.pathfinding.PathPoint; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; + +/** Minecraft's pathfinder refused to play nicely, so I 'borrowed' its code and fiddled with it. */ +public class WizardryPathFinder { + + /** The path being generated */ + private final PathHeap path = new PathHeap(); + private final Set closedSet = Sets.newHashSet(); + /** Selection of path points to add to the path */ + private final PathPoint[] pathOptions = new PathPoint[32]; + private final NodeProcessor nodeProcessor; + + public WizardryPathFinder(NodeProcessor processor){ + this.nodeProcessor = processor; + } + + @Nullable + public Path findPath(IBlockAccess world, EntityLiving entity, BlockPos destination, float range){ + return this.findPath(world, entity, (double)((float)destination.getX() + 0.5F), (double)((float)destination.getY() + 0.5F), (double)((float)destination.getZ() + 0.5F), range); + } + + @Nullable + private Path findPath(IBlockAccess world, EntityLiving entity, double x, double y, double z, float range){ + this.path.clearPath(); + this.nodeProcessor.initProcessor(world, entity); + PathPoint pathpoint = this.nodeProcessor.getStart(); + PathPoint pathpoint1 = this.nodeProcessor.getPathPointToCoords(x, y, z); + Path path = this.findPath(pathpoint, pathpoint1, range); + this.nodeProcessor.postProcess(); + return path; + } + + @Nullable + private Path findPath(PathPoint start, PathPoint end, float range){ + + start.totalPathDistance = 0.0F; + start.distanceToNext = start.distanceManhattan(end); + start.distanceToTarget = start.distanceToNext; + this.path.clearPath(); + this.closedSet.clear(); + this.path.addPoint(start); + PathPoint pathpoint = start; + int i = 0; + + while(!this.path.isPathEmpty()){ + + ++i; + + // This is the offending line - timeout limit changed from 200 to 5000. + if(i >= 5000){ + break; + } + + PathPoint pathpoint1 = this.path.dequeue(); + + if(pathpoint1.equals(end)){ + pathpoint = end; + break; + } + + if(pathpoint1.distanceManhattan(end) < pathpoint.distanceManhattan(end)){ + pathpoint = pathpoint1; + } + + pathpoint1.visited = true; + int j = this.nodeProcessor.findPathOptions(this.pathOptions, pathpoint1, end, range); + + for(int k = 0; k < j; ++k){ + + PathPoint pathpoint2 = this.pathOptions[k]; + float f = pathpoint1.distanceManhattan(pathpoint2); + pathpoint2.distanceFromOrigin = pathpoint1.distanceFromOrigin + f; + pathpoint2.cost = f + pathpoint2.costMalus; + float f1 = pathpoint1.totalPathDistance + pathpoint2.cost; + + if(pathpoint2.distanceFromOrigin < range && (!pathpoint2.isAssigned() || f1 < pathpoint2.totalPathDistance)){ + + pathpoint2.previous = pathpoint1; + pathpoint2.totalPathDistance = f1; + pathpoint2.distanceToNext = pathpoint2.distanceManhattan(end) + pathpoint2.costMalus; + + if(pathpoint2.isAssigned()){ + this.path.changeDistance(pathpoint2, pathpoint2.totalPathDistance + pathpoint2.distanceToNext); + }else{ + pathpoint2.distanceToTarget = pathpoint2.totalPathDistance + pathpoint2.distanceToNext; + this.path.addPoint(pathpoint2); + } + } + } + } + + if(pathpoint == start){ + return null; + }else{ + Path path = this.createEntityPath(start, pathpoint); + return path; + } + } + + /** + * Returns a new PathEntity for a given start and end point + */ + private Path createEntityPath(PathPoint start, PathPoint end){ + + int i = 1; + + for(PathPoint pathpoint = end; pathpoint.previous != null; pathpoint = pathpoint.previous){ + ++i; + } + + PathPoint[] points = new PathPoint[i]; + PathPoint pathpoint1 = end; + --i; + + for(points[i] = end; pathpoint1.previous != null; points[i] = pathpoint1){ + pathpoint1 = pathpoint1.previous; + --i; + } + + return new Path(points); + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java new file mode 100644 index 00000000..c0912b1f --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -0,0 +1,967 @@ +package electroblob.wizardry.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; +import java.util.UUID; +import java.util.function.Function; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.tuple.ImmutablePair; + +import electroblob.wizardry.CommonProxy; +import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.ISummonedCreature; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.spell.MindControl; +import electroblob.wizardry.spell.Spell; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntityCreeper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.inventory.EntityEquipmentSlot.Type; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** This class contains some useful static methods for use anywhere - items, entities, spells, events, blocks, etc. + * @see CommonProxy + * @see WandHelper + * @since Wizardry 1.0 + * @author Electroblob */ +public final class WizardryUtilities { + + /** Constant which is simply an array of the four armour slots. (Could've sworn this exists somewhere in + * vanilla, but I can't find it anywhere...) */ + public static final EntityEquipmentSlot[] ARMOUR_SLOTS; + /** Changed to a constant in wizardry 2.1, since this is a lot more efficient. */ + private static final DataParameter POWERED; + + static { + // The list of slots needs to be mutable. + List slots = new ArrayList(Arrays.asList(EntityEquipmentSlot.values())); + slots.removeIf(slot -> slot.getSlotType() != Type.ARMOR); + ARMOUR_SLOTS = slots.toArray(new EntityEquipmentSlot[0]); + + // Null is passed in deliberately since POWERED is a static field. + POWERED = ReflectionHelper.getPrivateValue(EntityCreeper.class, null, "POWERED", "field_184714_b"); + } + + // SECTION Block/Entity/World Utilities + // =============================================================================================================== + + /** + * Returns whether the block at the given coordinates can be replaced by another one (works as if a block is being placed by a player). + * True for air, liquids, vines, tall grass and snow layers but not for flowers, signs etc. + * This is a shortcut for world.getBlockState(pos).getMaterial().isReplaceable(). + * @see WizardryUtilities#canBlockBeReplacedB(World, BlockPos) + */ + public static boolean canBlockBeReplaced(World world, BlockPos pos){ + return world.isAirBlock(new BlockPos(pos)) || world.getBlockState(pos).getMaterial().isReplaceable(); + } + + /** + * Returns whether the block at the given coordinates can be replaced by another one (works as if a block is being placed by a player) + * and is not a liquid. + * True for air, vines, tall grass and snow layers but not for flowers, signs etc. or any liquids. + * @see WizardryUtilities#canBlockBeReplaced(World, BlockPos) + */ + public static boolean canBlockBeReplacedB(World world, BlockPos pos){ + return canBlockBeReplaced(world, pos) && !world.getBlockState(pos).getMaterial().isLiquid(); + } + + /** + * Returns whether the block at the given coordinates is unbreakable in survival mode. In vanilla this is true for + * bedrock and end portal frame, for example. + * This is a shortcut for world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f. + * Not much of a shortcut any more, since block ids have been phased out. + */ + public static boolean isBlockUnbreakable(World world, BlockPos pos){ + return world.isAirBlock(new BlockPos(pos)) ? false : world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f; + } + + /** + * Finds the nearest floor level to the given y coord within the range specified at the given x and z coords. + * Liquids and other blocks that cannot be built on top of do not count, but stuff like signs does. + * (Technically any block is allowed to be the floor according to the code, but seeing as it searches upwards and + * non-solid blocks usually need a supporting block, the floor is likely to always be solid). + * @param world + * @param x The x coordinate to search in + * @param y The y coordinate to search from + * @param z The z coordinate to search in + * @param range The maximum distance from the given y coordinate to search. + * @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the floor + * as would be seen in the debug screen when the player is standing on it. + * @see WizardryUtilities#getNearestFloorLevelB(World, BlockPos, int) + */ + public static int getNearestFloorLevel(World world, BlockPos pos, int range){ + + int yCoord = -2; + for(int i = -range; i <= range; i++){ + // The last bit determines whether the block found to be a suitable floor is closer than the previous one found. + if(world.isSideSolid(pos.up(i), EnumFacing.UP) && (world.isAirBlock(pos.up(i+1)) || !world.isSideSolid(pos.up(i+1), EnumFacing.UP)) + && (i < yCoord-pos.getY() || yCoord == -2)){ + yCoord = pos.getY() + i; + } + } + return yCoord + 1; + } + + /** + * Finds the nearest floor level to the given y coord within the range specified at the given x and z coords. + * Only works if the block above the floor is actually air and the floor is solid or a liquid. + * @param world + * @param x The x coordinate to search in + * @param y The y coordinate to search from + * @param z The z coordinate to search in + * @param range The maximum distance from the given y coordinate to search. + * @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the floor + * as would be seen in the debug screen when the player is standing on it. + * @see WizardryUtilities#getNearestFloorLevel(World, BlockPos, int) + */ + public static int getNearestFloorLevelB(World world, BlockPos pos, int range){ + int yCoord = -2; + for(int i = -range; i <= range; i++){ + if(world.isAirBlock(new BlockPos(pos.up(i+1))) && (world.getBlockState(pos.up(i)).getMaterial().isLiquid() || world.isSideSolid(pos.up(i), EnumFacing.UP)) + && (i < yCoord-pos.getY() || yCoord == -2)){ + // The last bit determines whether the block found to be a suitable floor is closer than the previous one found. + yCoord = pos.getY() + i; + } + } + return yCoord + 1; + } + + /** + * Finds the nearest floor level to the given y coord within the range specified at the given x and z coords. + * Everything that is not air is treated as floor, even stuff that can't be walked on. + * @param world + * @param x The x coordinate to search in + * @param y The y coordinate to search from + * @param z The z coordinate to search in + * @param range The maximum distance from the given y coordinate to search. + * @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the floor + * as would be seen in the debug screen when the player is standing on it. + * @see WizardryUtilities#getNearestFloorLevel(World, BlockPos, int) + */ + public static int getNearestFloorLevelC(World world, BlockPos pos, int range){ + int yCoord = -2; + for(int i = -range; i <= range; i++){ + if(world.isAirBlock(new BlockPos(pos.up(i+1))) && (i < yCoord-pos.getY() || yCoord == -2)){ + // The last bit determines whether the block found to be a suitable floor is closer than the previous one found. + yCoord = pos.getY() + i; + } + } + return yCoord + 1; + } + + /** + * Gets a random position on the ground near the player within the specified horizontal and vertical ranges. Used + * to find a position to spawn entities in summoning spells. + * @param entity The entity around which to search + * @param horizontalRange The maximum number of blocks on the x or z axis the returned position can be from the + * given entity. The number of operations performed by this method is proportional to the square of this + * parameter, so for performance reasons it is recommended that it does not exceed around 10. + * @param verticalRange The maximum number of blocks on the y axis the returned position can be from the given + * entity + * @return A BlockPos with the coordinates of the block directly above the ground at the position found, or null + * if none were found within range. Importantly, since this method checks all possible positions within + * range (i.e. randomness only occurs when deciding between the possible positions), if it returns null once + * then it will always return null given the same circumstances and parameters. What this means is that you can + * (and should) immediately stop trying to cast a summoning spell if this returns null. + */ + @Nullable + public static BlockPos findNearbyFloorSpace(Entity entity, int horizontalRange, int verticalRange){ + + World world = entity.worldObj; + List possibleLocations = new ArrayList(); + BlockPos origin = new BlockPos(entity); + + for(int x = -horizontalRange; x <= horizontalRange; x++){ + for(int z = -horizontalRange; z <= horizontalRange; z++){ + int y = WizardryUtilities.getNearestFloorLevel(world, origin.add(x, 0, z), verticalRange); + if(y > -1) possibleLocations.add(new BlockPos(origin.getX() + x, y, origin.getZ() + z)); + } + } + + if(possibleLocations.isEmpty()){ + return null; + }else{ + return possibleLocations.get(world.rand.nextInt(possibleLocations.size())); + } + + } + + /** + * Gets the blockstate of the block the specified entity is standing on. Uses {@link MathHelper#floor_double(double)} because casting to int will not + * return the correct coordinate when x or z is negative. + */ + public static IBlockState getBlockEntityIsStandingOn(Entity entity){ + BlockPos pos = new BlockPos(MathHelper.floor_double(entity.posX), (int)entity.getEntityBoundingBox().minY-1, MathHelper.floor_double(entity.posZ)); + return entity.worldObj.getBlockState(pos); + } + + /** + * Shorthand for {@link WizardryUtilities#getEntitiesWithinRadius(double, double, double, double, World, Class)} + * with EntityLivingBase as the entity type. This is by far the most common use for that method, which is why this + * shorthand exists. + * @param radius The search radius + * @param x The x coordinate to search around + * @param y The y coordinate to search around + * @param z The z coordinate to search around + * @param world The world to search in + */ + public static List getEntitiesWithinRadius(double radius, double x, double y, double z, World world){ + return getEntitiesWithinRadius(radius, x, y, z, world, EntityLivingBase.class); + } + + /** + * Returns all entities of the specified type within the specified radius of the given coordinates. This is different to using + * a raw AABB because a raw AABB will search in a cube volume rather than a sphere. + * Note that this does not exclude any entities; if any specific entities are to be excluded this must be + * checked when iterating through the list. + * @see {@link WizardryUtilities#getEntitiesWithinRadius(double, double, double, double, World)} + * @param radius The search radius + * @param x The x coordinate to search around + * @param y The y coordinate to search around + * @param z The z coordinate to search around + * @param world The world to search in + * @param entityType The class of entity to search for; pass in Entity.class for all entities + */ + public static List getEntitiesWithinRadius(double radius, double x, double y, double z, World world, Class entityType){ + AxisAlignedBB aabb = new AxisAlignedBB(x - radius, y - radius, z - radius, x + radius, y + radius, z + radius); + List entityList = world.getEntitiesWithinAABB(entityType, aabb); + for(int i=0;i radius){ + entityList.remove(i); + } + } + return entityList; + } + + /** + * Gets an entity from its UUID. Note that you should check this isn't null. If the UUID is known to belong + * to an EntityPlayer, use the more efficient {@link World#getPlayerEntityByUUID(UUID)} instead. + * @param world The world the entity is in + * @param id The entity's UUID + * @return The Entity that has the given UUID, or null if no such entity exists in the specified world. + */ + @Nullable + public static Entity getEntityByUUID(World world, UUID id){ + + for(Entity entity : world.loadedEntityList){ + // This is a perfect example of where you need to use .equals() and not ==. For most applications, + // this was unnoticeable until world reload because the UUID instance or entity instance is stored. + // Fixed now though. + if(entity.getUniqueID().equals(id)){ + return entity; + } + } + return null; + } + + // No point allowing anything other than players for these methods since other entities can use Entity#playSound. + + /** Shortcut for {@link World#playSound(EntityPlayer, double, double, double, SoundEvent, SoundCategory, float, float)} + * where the player is null but the x, y and z coordinates are those of the passed in player. Use in preference to + * {@link EntityPlayer#playSound(SoundEvent, float, float)} if there are client-server discrepancies. */ + public static void playSoundAtPlayer(EntityPlayer player, SoundEvent sound, SoundCategory category, float volume, float pitch){ + player.worldObj.playSound(null, player.posX, player.posY, player.posZ, sound, category, volume, pitch); + } + + /** See {@link WizardryUtilities#playSoundAtPlayer(EntityPlayer, SoundEvent, SoundCategory, float, float)}. Category + * defaults to {@link SoundCategory#PLAYERS}. */ + public static void playSoundAtPlayer(EntityPlayer player, SoundEvent sound, float volume, float pitch){ + player.worldObj.playSound(null, player.posX, player.posY, player.posZ, sound, SoundCategory.PLAYERS, volume, pitch); + } + + /** + * Returns the entity riding the given entity, or null if there is none. Allows for neater code now that + * entities have a list of passengers, because it is necessary to check that the list is not null or empty first. + */ + @Nullable + public static Entity getRider(Entity entity){ + return entity.getPassengers() != null && !entity.getPassengers().isEmpty() ? entity.getPassengers().get(0) : null; + } + + /** + * Attacks the given entity with the given damage source and amount, but preserving the entity's original velocity + * instead of applying knockback, as would happen with {@link EntityLivingBase#attackEntityFrom(DamageSource, float)} + * (More accurately, calls that method as normal and then resets the entity's velocity to what it was before). + * Handy for when you need to damage an entity repeatedly in a short space of time. + * @param entity The entity to attack + * @param source The source of the damage + * @param amount The amount of damage to apply + * @return True if the attack succeeded, false if not. + */ + public static boolean attackEntityWithoutKnockback(Entity entity, DamageSource source, float amount){ + double vx = entity.motionX; double vy = entity.motionY; double vz = entity.motionZ; + boolean succeeded = entity.attackEntityFrom(source, amount); + entity.motionX = vx; entity.motionY = vy; entity.motionZ = vz; + return succeeded; + } + + /** + * Applies the standard (non-enchanted) amount of knockback to the given target, using the same calculation as + * {@link EntityLivingBase#attackEntityFrom(DamageSource, float)}. Use in conjunction with + * {@link WizardryUtilities#attackEntityWithoutKnockback(Entity, DamageSource, float)} to change the source of + * knockback for an attack. + * @param attacker The entity that caused the knockback; the target will be pushed away from this entity. + * @param target The entity to be knocked back. + */ + public static void applyStandardKnockback(Entity attacker, EntityLivingBase target){ + double dx = attacker.posX - target.posX; + double dz; + for(dz = attacker.posZ - target.posZ; dx * dx + dz * dz < 1.0E-4D; dz = (Math.random() - Math.random()) * 0.01D){ + dx = (Math.random() - Math.random()) * 0.01D; + } + // The first argument is never used. + target.knockBack(null, 0.4f, dx, dz); + } + + // Just what benefit does having posY be the eye position on the first person client actually give? + + /** + * Gets the y coordinate of the given player's eyes. This is to cover an inconsistency between the value of + * EntityPlayer.posY on the first person client and everywhere else; in first person (i.e. when + * Minecraft.getMinecraft().thePlayer == player) player.posY is the eye position, but everywhere else it is the + * feet position. This is intended for use when spawning particles, since this is the only situation where the + * discrepancy is likely to matter. + *

    + * As of Wizardry 1.2, this is just a shorthand for:

    + *

    player.getEntityBoundingBox().minY + player.getEyeHeight()
    + */ + public static double getPlayerEyesPos(EntityPlayer player){ + return player.getEntityBoundingBox().minY + player.getEyeHeight(); + } + + /** Returns a list of the itemstacks in the given player's hotbar. Defined here for convenience and to + * centralise the (unfortunately unavoidable) use of hardcoded numbers to reference the inventory slots. The + * returned list is a modifiable copy of part of the player's inventory stack list; as such, changes to the list + * are not written through to the player's inventory. However, the ItemStack instances themselves are not + * copied, so changes to any of their fields (size, metadata...) will change those in the player's inventory. + * @since Wizardry 1.2 */ + public static List getHotbar(EntityPlayer player){ + return new ArrayList(Arrays.asList(player.inventory.mainInventory).subList(0, 9)); + } + + /** Returns a list of the itemstacks in the given player's hotbar and offhand, sorted into the following order: + * main hand, offhand, rest of hotbar left-to-right. The returned list is a modifiable copy of part of the player's + * inventory stack list; as such, changes to the list are not written through to the player's inventory. + * However, the ItemStack instances themselves are not copied, so changes to any of their fields (size, metadata...) + * will change those in the player's inventory. + * @since Wizardry 1.2 */ + public static List getPrioritisedHotbarAndOffhand(EntityPlayer player){ + List hotbar = WizardryUtilities.getHotbar(player); + // Adds the offhand item to the beginning of the list so it is processed before the hotbar + hotbar.add(0, player.getHeldItemOffhand()); + // Moves the item in the main hand to the beginning of the list so it is processed first + hotbar.remove(player.getHeldItemMainhand()); + hotbar.add(0, player.getHeldItemMainhand()); + return hotbar; + } + + /** Tests whether the specified player has any of the specified item in their entire inventory, including armour + * slots and offhand. */ + public static boolean doesPlayerHaveItem(EntityPlayer player, Item item){ + + for(ItemStack stack : player.inventory.mainInventory){ + if(stack != null && stack.getItem() == item){ + return true; + } + } + + for(ItemStack stack : player.inventory.armorInventory){ + if(stack != null && stack.getItem() == item){ + return true; + } + } + + for(ItemStack stack : player.inventory.offHandInventory){ + if(stack != null && stack.getItem() == item){ + return true; + } + } + + return false; + } + + /** Checks if the given player is opped on the given server. If the server is a singleplayer or LAN server, this + * means they have cheats enabled. */ + public static boolean isPlayerOp(EntityPlayer player, MinecraftServer server){ + return server.getPlayerList().getOppedPlayers().getEntry(player.getGameProfile()) != null; + } + + /** Turns the given creeper into a charged creeper. In 1.10, this requires reflection since the DataManager keys + * are private. (You could call {@link EntityCreeper#onStruckByLightning(...)} and then heal it and + * extinguish it, but that's a bit awkward.) */ + public static void chargeCreeper(EntityCreeper creeper){ + creeper.getDataManager().set(POWERED, true); + } + + // SECTION Raytracing + // =============================================================================================================== + + /** + * Does a block ray trace (NOT entities) from an entity's eyes (i.e. properly...) + */ + @Nullable + public static RayTraceResult rayTrace(double range, World world, EntityLivingBase entity, boolean hitLiquids){ + + Vec3d start = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ); + Vec3d look = entity.getLookVec(); + Vec3d end = start.addVector(look.xCoord * range, look.yCoord * range, look.zCoord * range); + return world.rayTraceBlocks(start, end, hitLiquids); + } + + /** + * Helper method which does a rayTrace for entities from an entity's eye level in the direction they are looking + * with a specified range, using the tracePath method. Tidies up the code a bit. Border size defaults to 1. + * + * @param world + * @param entity + * @param range + * @return + */ + @Nullable + public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range){ + double dx = entity.getLookVec().xCoord * range; + double dy = entity.getLookVec().yCoord * range; + double dz = entity.getLookVec().zCoord * range; + HashSet hashset = new HashSet(1); + hashset.add(entity); + return WizardryUtilities.tracePath(world, (float)entity.posX, (float)(entity.getEntityBoundingBox().minY + entity.getEyeHeight()), (float)entity.posZ, (float)(entity.posX + dx), (float)(entity.posY + entity.getEyeHeight() + dy), (float)(entity.posZ + dz), 1.0f, hashset, false); + } + + /** + * Helper method which does a rayTrace for entities from a entity's eye level in the direction they are looking + * with a specified range and radius, using the tracePath method. Tidies up the code a bit. + * + * @param world + * @param entity + * @param range + * @param borderSize + * @return + */ + @Nullable + public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range, float borderSize){ + double dx = entity.getLookVec().xCoord * range; + double dy = entity.getLookVec().yCoord * range; + double dz = entity.getLookVec().zCoord * range; + HashSet hashset = new HashSet(1); + hashset.add(entity); + return WizardryUtilities.tracePath(world, (float)entity.posX, (float)(entity.getEntityBoundingBox().minY + entity.getEyeHeight()), (float)entity.posZ, (float)(entity.posX + dx), (float)(entity.posY + entity.getEyeHeight() + dy), (float)(entity.posZ + dz), borderSize, hashset, false); + } + + /** + * Method for ray tracing entities (the useless default method doesn't work, despite EnumHitType having an ENTITY field...) + * You can also use this for seeking. + * + * @param world + * @param x startX + * @param y startY + * @param z startZ + * @param tx endX + * @param ty endY + * @param tz endZ + * @param borderSize extra area to examine around line for entities + * @param excluded any excluded entities (the player, etc) + * @return a RayTraceResult of either the block hit (no entity hit), the entity hit (hit an entity), or null for nothing hit + */ + @Nullable + public static RayTraceResult tracePath(World world, float x, float y, float z, float tx, float ty, float tz, float borderSize, HashSet excluded, boolean collideablesOnly){ + + Vec3d startVec = new Vec3d(x, y, z); + //Vec3d lookVec = new Vec3d(tx-x, ty-y, tz-z); + Vec3d endVec = new Vec3d(tx, ty, tz); + float minX = x < tx ? x : tx; + float minY = y < ty ? y : ty; + float minZ = z < tz ? z : tz; + float maxX = x > tx ? x : tx; + float maxY = y > ty ? y : ty; + float maxZ = z > tz ? z : tz; + AxisAlignedBB bb = new AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ).expand(borderSize, borderSize, borderSize); + List allEntities = world.getEntitiesWithinAABBExcludingEntity(null, bb); + RayTraceResult blockHit = world.rayTraceBlocks(startVec, endVec); + startVec = new Vec3d(x, y, z); + endVec = new Vec3d(tx, ty, tz); + float maxDistance = (float) endVec.distanceTo(startVec); + if(blockHit!=null) + { + maxDistance = (float) blockHit.hitVec.distanceTo(startVec); + } + Entity closestHitEntity = null; + float closestHit = maxDistance; + float currentHit = 0.f; + AxisAlignedBB entityBb;// = ent.getBoundingBox(); + RayTraceResult intercept; + for(Entity ent : allEntities) + { + if((ent.canBeCollidedWith() || !collideablesOnly) && ((excluded != null && !excluded.contains(ent)) || excluded == null)) + { + float entBorder = ent.getCollisionBorderSize(); + entityBb = ent.getEntityBoundingBox(); + if(entityBb!=null) + { + entityBb = entityBb.expand(entBorder, entBorder, entBorder); + intercept = entityBb.calculateIntercept(startVec, endVec); + if(intercept!=null) + { + currentHit = (float) intercept.hitVec.distanceTo(startVec); + if(currentHit < closestHit || currentHit==0) + { + closestHit = currentHit; + closestHitEntity = ent; + } + } + } + } + } + if(closestHitEntity!=null) + { + blockHit = new RayTraceResult(closestHitEntity); + } + return blockHit; + } + + // SECTION Rendering and GUIs + // =============================================================================================================== + + // Doesn't seem right to put this in the proxies since it should only ever be called from client-side code, and I'm + // not about to make a whole separate utilities class just for one method. Fully qualified names it is! + /** + * [Client-side only] Draws a textured rectangle, taking the size of the image and the bit needed into + * account, unlike {@link net.minecraft.client.gui.Gui#drawTexturedModalRect(int, int, int, int, int, int) + * Gui.drawTexturedModalRect(int, int, int, int, int, int)}, which is harcoded for only 256x256 textures. Also + * handy for custom potion icons. + * @param x The x position of the rectangle + * @param y The y position of the rectangle + * @param u The x position of the top left corner of the section of the image wanted + * @param v The y position of the top left corner of the section of the image wanted + * @param width The width of the section + * @param height The height of the section + * @param textureWidth The width of the actual image. + * @param textureHeight The height of the actual image. + */ + @SideOnly(Side.CLIENT) + public static void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight){ + + float f = 1F / (float)textureWidth; + float f1 = 1F / (float)textureHeight; + + // Essentially the same as getting the tessellator. For most code, you'll want the tessellator AND the vertexbuffer + // stored in local variables. + net.minecraft.client.renderer.VertexBuffer buffer = net.minecraft.client.renderer.Tessellator.getInstance().getBuffer(); + // Equivalent of tessellator.startDrawingQuads() + buffer.begin(org.lwjgl.opengl.GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + // Equivalent of tessellator.addVertex() + buffer.pos((double)(x), (double)(y + height), 0).tex((double)((float)(u) * f), (double)((float)(v + height) * f1)).endVertex(); + buffer.pos((double)(x + width), (double)(y + height), 0).tex((double)((float)(u + width) * f), (double)((float)(v + height) * f1)).endVertex(); + buffer.pos((double)(x + width), (double)(y), 0).tex((double)((float)(u + width) * f), (double)((float)(v) * f1)).endVertex(); + buffer.pos((double)(x), (double)(y), 0).tex((double)((float)(u) * f), (double)((float)(v) * f1)).endVertex(); + // Exactly the same as before. + net.minecraft.client.renderer.Tessellator.getInstance().draw(); + } + + /** Shorthand for {@link WizardryUtilities#drawTexturedRect(int, int, int, int, int, int, int, int)} which draws + * the entire texture (u and v are set to 0 and textureWidth and textureHeight are the same as width and height). */ + @SideOnly(Side.CLIENT) + public static void drawTexturedRect(int x, int y, int width, int height){ + drawTexturedRect(x, y, 0, 0, width, height, width, height); + } + + // SECTION NBT and Data Storage + // =============================================================================================================== + + /** + * Verifies that the given string is a valid string representation of a UUID. More specifically, returns true if and + * only if the given string is not null and matches the regular expression:

    + *

    /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/

    + * which is the regex equivalent of the standard string representation of a UUID as described in {@link UUID#toString()}. + * This method is intended to be used as a check to prevent an {@link IllegalArgumentException} from occurring when + * calling {@link UUID#fromString(String)}. + * @param string The string to be checked + * @return Whether the given string is a valid string representation of a UUID + * @deprecated UUIDs can now be stored in NBT directly; use that in preference to storing them as strings. + */ + @Deprecated + public static boolean verifyUUIDString(String string){ + return string != null && string.matches("/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/"); + } + + /** Generic method that stores any Map to an NBTTagList, given two functions that convert the key and value + * types in that map to subclasses of NBTBase. For what it's worth, there is very little point in using this unless + * you can use something more concise than an anonymous class to do the conversion. A lambda expression, or better, + * a method reference, would fit nicely. For example, take ExtendedPlayer's use of this to store conjured item + * durations: + *

    + * properties.setTag("conjuredItems", WizardryUtilities.mapToNBT(this.conjuredItemDurations, + * item -> new NBTTagInt(Item.getIdFromItem((Item)item)), NBTTagInt::new)); + *

    + * This is a lot nicer than simply iterating through the map, because for that you need to use the entry list, + * which introduces local variables that aren't really necessary. Notice that, since the values V in the map are + * simply Integer objects, a simple constructor reference to NBTTagInt::new can be used instead of a lambda + * expression (the Integer is auto-unboxed to int). + * + * @param The type of key stored in the given Map. + * @param The type of value stored in the given Map. + * @param The subtype of NBTBase that the keys (of type K) will be converted to. + * @param The subtype of NBTBase that the values (of type V) will be converted to. + * @param map The Map to be stored. + * @param keyFunction A Function that converts the keys in the map to NBT objects that can be stored. + * @param valueFunction A Function that converts the values in the map to NBT objects that can be stored. + * @param keyTagName The tag name to use for the key tags. + * @param valueTagName The tag name to use for the value tags. + * @return An NBTTagList that represents the given Map. + */ + public static NBTTagList mapToNBT(Map map, Function keyFunction, Function valueFunction, String keyTagName, String valueTagName){ + + NBTTagList tagList = new NBTTagList(); + + for(Entry entry : map.entrySet()){ + NBTTagCompound mapping = new NBTTagCompound(); + mapping.setTag(keyTagName, keyFunction.apply(entry.getKey())); + mapping.setTag(valueTagName, valueFunction.apply(entry.getValue())); + tagList.appendTag(mapping); + } + + return tagList; + } + + /** See {@link WizardryUtilities#mapToNBT(Map, Function, Function, String, String)}; this version is for when the + * names of the individual key/value tags are unimportant (they default to "key" and "value" respectively). */ + public static NBTTagList mapToNBT(Map map, Function keyFunction, Function valueFunction){ + return mapToNBT(map, keyFunction, valueFunction, "key", "value"); + } + + /** Generic method that reads a Map from an NBTTagList, given two functions that convert the key and value tag types + * into the key and value types in the returned map. The given NBTTagList remains unchanged after calling this method. + * + * @param The type of key stored in the returned Map. + * @param The type of value stored in the returned Map. + * @param The subtype of NBTBase that the keys are stored as. + * @param The subtype of NBTBase that the values are stored as. + * @param tagList The NBTTagList to be converted. This must be a list of compound tags. + * @param keyFunction A Function that converts the generic NBTBase tags in the list to keys of type K for the map. + * @param valueFunction A Function that converts the generic NBTBase tags in the list to values of type V for the map. + * @param keyTagName The tag name used for the key tags. + * @param valueTagName The tag name used for the value tags. + * @return A Map containing the keys and values stored in the given NBTTagList. Can be empty, but not null. + * @throws ClassCastException If the tags are not of the expected type. + * @see WizardryUtilities#mapToNBT(Map, Function, Function, String, String) + */ + @SuppressWarnings("unchecked") // Intentional, because throwing an exception is appropriate here. + public static Map NBTToMap(NBTTagList tagList, Function keyFunction, Function valueFunction, String keyTagName, String valueTagName){ + + Map map = new HashMap(); + + for(int i=0; i Map NBTToMap(NBTTagList tagList, Function keyFunction, Function valueFunction){ + return NBTToMap(tagList, keyFunction, valueFunction, "key", "value"); + } + + /** Generic method that stores any Collection to an NBTTagList, given a function that converts the elements in + * that collection to subclasses of NBTBase. For what it's worth, there is very little point in using this unless + * you can use something more concise than an anonymous class to do the conversion. A lambda expression, or better, + * a method reference, would fit nicely. + * + * @param The type of element stored in the given Collection. + * @param The NBT tag type that the elements will be converted to. + * @param list The Collection to be stored. + * @param function A Function that converts the elements in the collection to NBT objects that can be stored. + * @return An NBTTagList that represents the given Collection. + */ + public static NBTTagList listToNBT(Collection list, Function function){ + + NBTTagList tagList = new NBTTagList(); + // If the collection is ordered, it will preserve the order, even though we don't know what type it is yet. + for(E element : list){ + tagList.appendTag(function.apply(element)); + } + + return tagList; + } + + /** Generic method that reads a Collection from an NBTTagList, given a function that converts the element tag + * types to the element types in the returned collection. The given NBTTagList remains unchanged after calling this + * method. Unless the target variable for this method is of type Collection, you will need to create a new + * collection containing the elements in the returned collection via that collection's constructor (e.g. {@code new + * HashSet(collection)}). Although this method returns a Collection rather than any of its subtypes, it + * uses an ArrayList internally to guarantee the order of the elements in the returned collection is the same + * as the order in which they were stored. As such, you may safely cast to List should you wish. + * + * @param The type of element stored in the returned Collection. + * @param The subtype of NBTBase that the elements are stored as. + * @param tagList The NBTTagList to be converted. + * @param function A Function that converts the generic NBTBase tags in the list to elements for the collection. + * Chances are you will need to cast the NBTBase tag to whichever NBT tag type you are expecting in order to + * access the appropriate getter method. + * @return A Collection containing the elements stored in the given NBTTagList. Can be empty, but not null. + * @throws ClassCastException If the tags are not of the expected type. + */ + @SuppressWarnings("unchecked") // Intentional, because throwing an exception is appropriate here. + public static Collection NBTToList(NBTTagList tagList, Function function){ + // Uses an ArrayList to guarantee iteration order, and also to permit duplicate elements (which are + // perfectly reasonable in this context). + Collection list = new ArrayList(); + // The original tag list should remain unchanged, hence the copy. + NBTTagList tagList2 = (NBTTagList) tagList.copy(); + + while(!tagList2.hasNoTags()){ + NBTBase tag = tagList2.removeTag(0); + // Why oh why is NBTTagList not parametrised? It even has a tagType field, so it must know! + try { list.add(function.apply((T)tag)); } catch (ClassCastException e){ + Wizardry.logger.error("Error when reading list from NBT: unexpected tag type " + NBTBase.NBT_TYPES[tag.getId()], e); + } + } + + return list; + + } + + // TODO: Backport: It has recently become apparent that storing UUIDs as strings is not good practice, so backport these two + // methods to 1.7.10 and replace tag.setUniqueId and tag.getUniqueId with their respective contents from 1.10.2. + + /** Returns an NBTTagCompound which contains only the given UUID, stored using + * {@link NBTTagCompound#setUniqueId(String, UUID)}. Allows for neater storage to NBTTagLists. */ + public static NBTTagCompound UUIDtoTagCompound(UUID id){ + NBTTagCompound tag = new NBTTagCompound(); + tag.setUniqueId("uuid", id); + return tag; + } + + /** Wrapper for {@link NBTTagCompound#getUniqueId(String)} which converts an NBTTagCompound directly to a UUID. + * Intended to be used as the inverse of {@link WizardryUtilities#UUIDtoTagCompound(UUID)}.*/ + public static UUID tagCompoundToUUID(NBTTagCompound tag){ + return tag.getUniqueId("uuid"); + } + + // SECTION Ally Designation System + // =============================================================================================================== + + /** + * Returns whether the given target can be attacked by the given attacker. It is up to the caller of this method + * to work out what this means; it doesn't necessarily mean the target is completely immune (for example, revenge + * targeting might reasonably bypass this). This method is intended for use where the damage is indirect and/or + * unavoidable; direct attacks should not check this method. Currently this means the following situations check + * this method: + *

    + * - AI targeting for summoned creatures
    + * - AI targeting for mind-controlled creatures
    + * - Constructs with an area of effect
    + * - Instantaneous spells with an area of effect around the caster (e.g. forest's curse, thunderstorm)
    + * - Any lightning chaining effects
    + * - Any projectiles which seek targets + *

    + * Also note that the friendly fire option is dealt with + * in the event handler. This method acts as a sort of wrapper for all the ADS stuff in {@link WizardData}; more + * details about the ally designation system can be found there. + * + * @param attacker The entity that cast the spell originally + * @param target The entity being attacked + * + * @return False under any of the following circumstances, true otherwise: + *

    + * - Either entity is null + *

    + * - The target is the attacker (this isn't as stupid as it sounds - anything with an AoE might cause this to be + * true, as can summoned creatures) + *

    + * - The target and the attacker are both players and the target is an ally of the attacker (but the + * attacker need not be an ally of the target) + *

    + * - The target is a creature that was summoned/controlled by the attacker or by an ally of the attacker. + */ + public static boolean isValidTarget(Entity attacker, Entity target){ + + if(attacker == null || target == null) return false; + + // Tests whether the target is the attacker + if(target == attacker) return false; + + // Tests whether the target is a creature that was summoned by the attacker + if(target instanceof ISummonedCreature && ((ISummonedCreature)target).getCaster() == attacker){ + return false; + } + + // Tests whether the target is a creature that was mind controlled by the attacker + if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(WizardryPotions.mind_control)){ + + NBTTagCompound entityNBT = target.getEntityData(); + + if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){ + if(attacker == WizardryUtilities.getEntityByUUID(target.worldObj, entityNBT.getUniqueId(MindControl.NBT_KEY))){ + return false; + } + } + } + + // Ally section + if(attacker instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker) != null){ + + if(target instanceof EntityPlayer){ + // Tests whether the target is an ally of the attacker + if(WizardData.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)target)){ + return false; + } + + }else if(target instanceof ISummonedCreature){ + // Tests whether the target is a creature that was summoned by an ally of the attacker + if(((ISummonedCreature)target).getCaster() instanceof EntityPlayer + && WizardData.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)((ISummonedCreature)target).getCaster())){ + return false; + } + + }else if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(WizardryPotions.mind_control)){ + // Tests whether the target is a creature that was mind controlled by an ally of the attacker + NBTTagCompound entityNBT = target.getEntityData(); + + if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){ + + Entity controller = WizardryUtilities.getEntityByUUID(target.worldObj, entityNBT.getUniqueId(MindControl.NBT_KEY)); + + if(controller instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)controller)){ + return false; + } + } + } + } + + return true; + } + + /** Helper method for testing if the second player is an ally of the first player. Makes the code neater. */ + public static boolean isPlayerAlly(EntityPlayer allyOf, EntityPlayer possibleAlly) { + + WizardData properties = WizardData.get(allyOf); + + if(properties != null && properties.isPlayerAlly(possibleAlly)) return true; + + return false; + } + + // SECTION Loot and Weighting + // =============================================================================================================== + + /** + * See {@link WizardryUtilities#getStandardWeightedRandomSpellId(Random, boolean)}. nonContinuous defaults to false. + */ + public static int getStandardWeightedRandomSpellId(Random random){ + return getStandardWeightedRandomSpellId(random, false); + } + + /** + * Helper method which gets a spell id according to the standard weighting. The tier is a weighted random value; + * the actual spell within that tier is completely random. Will not return the id of a spell which has been + * disabled in the config. This is for simple stuff like chests and drops; more complex generators like wizard + * trades don't use this method. + *

    + * For reference, the standard weighting is as follows: + * Basic: 60%, Apprentice: 25%, Advanced: 10%, Master: 5% + * + * @param random An instance of {@link Random} to use for RNG + * @param nonContinuous Whether the spells must be non-continuous (used for scrolls) + * @return A random spell id number + */ + public static int getStandardWeightedRandomSpellId(Random random, boolean nonContinuous){ + + Tier tier = Tier.getWeightedRandomTier(random); + + List spells = Spell.getSpells(new Spell.TierElementFilter(tier, null)); + if(nonContinuous) spells.retainAll(Spell.getSpells(Spell.nonContinuousSpells)); + + // Ensures the tier chosen actually has spells in it, and if not uses BASIC instead. + if(spells.isEmpty()){ + spells = Spell.getSpells(new Spell.TierElementFilter(Tier.BASIC, null)); + if(nonContinuous) spells.retainAll(Spell.getSpells(Spell.nonContinuousSpells)); + } + + // Finds a random spell in the list and returns its id. + return spells.get(random.nextInt(spells.size())).id(); + } + + // TODO: These methods need a rethink. What are we trying to achieve with them? Should each use case look in the same + // pool of items? For example, might we (or someone else) want to have a wand which can generate in chests, but is + // not used by wizards? + + // I reckon this should be strictly for cases where we only ever want the standard wand set, i.e. wizards' gear, etc. + + /** + * Helper method to return the appropriate armour item based on element and slot. As of Wizardry 2.1, this uses + * the immutable map stored in {@link WizardryItems#ARMOUR_MAP}. + * Currently used to iterate through armour for registering charging recipes and for chest generation. + * @param element The EnumElement of the armour required. Null will be converted to {@link Element#MAGIC}. + * @param slot EntityEquipmentSlot of the armour piece required + * @return The armour item which corresponds to the given element and slot, or null if no such item exists. + * @throws IllegalArgumentException if the given slot is not an armour slot. + */ + public static Item getArmour(Element element, EntityEquipmentSlot slot){ + if(slot == null || slot.getSlotType() != Type.ARMOR) throw new IllegalArgumentException("Must be a valid armour slot"); + if(element == null) element = Element.MAGIC; + return WizardryItems.ARMOUR_MAP.get(ImmutablePair.of(slot, element)); + } + + /** + * Helper method to return the appropriate wand based on tier and element.As of Wizardry 2.1, this uses + * the immutable map stored in {@link WizardryItems#WAND_MAP}. + * Currently used in the packet handler for upgrading wands, for chest generation and to iterate through + * wands for charging recipes. + * @param tier The tier of the wand required. + * @param element The element of the wand required. Null will be converted to {@link Element#MAGIC}. + * @return The wand item which corresponds to the given element and slot, or null if no such item exists. + * @throws NullPointerException if the given tier is null. + */ + public static Item getWand(Tier tier, Element element){ + if(tier == null) throw new NullPointerException("The given tier cannot be null."); + return WizardryItems.WAND_MAP.get(ImmutablePair.of(tier, element)); + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/arcane_workbench.json b/src/main/resources/assets/wizardry/blockstates/arcane_workbench.json new file mode 100644 index 00000000..c5741b8e --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/arcane_workbench.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:arcane_workbench" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/crystal_block.json b/src/main/resources/assets/wizardry/blockstates/crystal_block.json new file mode 100644 index 00000000..d5ed94e1 --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/crystal_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:crystal_block" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/crystal_flower.json b/src/main/resources/assets/wizardry/blockstates/crystal_flower.json new file mode 100644 index 00000000..61e2d72c --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/crystal_flower.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "wizardry:crystal_flower" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/crystal_ore.json b/src/main/resources/assets/wizardry/blockstates/crystal_ore.json new file mode 100644 index 00000000..234c9a97 --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/crystal_ore.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:crystal_ore" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/ice_statue.json b/src/main/resources/assets/wizardry/blockstates/ice_statue.json new file mode 100644 index 00000000..e2c0b099 --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/ice_statue.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:ice_statue" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/magic_light.json b/src/main/resources/assets/wizardry/blockstates/magic_light.json new file mode 100644 index 00000000..df809b83 --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/magic_light.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:magic_light" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/meteor.json b/src/main/resources/assets/wizardry/blockstates/meteor.json new file mode 100644 index 00000000..f1d33b5b --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/meteor.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:meteor" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/petrified_stone.json b/src/main/resources/assets/wizardry/blockstates/petrified_stone.json new file mode 100644 index 00000000..c8495ade --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/petrified_stone.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:petrified_stone" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/snare.json b/src/main/resources/assets/wizardry/blockstates/snare.json new file mode 100644 index 00000000..594eb529 --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/snare.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:snare" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/spectral_block.json b/src/main/resources/assets/wizardry/blockstates/spectral_block.json new file mode 100644 index 00000000..79efd6b9 --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/spectral_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:spectral_block" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/transportation_stone.json b/src/main/resources/assets/wizardry/blockstates/transportation_stone.json new file mode 100644 index 00000000..67830c59 --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/transportation_stone.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:transportation_stone" } + } +} diff --git a/src/main/resources/assets/wizardry/blockstates/vanishing_cobweb.json b/src/main/resources/assets/wizardry/blockstates/vanishing_cobweb.json new file mode 100644 index 00000000..ce86f118 --- /dev/null +++ b/src/main/resources/assets/wizardry/blockstates/vanishing_cobweb.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "wizardry:vanishing_cobweb" } + } +} diff --git a/src/main/resources/assets/wizardry/lang/en_GB.lang b/src/main/resources/assets/wizardry/lang/en_GB.lang new file mode 100644 index 00000000..fc660274 --- /dev/null +++ b/src/main/resources/assets/wizardry/lang/en_GB.lang @@ -0,0 +1,738 @@ +tile.wizardry:arcane_workbench.name=Arcane Workbench +tile.wizardry:crystal_ore.name=Crystal Ore +tile.wizardry:petrified_stone.name=Petrified Stone +tile.wizardry:ice_statue.name=Ice Statue +tile.wizardry:crystal_flower.name=Crystal Flower +tile.wizardry:snare.name=Snare +tile.wizardry:transportation_stone.name=Stone of Transportation +tile.wizardry:spectral_block.name=Spectral Block +tile.wizardry:crystal_block.name=Block of Crystal + +item.wizardry:magic_crystal.name=Magic Crystal +item.wizardry:magic_wand.name=Magic Wand +item.wizardry:apprentice_wand.name=Apprentice Wand +item.wizardry:advanced_wand.name=Advanced Wand +item.wizardry:master_wand.name=Master Wand +item.wizardry:spell_book.name=Spell Book + +item.wizardry:arcane_tome.name=Tome of Arcana +item.wizardry:arcane_tome.desc1=Upgrades any %1$s +item.wizardry:arcane_tome.desc2=wand to %1$s tier + +item.wizardry:wizard_handbook.name=The Wizard's Handbook +item.wizardry:wizard_handbook.desc=by %1$s + +item.wizardry:wand.buff=+%1$s %2$s potency +item.wizardry:wand.spell=Current Spell: %1$s +item.wizardry:wand.mana=Mana: %1$s/%2$s + +item.wizardry:wand.addally=%1$s has been added to your list of allies +item.wizardry:wand.removeally=%1$s has been removed from your list of allies + +item.wizardry:basic_fire_wand.name=Wand of Embers +item.wizardry:basic_ice_wand.name=Wand of Frost +item.wizardry:basic_lightning_wand.name=Wand of Sparks +item.wizardry:basic_necromancy_wand.name=Wand of Shadows +item.wizardry:basic_earth_wand.name=Wand of the Forest +item.wizardry:basic_sorcery_wand.name=Wand of Mystery +item.wizardry:basic_healing_wand.name=Wand of Healing + +item.wizardry:apprentice_fire_wand.name=Apprentice Pyromancer Wand +item.wizardry:apprentice_ice_wand.name=Apprentice Ice Mage Wand +item.wizardry:apprentice_lightning_wand.name=Apprentice Storm Mage Wand +item.wizardry:apprentice_necromancy_wand.name=Apprentice Necromancer Wand +item.wizardry:apprentice_earth_wand.name=Apprentice Earth Mage Wand +item.wizardry:apprentice_sorcery_wand.name=Apprentice Sorcerer Wand +item.wizardry:apprentice_healing_wand.name=Apprentice Healer Wand + +item.wizardry:advanced_fire_wand.name=Wand of the Pyromancer +item.wizardry:advanced_ice_wand.name=Wand of the Ice Mage +item.wizardry:advanced_lightning_wand.name=Wand of the Storm Mage +item.wizardry:advanced_necromancy_wand.name=Wand of the Necromancer +item.wizardry:advanced_earth_wand.name=Wand of the Earth Mage +item.wizardry:advanced_sorcery_wand.name=Wand of the Sorcerer +item.wizardry:advanced_healing_wand.name=Wand of the Healer + +item.wizardry:master_fire_wand.name=Master Pyromancer Wand +item.wizardry:master_ice_wand.name=Master Ice Mage Wand +item.wizardry:master_lightning_wand.name=Master Storm Mage Wand +item.wizardry:master_necromancy_wand.name=Master Necromancer Wand +item.wizardry:master_earth_wand.name=Master Earth Mage Wand +item.wizardry:master_sorcery_wand.name=Master Sorcerer Wand +item.wizardry:master_healing_wand.name=Master Healer Wand + +item.wizardry:spectral_sword.name=Spectral Sword +item.wizardry:spectral_pickaxe.name=Spectral Pickaxe +item.wizardry:spectral_bow.name=Spectral Bow + +item.wizardry:mana_flask.name=Mana Flask +item.wizardry:storage_upgrade.name=Wand Storage Upgrade +item.wizardry:siphon_upgrade.name=Wand Siphon Upgrade +item.wizardry:condenser_upgrade.name=Wand Condenser Upgrade +item.wizardry:range_upgrade.name=Wand Range Upgrade +item.wizardry:duration_upgrade.name=Wand Duration Upgrade +item.wizardry:cooldown_upgrade.name=Wand Cooldown Upgrade +item.wizardry:blast_upgrade.name=Wand Blast Upgrade +item.wizardry:attunement_upgrade.name=Wand Attunement Upgrade + +item.wizardry:flaming_axe.name=Flaming Axe +item.wizardry:frost_axe.name=Frost Axe + +item.wizardry:firebomb.name=Firebomb +item.wizardry:poison_bomb.name=Poison Bomb +item.wizardry:smoke_bomb.name=Smoke Bomb + +item.wizardry:blank_scroll.name=Blank Scroll +item.wizardry:scroll.name=Scroll of %1$s +item.wizardry:scroll.undiscovered.name=Scroll "%1$s" +item.wizardry:identification_scroll.name=Scroll of Identification +item.wizardry:identification_scroll.desc1=%1$sIdentifies an unknown +item.wizardry:identification_scroll.desc2=%1$sspell book or scroll +item.wizardry:identification_scroll.nothing_to_identify=Nothing to identify! + +item.wizardry:armour_upgrade.name=Arcane Seal of Protection +item.wizardry:armour_upgrade.desc1=%1$sUpgrades any wizard armour +item.wizardry:armour_upgrade.desc2=%1$sto make it %2$slegendary + +item.wizardry:magic_silk.name=Magical Silk + +item.wizardry:wizard_armour.legendary=Legendary +item.wizardry:wizard_armour.buff=-%1$s %2$s cost +item.wizardry:wizard_armour.mana=Mana: %1$s/%2$s + +item.wizardry:wizard_hat.name=Wizard Hat +item.wizardry:wizard_robe.name=Wizard Robes +item.wizardry:wizard_leggings.name=Wizard Leggings +item.wizardry:wizard_boots.name=Wizard Boots + +item.wizardry:wizard_hat_fire.name=Pyromancer Hat +item.wizardry:wizard_robe_fire.name=Pyromancer Robes +item.wizardry:wizard_leggings_fire.name=Pyromancer Leggings +item.wizardry:wizard_boots_fire.name=Pyromancer Boots + +item.wizardry:wizard_hat_ice.name=Ice Mage Hat +item.wizardry:wizard_robe_ice.name=Ice Mage Robes +item.wizardry:wizard_leggings_ice.name=Ice Mage Leggings +item.wizardry:wizard_boots_ice.name=Ice Mage Boots + +item.wizardry:wizard_hat_lightning.name=Storm Mage Hat +item.wizardry:wizard_robe_lightning.name=Storm Mage Robes +item.wizardry:wizard_leggings_lightning.name=Storm Mage Leggings +item.wizardry:wizard_boots_lightning.name=Storm Mage Boots + +item.wizardry:wizard_hat_necromancy.name=Necromancer Hat +item.wizardry:wizard_robe_necromancy.name=Necromancer Robes +item.wizardry:wizard_leggings_necromancy.name=Necromancer Leggings +item.wizardry:wizard_boots_necromancy.name=Necromancer Boots + +item.wizardry:wizard_hat_earth.name=Earth Mage Hat +item.wizardry:wizard_robe_earth.name=Earth Mage Robes +item.wizardry:wizard_leggings_earth.name=Earth Mage Leggings +item.wizardry:wizard_boots_earth.name=Earth Mage Boots + +item.wizardry:wizard_hat_sorcery.name=Sorcerer Hat +item.wizardry:wizard_robe_sorcery.name=Sorcerer Robes +item.wizardry:wizard_leggings_sorcery.name=Sorcerer Leggings +item.wizardry:wizard_boots_sorcery.name=Sorcerer Boots + +item.wizardry:wizard_hat_healing.name=Healer Hat +item.wizardry:wizard_robe_healing.name=Healer Robes +item.wizardry:wizard_leggings_healing.name=Healer Leggings +item.wizardry:wizard_boots_healing.name=Healer Boots + +item.wizardry:spawn_wizard.name=Spawn Wizard +item.wizardry:spawn_evil_wizard.name=Spawn Evil Wizard + +item.wizardry:spectral_helmet.name=Spectral Helmet +item.wizardry:spectral_chestplate.name=Spectral Chestplate +item.wizardry:spectral_leggings.name=Spectral Leggings +item.wizardry:spectral_boots.name=Spectral Boots + +entity.wizardry.summonedcreature.nameplate=%1$s's %2$s +entity.wizardry.summonedcreature.nameplate_fallback=Someone's %1$s + +entity.wizardry.zombie_minion.name=Zombie +entity.wizardry.skeleton_minion.name=Skeleton +entity.wizardry.spider_minion.name=Spider +entity.wizardry.blaze_minion.name=Blaze +entity.wizardry.ice_wraith.name=Ice Wraith +entity.wizardry.lightning_wraith.name=Lightning Wraith +entity.wizardry.shadow_wraith.name=Shadow Wraith +entity.wizardry.spirit_wolf.name=Spirit Wolf +entity.wizardry.spirit_horse.name=Spirit Horse +entity.wizardry.ice_giant.name=Ice Giant +entity.wizardry.phoenix.name=Phoenix +entity.wizardry.wizard.name=Wizard +entity.wizardry.magic_slime.name=Magical Slime +entity.wizardry.silverfish_minion.name=Silverfish +entity.wizardry.storm_elemental.name=Storm Elemental +entity.wizardry.evil_wizard.name=Wizard +entity.wizardry.decoy.name=Decoy + +entity.wizardry.magic_missile.name=Magic +entity.wizardry.arc.name=Magic +entity.wizardry.spark_bomb.name=Magic +entity.wizardry.ice_shard.name=Magic +entity.wizardry.firebomb.name=Magic +entity.wizardry.poison_bomb.name=Magic +entity.wizardry.force_orb.name=Magic +entity.wizardry.spark.name=Magic +entity.wizardry.darkness_orb.name=Magic +entity.wizardry.fire_sigil.name=Magic +entity.wizardry.frost_sigil.name=Magic +entity.wizardry.lightning_sigil.name=Magic +entity.wizardry.lightning_arrow.name=Magic +entity.wizardry.firebolt.name=Magic +entity.wizardry.ice_charge.name=Magic +entity.wizardry.force_arrow.name=Magic +entity.wizardry.dart.name=Magic +entity.wizardry.lightning_disc.name=Magic +entity.wizardry.thunderbolt.name=Magic +entity.wizardry.decay.name=Magic +entity.wizardry.ice_lance.name=Magic +entity.wizardry.smoke_bomb.name=Magic +entity.wizardry.ice_spike.name=Magic + +entity.wizardry.black_hole.name=Black Hole +entity.wizardry.shield.name=Shield +entity.wizardry.meteor.name=Meteor +entity.wizardry.blizzard.name=Blizzard +entity.wizardry.bubble.name=Bubble +entity.wizardry.tornado.name=Tornado +entity.wizardry.lightning_hammer.name=Lightning Hammer +entity.wizardry.arrow_rain.name=Arrow Rain +entity.wizardry.healing_aura.name=Healing Aura +entity.wizardry.forcefield.name=Forcefield +entity.wizardry.ring_of_fire.name=Ring of Fire +entity.wizardry.earthquake.name=Earthquake +entity.wizardry.falling_grass.name=Falling Grass +entity.wizardry.hailstorm.name=Hailstorm +entity.wizardry.lightning_pulse.name=Lightning Pulse + +item_group.wizardry=Wizardry +item_group.wizardryspells=Spells + +achievement.crystal=A Curious Crystal... +achievement.crystal.desc=Mine a magic crystal +achievement.arcane_initiate=Arcane Initiate +achievement.arcane_initiate.desc=Craft a magic wand with a gold nugget, a stick and a magic crystal +achievement.apprentice=Wizard's Apprentice +achievement.apprentice.desc=Use a tome of arcana to upgrade your wand +achievement.master=Arcane Master +achievement.master.desc=Obtain a master wand +achievement.all_spells=Mage of All Trades +achievement.all_spells.desc=Cast every single spell in the game +achievement.wizard_trade=Magic Dealing +achievement.wizard_trade.desc=Purchase an item from a wizard +achievement.buy_master_spell=Knowledge is Power +achievement.buy_master_spell.wizardry:desc=Purchase a master spell from a wizard +achievement.freeze_blaze=Not So Hot Now +achievement.freeze_blaze.desc=Freeze a blaze solid +achievement.charge_creeper=It's Gonna Blow +achievement.charge_creeper.desc='Accidentally' charge a creeper +achievement.frankenstein=Frankenstein +achievement.frankenstein.desc=Turn a pig into a zombie pigman using the lightning bolt spell +achievement.special_upgrade=Arcane Tinkering +achievement.special_upgrade.desc=Apply a special upgrade to a wand +achievement.craft_flask=It's Magic, Bottled! +achievement.craft_flask.desc=Craft a mana flask +achievement.elemental=Elemental +achievement.elemental.desc=Obtain an elemental wand +achievement.armour_set=Now You're a Proper Wizard +achievement.armour_set.desc=Craft and equip a full set of wizard armour +achievement.legendary=Legendary +achievement.legendary.desc=Obtain a piece of legendary wizard armour +achievement.self_destruct=That Backfired +achievement.self_destruct.desc=Get killed by your own magic +achievement.pig_tornado=Not Again... +achievement.pig_tornado.desc=Ride a pig into a tornado +achievement.jam_wizard=Jamming Session +achievement.jam_wizard.desc=Use the arcane jammer spell on a wizard +achievement.slime_skeleton=Sticky Situation +achievement.slime_skeleton.desc=Engulf a skeleton in slime +achievement.anger_wizard=You'll Regret That +achievement.anger_wizard.desc=Make a wizard angry +achievement.defeat_evil_wizard=Righteousness +achievement.defeat_evil_wizard.desc=Defeat an evil wizard +achievement.max_out_wand=Fully Equipped +achievement.max_out_wand.desc=Apply the maximum number of upgrades to a master wand +achievement.element_master=Element Mastery +achievement.element_master.desc=Cast all the spells of any element +achievement.identify_spell=Arcane Appraisal +achievement.identify_spell.wizardry:desc=Use a scroll of identification to identify a spell book or scroll + +tile.wizardry:transportation_stone.confirm=You will now be returned here upon casting %1$s +tile.wizardry:transportation_stone.invalid=You must make a circle with 8 stones of transportation first! + +container.wizardry:arcane_workbench=Arcane Workbench +container.wizardry:arcane_workbench.apply=Apply +container.wizardry:arcane_workbench.mana=Mana: +container.wizardry:arcane_workbench.upgrades=Applied Upgrades: + +tier.basic=Novice +tier.apprentice=Apprentice +tier.advanced=Advanced +tier.master=Master + +element.simple=None +element.fire=Fire +element.ice=Ice +element.lightning=Lightning +element.necromancy=Necromancy +element.earth=Earth +element.sorcery=Sorcery +element.healing=Healing + +element.simple.wizard=Wizard +element.fire.wizard=Pyromancer +element.ice.wizard=Ice Mage +element.lightning.wizard=Storm Mage +element.necromancy.wizard=Necromancer +element.earth.wizard=Earth Mage +element.sorcery.wizard=Sorcerer +element.healing.wizard=Healer + +spelltype.attack=Attack +spelltype.defence=Defence +spelltype.utility=Utility +spelltype.minion=Minion + +spell.disabled=%1$s has been disabled in the config +spell.resist=%1$s resisted %2$s +spell.discover=Discovered the spell %1$s! + +spell.wizardry:agility=Agility +spell.wizardry:arc=Arc +spell.wizardry:arcane_jammer=Arcane Jammer +spell.wizardry:arrow_rain=Arrow Rain +spell.wizardry:banish=Banish +spell.wizardry:black_hole=Black Hole +spell.wizardry:blink=Blink +spell.wizardry:blizzard=Blizzard +spell.wizardry:bubble=Bubble +spell.wizardry:chain_lightning=Chain Lightning +spell.wizardry:clairvoyance=Clairvoyance +spell.wizardry:cobwebs=Cobwebs +spell.wizardry:conjure_armour=Conjure Armour +spell.wizardry:conjure_bow=Conjure Bow +spell.wizardry:conjure_pickaxe=Conjure Pickaxe +spell.wizardry:conjure_sword=Conjure Sword +spell.wizardry:cure_effects=Cure Effects +spell.wizardry:curse_of_soulbinding=Curse of Soulbinding +spell.wizardry:darkness_orb=Darkness Orb +spell.wizardry:darkvision=Darkvision +spell.wizardry:dart=Dart +spell.wizardry:decay=Decay +spell.wizardry:decoy=Decoy +spell.wizardry:detonate=Detonate +spell.wizardry:diamondflesh=Diamondflesh +spell.wizardry:earthquake=Earthquake +spell.wizardry:entrapment=Entrapment +spell.wizardry:fireball=Fireball +spell.wizardry:firebolt=Firebolt +spell.wizardry:firebomb=Firebomb +spell.wizardry:fire_resistance=Fire Resistance +spell.wizardry:fire_sigil=Fire Sigil +spell.wizardry:fireskin=Fireskin +spell.wizardry:firestorm=Firestorm +spell.wizardry:flame_ray=Flame Ray +spell.wizardry:flaming_axe=Flaming Axe +spell.wizardry:flaming_weapon=Flaming Weapon +spell.wizardry:flight=Flight +spell.wizardry:font_of_mana=Font of Mana +spell.wizardry:font_of_vitality=Font of Vitality +spell.wizardry:force_arrow=Force Arrow +spell.wizardry:forcefield=Forcefield +spell.wizardry:force_orb=Force Orb +spell.wizardry:forests_curse=Forest's Curse +spell.wizardry:freeze=Freeze +spell.wizardry:freezing_weapon=Freezing Weapon +spell.wizardry:frost_axe=Frost Axe +spell.wizardry:frost_ray=Frost Ray +spell.wizardry:frost_sigil=Frost Sigil +spell.wizardry:glide=Glide +spell.wizardry:greater_fireball=Greater Fireball +spell.wizardry:greater_heal=Greater Heal +spell.wizardry:group_heal=Group Heal +spell.wizardry:growth_aura=Growth Aura +spell.wizardry:hailstorm=Hailstorm +spell.wizardry:heal=Heal +spell.wizardry:heal_ally=Heal Ally +spell.wizardry:healing_aura=Healing Aura +spell.wizardry:homing_spark=Homing Spark +spell.wizardry:ice_age=Ice Age +spell.wizardry:ice_charge=Ice Charge +spell.wizardry:ice_lance=Ice Lance +spell.wizardry:ice_shard=Ice Shard +spell.wizardry:ice_shroud=Ice Shroud +spell.wizardry:ice_spikes=Ice Spikes +spell.wizardry:ice_statue=Ice Statue +spell.wizardry:ignite=Ignite +spell.wizardry:imbue_weapon=Imbue Weapon +spell.wizardry:intimidate=Intimidate +spell.wizardry:invigorating_presence=Invigorating Presence +spell.wizardry:invisibility=Invisibility +spell.wizardry:invoke_weather=Invoke Weather +spell.wizardry:ironflesh=Ironflesh +spell.wizardry:leap=Leap +spell.wizardry:levitation=Levitation +spell.wizardry:life_drain=Life Drain +spell.wizardry:light=Light +spell.wizardry:lightning_arrow=Lightning Arrow +spell.wizardry:lightning_bolt=Lightning Bolt +spell.wizardry:lightning_disc=Lightning Disc +spell.wizardry:lightning_hammer=Lightning Hammer +spell.wizardry:lightning_pulse=Lightning Pulse +spell.wizardry:lightning_ray=Lightning Ray +spell.wizardry:lightning_sigil=Lightning Sigil +spell.wizardry:lightning_web=Lightning Web +spell.wizardry:magic_missile=Magic Missile +spell.wizardry:metamorphosis=Metamorphosis +spell.wizardry:meteor=Meteor +spell.wizardry:mind_control=Mind Control +spell.wizardry:mind_trick=Mind Trick +spell.wizardry:none=[Empty Slot] +spell.wizardry:oakflesh=Oakflesh +spell.wizardry:petrify=Petrify +spell.wizardry:phase_step=Phase Step +spell.wizardry:plague_of_darkness=Plague of Darkness +spell.wizardry:pocket_furnace=Pocket Furnace +spell.wizardry:pocket_workbench=Pocket Workbench +spell.wizardry:poison=Poison +spell.wizardry:poison_bomb=Poison Bomb +spell.wizardry:replenish_hunger=Replenish Hunger +spell.wizardry:ring_of_fire=Ring of Fire +spell.wizardry:shadow_ward=Shadow Ward +spell.wizardry:shield=Shield +spell.wizardry:shockwave=Shockwave +spell.wizardry:silverfish_swarm=Silverfish Swarm +spell.wizardry:sixth_sense=Sixth Sense +spell.wizardry:slime=Slime +spell.wizardry:smoke_bomb=Smoke Bomb +spell.wizardry:snare=Snare +spell.wizardry:snowball=Snowball +spell.wizardry:spark_bomb=Spark Bomb +spell.wizardry:spectral_pathway=Spectral Pathway +spell.wizardry:spider_swarm=Spider Swarm +spell.wizardry:static_aura=Static Aura +spell.wizardry:summon_blaze=Summon Blaze +spell.wizardry:summon_ice_giant=Summon Ice Giant +spell.wizardry:summon_ice_wraith=Summon Ice Wraith +spell.wizardry:summon_iron_golem=Summon Iron Golem +spell.wizardry:summon_lightning_wraith=Summon Lightning Wraith +spell.wizardry:summon_phoenix=Summon Phoenix +spell.wizardry:summon_shadow_wraith=Summon Shadow Wraith +spell.wizardry:summon_skeleton=Summon Skeleton +spell.wizardry:summon_skeleton_legion=Summon Skeleton Legion +spell.wizardry:summon_snow_golem=Summon Snow Golem +spell.wizardry:summon_spirit_horse=Summon Spirit Horse +spell.wizardry:summon_spirit_wolf=Summon Spirit Wolf +spell.wizardry:summon_storm_elemental=Summon Storm Elemental +spell.wizardry:summon_wither_skeleton=Summon Wither Skeleton +spell.wizardry:summon_zombie=Summon Zombie +spell.wizardry:telekinesis=Telekinesis +spell.wizardry:thunderbolt=Thunderbolt +spell.wizardry:thunderstorm=Thunderstorm +spell.wizardry:tornado=Tornado +spell.wizardry:transience=Transience +spell.wizardry:transportation=Transportation +spell.wizardry:vanishing_box=Vanishing Box +spell.wizardry:wall_of_frost=Wall of Frost +spell.wizardry:water_breathing=Water Breathing +spell.wizardry:whirlwind=Whirlwind +spell.wizardry:wither=Wither +spell.wizardry:wither_skull=Wither Skull + +spell.wizardry:agility.desc=Grants the caster faster movement speed and greater jump height for 30 seconds. +spell.wizardry:arc.desc=Fires a spark of lightning at the target. +spell.wizardry:arcane_jammer.desc=Prevents the target from using magic for 15 seconds. +spell.wizardry:arrow_rain.desc="Archers, fire!" +spell.wizardry:banish.desc=Teleports the target against its will to a random location within a certain range. +spell.wizardry:black_hole.desc=Tear reality asunder. +spell.wizardry:blink.desc=Teleports the caster over a short distance to where they are pointing. +spell.wizardry:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed. +spell.wizardry:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged. +spell.wizardry:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice. +spell.wizardry:clairvoyance.desc=Reveals the path to a remembered location. With this spell selected, sneak-right-click on a block to set the location. Cast this spell normally to reveal the path. The path will fade after 90 seconds. +spell.wizardry:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken. +spell.wizardry:conjure_armour.desc=Creates spectral armour around the caster which offers protection equal to that of iron armour. The armour lasts for 60 seconds. The caster must have an empty armour slot. +spell.wizardry:conjure_bow.desc=Creates a spectral bow with unlimited arrows that lasts for 30 seconds. +spell.wizardry:conjure_pickaxe.desc=Creates a spectral pickaxe of equal strength to an iron pickaxe that lasts for 30 seconds. +spell.wizardry:conjure_sword.desc=Creates a spectral sword of equal strength to an iron sword that lasts for 30 seconds. +spell.wizardry:cure_effects.desc=Removes all potion effects currently affecting the caster, good or bad. +spell.wizardry:curse_of_soulbinding.desc=Causes the target's soul to be inextricably bound to that of the caster, meaning all damage dealt to the caster is also dealt to the victim. Lasts until either the victim or the caster dies. +spell.wizardry:darkness_orb.desc=Fires a slow moving bolt of dark energy in the direction you are pointing, which withers whatever it hits. +spell.wizardry:darkvision.desc=Grants the caster night vision for 45 seconds. +spell.wizardry:dart.desc=Fires a dart in the direction you are pointing which damages and weakens its target. +spell.wizardry:decay.desc=Creates a patch of decay on the ground which infects any creature that touches it, causing lingering damage over time and spreading more decay wherever it walks. +spell.wizardry:decoy.desc=Creates an illusory clone of the caster which tricks mobs into attacking it instead. The decoy will vanish after 30 seconds. +spell.wizardry:detonate.desc=Causes an explosion where you are pointing, damaging all nearby creatures - including the caster, if they are too close. +spell.wizardry:diamondflesh.desc="Your arrows are no match for me!" +spell.wizardry:earthquake.desc=A true master of earth magic can move mountains. +spell.wizardry:entrapment.desc=Traps the target in a sphere of darkness which pulls it helplessly upwards and continually damages it. +spell.wizardry:fireball.desc=Launches a fireball in the direction you are pointing. +spell.wizardry:firebolt.desc=Shoots a jet of fire a short distance in front of you. +spell.wizardry:firebomb.desc=Lanches a firebomb in the direction you are pointing which explodes on impact, setting targets on fire. +spell.wizardry:fire_resistance.desc=Grants the caster fire resistance for 30 seconds. +spell.wizardry:fire_sigil.desc=Places a magical fire trap on the ground which damages and sets on fire the creature that triggers it. +spell.wizardry:fireskin.desc=Cloaks the caster in flames for 30 seconds, causing anything that attacks them to catch fire. +spell.wizardry:firestorm.desc="I am the dragon." +spell.wizardry:flame_ray.desc=Creates a stream of flames in the direction you are pointing which sets on fire and continually damages targets. +spell.wizardry:flaming_axe.desc=Creates a flaming axe which sets enemies on fire when hit. Lasts for 30 seconds. +spell.wizardry:flaming_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of flame, causing it to set fire to its victims. The magic wears off after 45 seconds. +spell.wizardry:flight.desc=Soar like an eagle. +spell.wizardry:font_of_mana.desc="We were filled with an intense magical energy appearing to emanate from the centre of the..." - Extract from the journal of a forgotten mage; the rest of the page has been burnt away. +spell.wizardry:font_of_vitality.desc=It feels amazing. +spell.wizardry:force_arrow.desc=Shoots an arrow of force in the direction you are pointing. +spell.wizardry:forcefield.desc=Creates a forcefield around the caster which repels creatures and deflects projectiles. +spell.wizardry:force_orb.desc=Launches a sphere of force which damages and repels nearby creatures on impact. +spell.wizardry:forests_curse.desc="How dare you enter my forest!" +spell.wizardry:freeze.desc=Freezes the target for 10 seconds. Will also freeze water and create snow on the ground. +spell.wizardry:freezing_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of frost, causing it to freeze its victims. The magic wears off after 45 seconds. +spell.wizardry:frost_axe.desc=Creates a frozen axe which freezes enemies when hit. Lasts for 30 seconds. +spell.wizardry:frost_ray.desc=Creates a stream of frost in the direction you are pointing which slows and continually damages targets. +spell.wizardry:frost_sigil.desc=Places a magical ice trap on the ground which damages and freezes the creature that triggers it. +spell.wizardry:glide.desc=Allows the caster to glide downwards while in the air and holding the use item button. +spell.wizardry:greater_fireball.desc=Launches a large fireball in the direction you are pointing which explodes on impact. +spell.wizardry:greater_heal.desc=Heals the caster by 4 hearts. +spell.wizardry:group_heal.desc=Heals the caster and all nearby allies and summoned creatures by 3 hearts. +spell.wizardry:growth_aura.desc=Grows all crops near the caster. Also grows tall grass and flowers on grass. +spell.wizardry:hailstorm.desc=It was during the great winter of the third age that the ice mages discovered their true power. +spell.wizardry:heal.desc=Heals the caster by 2 hearts. +spell.wizardry:heal_ally.desc=Heals the target by 2 and a half hearts. +spell.wizardry:healing_aura.desc=Creates a zone of healing energy which regenerates the health of any ally inside it. Any undead inside the healing aura will slowly take damage. +spell.wizardry:homing_spark.desc=Creates a floating spark which moves towards enemies. +spell.wizardry:ice_age.desc="You shall be frozen for an eternity!" +spell.wizardry:ice_charge.desc=Launches an ice charge which explodes on impact, freezing nearby creatures and releasing shards in all directions. +spell.wizardry:ice_lance.desc=Fires a great spear of ice in the direction you are pointing which overpenetrates targets, damaging and freezing them in the process. +spell.wizardry:ice_shard.desc=Fires a shard of ice in the direction you are pointing which damages and slows targets when hit. +spell.wizardry:ice_shroud.desc=Creates a shroud of cold around the caster for 30 seconds, causing anything that attacks them to be frozen. +spell.wizardry:ice_spikes.desc=Causes razor-sharp ice spikes to rise from the ground where you are pointing, skewering any creatures caught amongst them. +spell.wizardry:ice_statue.desc=Freezes the target solid for 20 seconds or until broken out. The target cannot move or do anything while frozen but is also impervious to all damage. +spell.wizardry:ignite.desc=Sets the target on fire for 10 seconds. Also works like a flint and steel. +spell.wizardry:imbue_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with magic, rendering it more effective. The magic wears off after 45 seconds. +spell.wizardry:intimidate.desc=Emits an intimidating growl which causes nearby creatures to run away in fear. Fear stricken creatures will recover after 30 seconds. +spell.wizardry:invigorating_presence.desc=Grants the caster and all nearby allies increased strength for 45 seconds. +spell.wizardry:invisibility.desc=Makes the caster invisible for 30 seconds. +spell.wizardry:invoke_weather.desc=Changes the weather in the world. +spell.wizardry:ironflesh.desc=Greatly improves the caster's damage resistance for 30 seconds. +spell.wizardry:leap.desc=Causes the caster to jump upwards several blocks and slightly forward. +spell.wizardry:levitation.desc=Raises the caster upwards while the use item button is held. Will also negate fall damage if used before hitting the ground. +spell.wizardry:life_drain.desc=Creates a stream of withering energy in the direction you are pointing which drains the life of the target and uses it to gradually regenerate your health. +spell.wizardry:light.desc=Creates a magical point of light which illuminates the surrounding area. Lasts for 30 seconds. +spell.wizardry:lightning_arrow.desc=Shoots an arrow of lightning in the direction you are pointing. +spell.wizardry:lightning_bolt.desc=Causes lightning to strike where you are pointing. +spell.wizardry:lightning_disc.desc=Sends a disc of lightning flying off in the direction you are pointing, which seeks targets. +spell.wizardry:lightning_hammer.desc="I smite you by the wrath of the heavens!" +spell.wizardry:lightning_pulse.desc=Charges the ground around the caster with lightning, damaging and repelling nearby creatures. +spell.wizardry:lightning_ray.desc=Creates a stream of lightning in the direction you are pointing which continually damages targets. +spell.wizardry:lightning_sigil.desc=Places a magical lightning trap on the ground which damages the creature that triggers it and chains lightning to other nearby creatures. +spell.wizardry:lightning_web.desc="Focus. Channel the storm in your mind through your wand and unleash its fury." +spell.wizardry:magic_missile.desc=Fires a bolt of magical energy in the direction you are pointing. +spell.wizardry:metamorphosis.desc=Changes the target into another form. Only works on some creatures. +spell.wizardry:meteor.desc=Some wizards just want to see the world burn... +spell.wizardry:mind_control.desc=Takes control of the target's mind for 30 seconds, causing it switch sides and fight for the caster instead. Will not work on creatures that are too strong-willed. +spell.wizardry:mind_trick.desc=Confuses and disorients the target for 15 seconds, rendering it unable to attack effectively. The effect will be dispelled if the target takes damage. +spell.wizardry:none.desc=To get a spell book with the /give command, use metadata: /give [player] wizardry:spell_book 1 [spell id] (if you found this book in a chest, some other mod has messed things up). +spell.wizardry:oakflesh.desc=Improves the caster's damage resistance for 30 seconds. +spell.wizardry:petrify.desc=Turns the target to stone until broken out, with a chance for it to break out when it is dark. The target cannot move or do anything while petrified but is also impervious to all damage. +spell.wizardry:phase_step.desc=Teleports the caster through a 1 block thick wall in front of them. Range upgrades will increase the thickness you can teleport through. +spell.wizardry:plague_of_darkness.desc=The darkness will consume them all... +spell.wizardry:pocket_furnace.desc=Smelts up to 5 smeltable items in the caster's inventory. Items on the hotbar will be smelted first. +spell.wizardry:pocket_workbench.desc=Allows the caster to craft items as if they were at a crafting table. +spell.wizardry:poison.desc=Fires poison in the direction you are pointing. +spell.wizardry:poison_bomb.desc=Lanches a poison bomb in the direction you are pointing which explodes on impact, poisoning nearby creatures. +spell.wizardry:replenish_hunger.desc=Replenishes the caster's food level by 6 hunger points. +spell.wizardry:ring_of_fire.desc=Creates a ring of fire around the caster, damaging all nearby enemies and setting them on fire. +spell.wizardry:shadow_ward.desc=Creates a wall of darkness in front of the caster which causes half of all incoming damage to be inflicted upon the attacker instead. +spell.wizardry:shield.desc=Creates a protective barrier of force that blocks projectiles and magic. Also grants the caster a weak resistance effect. +spell.wizardry:shockwave.desc=Boom. +spell.wizardry:silverfish_swarm.desc="Ahhhh! They're MULTIPLYING!" +spell.wizardry:sixth_sense.desc=Allows the caster to sense the locations of nearby creatures, even through walls, for 20 seconds. +spell.wizardry:slime.desc=Engulfs the target in slime which slows and continually damages it. The slime bursts after 10 seconds. +spell.wizardry:smoke_bomb.desc=Launches a smoke bomb in the direction you are pointing which explodes on impact, releasing smoke and blinding nearby creatures for a short time. +spell.wizardry:snare.desc=Sets a trap on the ground which damages and briefly slows the creature that triggers it. +spell.wizardry:snowball.desc=Launches a snowball in the direction you are pointing. +spell.wizardry:spark_bomb.desc=Launches a shock charge in the direction you are pointing which releases sparks at nearby enemies on impact. +spell.wizardry:spectral_pathway.desc=Creates an indestructible magical bridge in front of you which extends for 15 blocks. The bridge vanishes after 60 seconds. +spell.wizardry:spider_swarm.desc=Summons a swarm of venomous spiders to fight for you. The spiders will disappear after 30 seconds or if they are killed. +spell.wizardry:static_aura.desc=Surrounds the caster with lightning for 30 seconds, firing a spark of lightning at anything that hits them. +spell.wizardry:summon_blaze.desc=Summons a blaze to fight for you. The blaze will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_ice_giant.desc="Smash them!" +spell.wizardry:summon_ice_wraith.desc=Summons an ice wraith to fight for you. The ice wraith will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_iron_golem.desc=Automatic automated autonomous automaton. +spell.wizardry:summon_lightning_wraith.desc=Summons a lightning wraith to fight for you. The lightning wraith will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_phoenix.desc=From the ashes... +spell.wizardry:summon_shadow_wraith.desc=Summons a shadow wraith to fight for you. +spell.wizardry:summon_skeleton.desc=Summons a skeleton to fight for you. The skeleton will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_skeleton_legion.desc="Rise, undead army!" +spell.wizardry:summon_snow_golem.desc=Creates a snow golem to fight for you. Lasts until the snow golem dies. +spell.wizardry:summon_spirit_horse.desc=Summons a spirit horse for you to ride. The spirit horse will vanish a short while after it is dismounted, or you can dismiss it by shift-right-clicking on it with any wand. +spell.wizardry:summon_spirit_wolf.desc=Summons a spirit wolf companion to fight for you. The spirit wolf will only disappear if it is killed, or you can dismiss it by shift-right-clicking on it with any wand. +spell.wizardry:summon_storm_elemental.desc="Storm Elemental: An ancient manifestation of the elements, it can hardly contain the raw power churning within it." - The Wizard's Guide to Arcane Beings, Volume I_i +spell.wizardry:summon_wither_skeleton.desc=Summons a wither skeleton to fight for you. The wither skeleton will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_zombie.desc=Summons a zombie to fight for you. The zombie will disappear after 30 seconds or if it is killed. +spell.wizardry:telekinesis.desc=Moves an item or other small object towards you, or right-clicks the block you are looking at. Can also be used to disarm players. +spell.wizardry:thunderbolt.desc=Shoots a bolt of thunder which knocks back targets. +spell.wizardry:thunderstorm.desc="Mwahahahahahaha!" +spell.wizardry:tornado.desc=Unleashes a tornado in the direction you are pointing which hurls anything in its path skywards. +spell.wizardry:transience.desc=Makes the caster transient for 20 seconds. The caster is immune to all damage while transient but cannot break or place blocks or cause any damage. +spell.wizardry:transportation.desc=Transports the caster to their remembered stone circle. To use this spell, make a circle of stones of transportation, then right click it with a wand. +spell.wizardry:vanishing_box.desc=Grants the caster access to their ender chest storage. +spell.wizardry:wall_of_frost.desc=Winter at your fingertips. +spell.wizardry:water_breathing.desc=Allows the caster to breathe underwater for 60 seconds. +spell.wizardry:whirlwind.desc=Causes the target to be blown upwards and away from you at speed. +spell.wizardry:wither.desc=Fires a ray of darkness which withers anything it touches. +spell.wizardry:wither_skull.desc=Launches a wither skull in the direction you are pointing. + +spell.wizardry:invoke_weather.sun=The rain begins to stop... +spell.wizardry:invoke_weather.rain=The heavens open... +spell.wizardry:transportation.missing=Your remembered stone circle is missing or obstructed... +spell.wizardry:transportation.undefined=You must remember the location of a stone circle first! +spell.wizardry:transportation.wrongdimension=Your remembered stone circle is in another dimension... +spell.wizardry:clairvoyance.searching=Searching... +spell.wizardry:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point +spell.wizardry:clairvoyance.outofrange=Your remembered location is too far away or inaccessible... +spell.wizardry:clairvoyance.undefined=You must remember a location first! +spell.wizardry:clairvoyance.wrongdimension=Your remembered location is in another dimension... + +potion.wizardry:frost=Frostbite +potion.wizardry:fireskin=Fireskin +potion.wizardry:ice_shroud=Ice Shroud +potion.wizardry:static_aura=Static Aura +potion.wizardry:transience=Transience +potion.wizardry:decay=Decay +potion.wizardry:sixth_sense=Sixth Sense +potion.wizardry:arcane_jammer=Arcane Jammer +potion.wizardry:mind_trick=Mind Trick +potion.wizardry:mind_control=Mind Control +potion.wizardry:font_of_mana=Font of Mana +potion.wizardry:fear=Fear + +enchantment.wizardry:magic_sword=Imbuement +enchantment.wizardry:magic_bow=Imbuement +enchantment.wizardry:flaming_weapon=Fire Imbuement +enchantment.wizardry:freezing_weapon=Frost Imbuement + +key.categories.wizardry=Wizardry + +key.wizardry:next_spell=Next Spell +key.wizardry:previous_spell=Previous Spell + +death.attack.wizardry_magic=%1$s was killed by %2$s using magic +death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic + +commands.wizardry:cast.usage=/%1$s [player] [damage multiplier] [range multiplier] [duration multiplier] [blast multiplier] +commands.wizardry:cast.success=Successfully cast %1$s +commands.wizardry:cast.success_continuous=Successfully cast %1$s; repeat the command to stop +commands.wizardry:cast.success_remote=Successfully cast %1$s as %2$s +commands.wizardry:cast.success_remote_continuous=Successfully cast %1$s as %2$s; repeat the command to stop +commands.wizardry:cast.fail=Unable to cast %1$s +commands.wizardry:cast.not_found=There is no such spell with ID %1$s +commands.wizardry:cast.tag_error=Data tag parsing failed: %s + +commands.wizardry:ally.usage=/%1$s [player] +commands.wizardry:ally.addally=%1$s has been added to %2$s's list of allies +commands.wizardry:ally.removeally=%1$s has been removed from %2$s's list of allies +commands.wizardry:ally.self=Players cannot be an ally of themselves! +commands.wizardry:ally.permission=You do not have permission to change other players' allies + +commands.wizardry:allies.usage=/%1$s [player] +commands.wizardry:allies.list=Players allied to you: %1$s +commands.wizardry:allies.list_other=Players allied to %1$s: %2$s +commands.wizardry:allies.permission=You do not have permission to view other players' allies +commands.wizardry:allies.none=None + +commands.wizardry:discoverspell.usage=/%1$s [player] +commands.wizardry:discoverspell.not_found=There is no such spell with ID %1$s +commands.wizardry:discoverspell.clear=Cleared all spell discovery data for %1$s +commands.wizardry:discoverspell.all=Added all spells to %1$s's spell discovery data +commands.wizardry:discoverspell.addspell=Added %1$s to %2$s's spell discovery data +commands.wizardry:discoverspell.removespell=Removed %1$s from %2$s's spell discovery data + +config.wizardry.title.general=Mod Options + +config.wizardry.category.spells=Configure Spells +config.wizardry.category.spells.tooltip=Select which spells are enabled +config.wizardry.title.spells=Spell Configuration +config.wizardry.subtitle.spells=Set a spell to false to disable it. + +config.wizardry.category.resistances=Configure Resistances +config.wizardry.category.resistances.tooltip=Configure which mobs are immune to different types of magic +config.wizardry.title.resistances=Resistance Configuration +config.wizardry.subtitle.resistances=See descriptions of individual options for more details. + +config.wizardry.category.ids=Configure IDs +config.wizardry.category.ids.tooltip=Change the IDs used by wizardry +config.wizardry.title.ids=ID Configuration +config.wizardry.subtitle.ids=Change these IDs if they conflict with another mod. + +config.wizardry.tower_rarity=Tower Rarity +config.wizardry.ore_dimensions=Ore Dimensions +config.wizardry.flower_dimensions=Flower Dimensions +config.wizardry.tower_dimensions=Tower Dimensions +config.wizardry.spell_book_drop_chance=Spell Book Drop Chance +config.wizardry.generate_loot=Generate Loot +config.wizardry.firebomb_is_craftable=Firebomb Is Craftable +config.wizardry.poison_bomb_is_craftable=Poison Bomb Is Craftable +config.wizardry.smoke_bomb_is_craftable=Smoke Bomb Is Craftable +config.wizardry.use_alternate_scroll_recipe=Use Alternate Scroll Recipe +config.wizardry.teleport_through_unbreakable_blocks=Teleport Through Unbreakable Blocks +config.wizardry.show_summoned_creature_names=Show Summoned Creature Names +config.wizardry.friendly_fire=Friendly Fire +config.wizardry.telekinetic_disarmament=Telekinetic Disarmament +config.wizardry.discovery_mode=Discovery Mode +config.wizardry.enable_shift_scrolling=Enable Shift-_scrolling +config.wizardry.minion_revenge_targeting=Minion Revenge Targeting +config.wizardry.player_damage_scaling=Player Damage Scaling Factor +config.wizardry.npc_damage_scaling=NPC Damage Scaling Factor +config.wizardry.cast_command_multiplier_limit=Cast Command Multiplier Limit +config.wizardry.summoned_creature_targets_whitelist=Summoned Creature Target Whitelist +config.wizardry.summoned_creature_targets_blacklist=Summoned Creature Target Blacklist +config.wizardry.spell_hud_position=Spell HUD Position +config.wizardry.cast_command_name=Cast Spell Command Name +config.wizardry.discoverspell_command_name=Discover Spell Command Name +config.wizardry.ally_command_name=Set Ally Command Name +config.wizardry.allies_command_name=View Allies Command Name + +config.wizardry.mobs_immune_to_fire=Mobs Immune To Fire +config.wizardry.mobs_immune_to_ice=Mobs Immune To Ice +config.wizardry.mobs_immune_to_lightning=Mobs Immune To Lightning +config.wizardry.mobs_immune_to_wither=Mobs Immune To Wither +config.wizardry.mobs_immune_to_poison=Mobs Immune To Poison + +config.wizardry.tower_rarity.tooltip=Rarity of wizard towers. Higher numbers are rarer. Set to 0 to disable wizard towers completely. +config.wizardry.ore_dimensions.tooltip=List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play! +config.wizardry.flower_dimensions.tooltip=List of dimension ids in which crystal flowers will generate. +config.wizardry.tower_dimensions.tooltip=List of dimension ids in which wizard towers will generate. +config.wizardry.spell_book_drop_chance.tooltip=The chance for mobs to drop a spell book when killed. The greater this number, the more often they will drop. Set to 0 to disable spell book drops. Set to 200 for guaranteed drops. +config.wizardry.generate_loot.tooltip=Whether to generate wizardry loot in dungeon chests. +config.wizardry.firebomb_is_craftable.tooltip=Whether firebombs can be crafted or not. +config.wizardry.poison_bomb_is_craftable.tooltip=Whether poison bombs can be crafted or not. +config.wizardry.smoke_bomb_is_craftable.tooltip=Whether smoke bombs can be crafted or not. +config.wizardry.use_alternate_scroll_recipe.tooltip=Whether to require a magic crystal in the shapeless crafting recipe for blank scrolls. Set to true if another mod adds a conflicting recipe. +config.wizardry.teleport_through_unbreakable_blocks.tooltip=Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. +config.wizardry.show_summoned_creature_names.tooltip=Whether to show summoned creatures' names and owners above their heads. +config.wizardry.friendly_fire.tooltip=Whether to allow players to damage their designated allies using magic. +config.wizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell.wizardry: Set to false to prevent stealing of items. +config.wizardry.discovery_mode.tooltip=For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false. +config.wizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. +config.wizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge attack their owner if their owner attacks them. +config.wizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. +config.wizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. +config.wizardry.cast_command_multiplier_limit.tooltip=Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned! +config.wizardry.summoned_creature_targets_whitelist.tooltip=List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.summoned_creature_targets_blacklist.tooltip=List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.spell_hud_position.tooltip=The position of the spell HUD. +config.wizardry.cast_command_name.tooltip=The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead. +config.wizardry.discoverspell_command_name.tooltip=The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead. +config.wizardry.ally_command_name.tooltip=The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead. +config.wizardry.allies_command_name.tooltip=The name of the /allies command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /allies you would type /magic instead. + +config.wizardry.mobs_immune_to_fire.tooltip=List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.mobs_immune_to_ice.tooltip=List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.mobs_immune_to_lightning.tooltip=List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.mobs_immune_to_wither.tooltip=List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.mobs_immune_to_poison.tooltip=List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). + +wizard.debug=%1$s, %2$s, %3$s \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/lang/en_US.lang b/src/main/resources/assets/wizardry/lang/en_US.lang new file mode 100644 index 00000000..3f87afb7 --- /dev/null +++ b/src/main/resources/assets/wizardry/lang/en_US.lang @@ -0,0 +1,738 @@ +tile.wizardry:arcane_workbench.name=Arcane Workbench +tile.wizardry:crystal_ore.name=Crystal Ore +tile.wizardry:petrified_stone.name=Petrified Stone +tile.wizardry:ice_statue.name=Ice Statue +tile.wizardry:crystal_flower.name=Crystal Flower +tile.wizardry:snare.name=Snare +tile.wizardry:transportation_stone.name=Stone of Transportation +tile.wizardry:spectral_block.name=Spectral Block +tile.wizardry:crystal_block.name=Block of Crystal + +item.wizardry:magic_crystal.name=Magic Crystal +item.wizardry:magic_wand.name=Magic Wand +item.wizardry:apprentice_wand.name=Apprentice Wand +item.wizardry:advanced_wand.name=Advanced Wand +item.wizardry:master_wand.name=Master Wand +item.wizardry:spell_book.name=Spell Book + +item.wizardry:arcane_tome.name=Tome of Arcana +item.wizardry:arcane_tome.desc1=Upgrades any %1$s +item.wizardry:arcane_tome.desc2=wand to %1$s tier + +item.wizardry:wizard_handbook.name=The Wizard's Handbook +item.wizardry:wizard_handbook.desc=by %1$s + +item.wizardry:wand.buff=+%1$s %2$s potency +item.wizardry:wand.spell=Current Spell: %1$s +item.wizardry:wand.mana=Mana: %1$s/%2$s + +item.wizardry:wand.addally=%1$s has been added to your list of allies +item.wizardry:wand.removeally=%1$s has been removed from your list of allies + +item.wizardry:basic_fire_wand.name=Wand of Embers +item.wizardry:basic_ice_wand.name=Wand of Frost +item.wizardry:basic_lightning_wand.name=Wand of Sparks +item.wizardry:basic_necromancy_wand.name=Wand of Shadows +item.wizardry:basic_earth_wand.name=Wand of the Forest +item.wizardry:basic_sorcery_wand.name=Wand of Mystery +item.wizardry:basic_healing_wand.name=Wand of Healing + +item.wizardry:apprentice_fire_wand.name=Apprentice Pyromancer Wand +item.wizardry:apprentice_ice_wand.name=Apprentice Ice Mage Wand +item.wizardry:apprentice_lightning_wand.name=Apprentice Storm Mage Wand +item.wizardry:apprentice_necromancy_wand.name=Apprentice Necromancer Wand +item.wizardry:apprentice_earth_wand.name=Apprentice Earth Mage Wand +item.wizardry:apprentice_sorcery_wand.name=Apprentice Sorcerer Wand +item.wizardry:apprentice_healing_wand.name=Apprentice Healer Wand + +item.wizardry:advanced_fire_wand.name=Wand of the Pyromancer +item.wizardry:advanced_ice_wand.name=Wand of the Ice Mage +item.wizardry:advanced_lightning_wand.name=Wand of the Storm Mage +item.wizardry:advanced_necromancy_wand.name=Wand of the Necromancer +item.wizardry:advanced_earth_wand.name=Wand of the Earth Mage +item.wizardry:advanced_sorcery_wand.name=Wand of the Sorcerer +item.wizardry:advanced_healing_wand.name=Wand of the Healer + +item.wizardry:master_fire_wand.name=Master Pyromancer Wand +item.wizardry:master_ice_wand.name=Master Ice Mage Wand +item.wizardry:master_lightning_wand.name=Master Storm Mage Wand +item.wizardry:master_necromancy_wand.name=Master Necromancer Wand +item.wizardry:master_earth_wand.name=Master Earth Mage Wand +item.wizardry:master_sorcery_wand.name=Master Sorcerer Wand +item.wizardry:master_healing_wand.name=Master Healer Wand + +item.wizardry:spectral_sword.name=Spectral Sword +item.wizardry:spectral_pickaxe.name=Spectral Pickaxe +item.wizardry:spectral_bow.name=Spectral Bow + +item.wizardry:mana_flask.name=Mana Flask +item.wizardry:storage_upgrade.name=Wand Storage Upgrade +item.wizardry:siphon_upgrade.name=Wand Siphon Upgrade +item.wizardry:condenser_upgrade.name=Wand Condenser Upgrade +item.wizardry:range_upgrade.name=Wand Range Upgrade +item.wizardry:duration_upgrade.name=Wand Duration Upgrade +item.wizardry:cooldown_upgrade.name=Wand Cooldown Upgrade +item.wizardry:blast_upgrade.name=Wand Blast Upgrade +item.wizardry:attunement_upgrade.name=Wand Attunement Upgrade + +item.wizardry:flaming_axe.name=Flaming Axe +item.wizardry:frost_axe.name=Frost Axe + +item.wizardry:firebomb.name=Firebomb +item.wizardry:poison_bomb.name=Poison Bomb +item.wizardry:smoke_bomb.name=Smoke Bomb + +item.wizardry:blank_scroll.name=Blank Scroll +item.wizardry:scroll.name=Scroll of %1$s +item.wizardry:scroll.undiscovered.name=Scroll "%1$s" +item.wizardry:identification_scroll.name=Scroll of Identification +item.wizardry:identification_scroll.desc1=%1$sIdentifies an unknown +item.wizardry:identification_scroll.desc2=%1$sspell book or scroll +item.wizardry:identification_scroll.nothing_to_identify=Nothing to identify! + +item.wizardry:armour_upgrade.name=Arcane Seal of Protection +item.wizardry:armour_upgrade.desc1=%1$sUpgrades any wizard armour +item.wizardry:armour_upgrade.desc2=%1$sto make it %2$slegendary + +item.wizardry:magic_silk.name=Magical Silk + +item.wizardry:wizard_armour.legendary=Legendary +item.wizardry:wizard_armour.buff=-%1$s %2$s cost +item.wizardry:wizard_armour.mana=Mana: %1$s/%2$s + +item.wizardry:wizard_hat.name=Wizard Hat +item.wizardry:wizard_robe.name=Wizard Robes +item.wizardry:wizard_leggings.name=Wizard Leggings +item.wizardry:wizard_boots.name=Wizard Boots + +item.wizardry:wizard_hat_fire.name=Pyromancer Hat +item.wizardry:wizard_robe_fire.name=Pyromancer Robes +item.wizardry:wizard_leggings_fire.name=Pyromancer Leggings +item.wizardry:wizard_boots_fire.name=Pyromancer Boots + +item.wizardry:wizard_hat_ice.name=Ice Mage Hat +item.wizardry:wizard_robe_ice.name=Ice Mage Robes +item.wizardry:wizard_leggings_ice.name=Ice Mage Leggings +item.wizardry:wizard_boots_ice.name=Ice Mage Boots + +item.wizardry:wizard_hat_lightning.name=Storm Mage Hat +item.wizardry:wizard_robe_lightning.name=Storm Mage Robes +item.wizardry:wizard_leggings_lightning.name=Storm Mage Leggings +item.wizardry:wizard_boots_lightning.name=Storm Mage Boots + +item.wizardry:wizard_hat_necromancy.name=Necromancer Hat +item.wizardry:wizard_robe_necromancy.name=Necromancer Robes +item.wizardry:wizard_leggings_necromancy.name=Necromancer Leggings +item.wizardry:wizard_boots_necromancy.name=Necromancer Boots + +item.wizardry:wizard_hat_earth.name=Earth Mage Hat +item.wizardry:wizard_robe_earth.name=Earth Mage Robes +item.wizardry:wizard_leggings_earth.name=Earth Mage Leggings +item.wizardry:wizard_boots_earth.name=Earth Mage Boots + +item.wizardry:wizard_hat_sorcery.name=Sorcerer Hat +item.wizardry:wizard_robe_sorcery.name=Sorcerer Robes +item.wizardry:wizard_leggings_sorcery.name=Sorcerer Leggings +item.wizardry:wizard_boots_sorcery.name=Sorcerer Boots + +item.wizardry:wizard_hat_healing.name=Healer Hat +item.wizardry:wizard_robe_healing.name=Healer Robes +item.wizardry:wizard_leggings_healing.name=Healer Leggings +item.wizardry:wizard_boots_healing.name=Healer Boots + +item.wizardry:spawn_wizard.name=Spawn Wizard +item.wizardry:spawn_evil_wizard.name=Spawn Evil Wizard + +item.wizardry:spectral_helmet.name=Spectral Helmet +item.wizardry:spectral_chestplate.name=Spectral Chestplate +item.wizardry:spectral_leggings.name=Spectral Leggings +item.wizardry:spectral_boots.name=Spectral Boots + +entity.wizardry.summonedcreature.nameplate=%1$s's %2$s +entity.wizardry.summonedcreature.nameplate_fallback=Someone's %1$s + +entity.wizardry.zombie_minion.name=Zombie +entity.wizardry.skeleton_minion.name=Skeleton +entity.wizardry.spider_minion.name=Spider +entity.wizardry.blaze_minion.name=Blaze +entity.wizardry.ice_wraith.name=Ice Wraith +entity.wizardry.lightning_wraith.name=Lightning Wraith +entity.wizardry.shadow_wraith.name=Shadow Wraith +entity.wizardry.spirit_wolf.name=Spirit Wolf +entity.wizardry.spirit_horse.name=Spirit Horse +entity.wizardry.ice_giant.name=Ice Giant +entity.wizardry.phoenix.name=Phoenix +entity.wizardry.wizard.name=Wizard +entity.wizardry.magic_slime.name=Magical Slime +entity.wizardry.silverfish_minion.name=Silverfish +entity.wizardry.storm_elemental.name=Storm Elemental +entity.wizardry.evil_wizard.name=Wizard +entity.wizardry.decoy.name=Decoy + +entity.wizardry.magic_missile.name=Magic +entity.wizardry.arc.name=Magic +entity.wizardry.spark_bomb.name=Magic +entity.wizardry.ice_shard.name=Magic +entity.wizardry.firebomb.name=Magic +entity.wizardry.poison_bomb.name=Magic +entity.wizardry.force_orb.name=Magic +entity.wizardry.spark.name=Magic +entity.wizardry.darkness_orb.name=Magic +entity.wizardry.fire_sigil.name=Magic +entity.wizardry.frost_sigil.name=Magic +entity.wizardry.lightning_sigil.name=Magic +entity.wizardry.lightning_arrow.name=Magic +entity.wizardry.firebolt.name=Magic +entity.wizardry.ice_charge.name=Magic +entity.wizardry.force_arrow.name=Magic +entity.wizardry.dart.name=Magic +entity.wizardry.lightning_disc.name=Magic +entity.wizardry.thunderbolt.name=Magic +entity.wizardry.decay.name=Magic +entity.wizardry.ice_lance.name=Magic +entity.wizardry.smoke_bomb.name=Magic +entity.wizardry.ice_spike.name=Magic + +entity.wizardry.black_hole.name=Black Hole +entity.wizardry.shield.name=Shield +entity.wizardry.meteor.name=Meteor +entity.wizardry.blizzard.name=Blizzard +entity.wizardry.bubble.name=Bubble +entity.wizardry.tornado.name=Tornado +entity.wizardry.lightning_hammer.name=Lightning Hammer +entity.wizardry.arrow_rain.name=Arrow Rain +entity.wizardry.healing_aura.name=Healing Aura +entity.wizardry.forcefield.name=Forcefield +entity.wizardry.ring_of_fire.name=Ring of Fire +entity.wizardry.earthquake.name=Earthquake +entity.wizardry.falling_grass.name=Falling Grass +entity.wizardry.hailstorm.name=Hailstorm +entity.wizardry.lightning_pulse.name=Lightning Pulse + +itemGroup.wizardry=Wizardry +itemGroup.wizardryspells=Spells + +achievement.crystal=A Curious Crystal... +achievement.crystal.desc=Mine a magic crystal +achievement.arcane_initiate=Arcane Initiate +achievement.arcane_initiate.desc=Craft a magic wand with a gold nugget, a stick and a magic crystal +achievement.apprentice=Wizard's Apprentice +achievement.apprentice.desc=Use a tome of arcana to upgrade your wand +achievement.master=Arcane Master +achievement.master.desc=Obtain a master wand +achievement.all_spells=Mage of All Trades +achievement.all_spells.desc=Cast every single spell in the game +achievement.wizard_trade=Magic Dealing +achievement.wizard_trade.desc=Purchase an item from a wizard +achievement.buy_master_spell=Knowledge is Power +achievement.buy_master_spell.wizardry:desc=Purchase a master spell from a wizard +achievement.freeze_blaze=Not So Hot Now +achievement.freeze_blaze.desc=Freeze a blaze solid +achievement.charge_creeper=It's Gonna Blow +achievement.charge_creeper.desc='Accidentally' charge a creeper +achievement.frankenstein=Frankenstein +achievement.frankenstein.desc=Turn a pig into a zombie pigman using the lightning bolt spell +achievement.special_upgrade=Arcane Tinkering +achievement.special_upgrade.desc=Apply a special upgrade to a wand +achievement.craft_flask=It's Magic, Bottled! +achievement.craft_flask.desc=Craft a mana flask +achievement.elemental=Elemental +achievement.elemental.desc=Obtain an elemental wand +achievement.armour_set=Now You're a Proper Wizard +achievement.armour_set.desc=Craft and equip a full set of wizard armor +achievement.legendary=Legendary +achievement.legendary.desc=Obtain a piece of legendary wizard armor +achievement.self_destruct=That Backfired +achievement.self_destruct.desc=Get killed by your own magic +achievement.pig_tornado=Not Again... +achievement.pig_tornado.desc=Ride a pig into a tornado +achievement.jam_wizard=Jamming Session +achievement.jam_wizard.desc=Use the arcane jammer spell on a wizard +achievement.slime_skeleton=Sticky Situation +achievement.slime_skeleton.desc=Engulf a skeleton in slime +achievement.anger_wizard=You'll Regret That +achievement.anger_wizard.desc=Make a wizard angry +achievement.defeat_evil_wizard=Righteousness +achievement.defeat_evil_wizard.desc=Defeat an evil wizard +achievement.max_out_wand=Fully Equipped +achievement.max_out_wand.desc=Apply the maximum number of upgrades to a master wand +achievement.element_master=Element Mastery +achievement.element_master.desc=Cast all the spells of any element +achievement.identify_spell=Arcane Appraisal +achievement.identify_spell.wizardry:desc=Use a scroll of identification to identify a spell book or scroll + +tile.wizardry:transportation_stone.confirm=You will now be returned here upon casting %1$s +tile.wizardry:transportation_stone.invalid=You must make a circle with 8 stones of transportation first! + +container.wizardry:arcane_workbench=Arcane Workbench +container.wizardry:arcane_workbench.apply=Apply +container.wizardry:arcane_workbench.mana=Mana: +container.wizardry:arcane_workbench.upgrades=Applied Upgrades: + +tier.basic=Novice +tier.apprentice=Apprentice +tier.advanced=Advanced +tier.master=Master + +element.simple=None +element.fire=Fire +element.ice=Ice +element.lightning=Lightning +element.necromancy=Necromancy +element.earth=Earth +element.sorcery=Sorcery +element.healing=Healing + +element.simple.wizard=Wizard +element.fire.wizard=Pyromancer +element.ice.wizard=Ice Mage +element.lightning.wizard=Storm Mage +element.necromancy.wizard=Necromancer +element.earth.wizard=Earth Mage +element.sorcery.wizard=Sorcerer +element.healing.wizard=Healer + +spelltype.attack=Attack +spelltype.defence=Defense +spelltype.utility=Utility +spelltype.minion=Minion + +spell.disabled=%1$s has been disabled in the config +spell.resist=%1$s resisted %2$s +spell.discover=Discovered the spell %1$s! + +spell.wizardry:agility=Agility +spell.wizardry:arc=Arc +spell.wizardry:arcane_jammer=Arcane Jammer +spell.wizardry:arrow_rain=Arrow Rain +spell.wizardry:banish=Banish +spell.wizardry:black_hole=Black Hole +spell.wizardry:blink=Blink +spell.wizardry:blizzard=Blizzard +spell.wizardry:bubble=Bubble +spell.wizardry:chain_lightning=Chain Lightning +spell.wizardry:clairvoyance=Clairvoyance +spell.wizardry:cobwebs=Cobwebs +spell.wizardry:conjure_armour=Conjure Armor +spell.wizardry:conjure_bow=Conjure Bow +spell.wizardry:conjure_pickaxe=Conjure Pickaxe +spell.wizardry:conjure_sword=Conjure Sword +spell.wizardry:cure_effects=Cure Effects +spell.wizardry:curse_of_soulbinding=Curse of Soulbinding +spell.wizardry:darkness_orb=Darkness Orb +spell.wizardry:darkvision=Darkvision +spell.wizardry:dart=Dart +spell.wizardry:decay=Decay +spell.wizardry:decoy=Decoy +spell.wizardry:detonate=Detonate +spell.wizardry:diamondflesh=Diamondflesh +spell.wizardry:earthquake=Earthquake +spell.wizardry:entrapment=Entrapment +spell.wizardry:fireball=Fireball +spell.wizardry:firebolt=Firebolt +spell.wizardry:firebomb=Firebomb +spell.wizardry:fire_resistance=Fire Resistance +spell.wizardry:fire_sigil=Fire Sigil +spell.wizardry:fireskin=Fireskin +spell.wizardry:firestorm=Firestorm +spell.wizardry:flame_ray=Flame Ray +spell.wizardry:flaming_axe=Flaming Axe +spell.wizardry:flaming_weapon=Flaming Weapon +spell.wizardry:flight=Flight +spell.wizardry:font_of_mana=Font of Mana +spell.wizardry:font_of_vitality=Font of Vitality +spell.wizardry:force_arrow=Force Arrow +spell.wizardry:forcefield=Forcefield +spell.wizardry:force_orb=Force Orb +spell.wizardry:forests_curse=Forest's Curse +spell.wizardry:freeze=Freeze +spell.wizardry:freezing_weapon=Freezing Weapon +spell.wizardry:frost_axe=Frost Axe +spell.wizardry:frost_ray=Frost Ray +spell.wizardry:frost_sigil=Frost Sigil +spell.wizardry:glide=Glide +spell.wizardry:greater_fireball=Greater Fireball +spell.wizardry:greater_heal=Greater Heal +spell.wizardry:group_heal=Group Heal +spell.wizardry:growth_aura=Growth Aura +spell.wizardry:hailstorm=Hailstorm +spell.wizardry:heal=Heal +spell.wizardry:heal_ally=Heal Ally +spell.wizardry:healing_aura=Healing Aura +spell.wizardry:homing_spark=Homing Spark +spell.wizardry:ice_age=Ice Age +spell.wizardry:ice_charge=Ice Charge +spell.wizardry:ice_lance=Ice Lance +spell.wizardry:ice_shard=Ice Shard +spell.wizardry:ice_shroud=Ice Shroud +spell.wizardry:ice_spikes=Ice Spikes +spell.wizardry:ice_statue=Ice Statue +spell.wizardry:ignite=Ignite +spell.wizardry:imbue_weapon=Imbue Weapon +spell.wizardry:intimidate=Intimidate +spell.wizardry:invigorating_presence=Invigorating Presence +spell.wizardry:invisibility=Invisibility +spell.wizardry:invoke_weather=Invoke Weather +spell.wizardry:ironflesh=Ironflesh +spell.wizardry:leap=Leap +spell.wizardry:levitation=Levitation +spell.wizardry:life_drain=Life Drain +spell.wizardry:light=Light +spell.wizardry:lightning_arrow=Lightning Arrow +spell.wizardry:lightning_bolt=Lightning Bolt +spell.wizardry:lightning_disc=Lightning Disk +spell.wizardry:lightning_hammer=Lightning Hammer +spell.wizardry:lightning_pulse=Lightning Pulse +spell.wizardry:lightning_ray=Lightning Ray +spell.wizardry:lightning_sigil=Lightning Sigil +spell.wizardry:lightning_web=Lightning Web +spell.wizardry:magic_missile=Magic Missile +spell.wizardry:metamorphosis=Metamorphosis +spell.wizardry:meteor=Meteor +spell.wizardry:mind_control=Mind Control +spell.wizardry:mind_trick=Mind Trick +spell.wizardry:none=[Empty Slot] +spell.wizardry:oakflesh=Oakflesh +spell.wizardry:petrify=Petrify +spell.wizardry:phase_step=Phase Step +spell.wizardry:plague_of_darkness=Plague of Darkness +spell.wizardry:pocket_furnace=Pocket Furnace +spell.wizardry:pocket_workbench=Pocket Workbench +spell.wizardry:poison=Poison +spell.wizardry:poison_bomb=Poison Bomb +spell.wizardry:replenish_hunger=Replenish Hunger +spell.wizardry:ring_of_fire=Ring of Fire +spell.wizardry:shadow_ward=Shadow Ward +spell.wizardry:shield=Shield +spell.wizardry:shockwave=Shockwave +spell.wizardry:silverfish_swarm=Silverfish Swarm +spell.wizardry:sixth_sense=Sixth Sense +spell.wizardry:slime=Slime +spell.wizardry:smoke_bomb=Smoke Bomb +spell.wizardry:snare=Snare +spell.wizardry:snowball=Snowball +spell.wizardry:spark_bomb=Spark Bomb +spell.wizardry:spectral_pathway=Spectral Pathway +spell.wizardry:spider_swarm=Spider Swarm +spell.wizardry:static_aura=Static Aura +spell.wizardry:summon_blaze=Summon Blaze +spell.wizardry:summon_ice_giant=Summon Ice Giant +spell.wizardry:summon_ice_wraith=Summon Ice Wraith +spell.wizardry:summon_iron_golem=Summon Iron Golem +spell.wizardry:summon_lightning_wraith=Summon Lightning Wraith +spell.wizardry:summon_phoenix=Summon Phoenix +spell.wizardry:summon_shadow_wraith=Summon Shadow Wraith +spell.wizardry:summon_skeleton=Summon Skeleton +spell.wizardry:summon_skeleton_legion=Summon Skeleton Legion +spell.wizardry:summon_snow_golem=Summon Snow Golem +spell.wizardry:summon_spirit_horse=Summon Spirit Horse +spell.wizardry:summon_spirit_wolf=Summon Spirit Wolf +spell.wizardry:summon_storm_elemental=Summon Storm Elemental +spell.wizardry:summon_wither_skeleton=Summon Wither Skeleton +spell.wizardry:summon_zombie=Summon Zombie +spell.wizardry:telekinesis=Telekinesis +spell.wizardry:thunderbolt=Thunderbolt +spell.wizardry:thunderstorm=Thunderstorm +spell.wizardry:tornado=Tornado +spell.wizardry:transience=Transience +spell.wizardry:transportation=Transportation +spell.wizardry:vanishing_box=Vanishing Box +spell.wizardry:wall_of_frost=Wall of Frost +spell.wizardry:water_breathing=Water Breathing +spell.wizardry:whirlwind=Whirlwind +spell.wizardry:wither=Wither +spell.wizardry:wither_skull=Wither Skull + +spell.wizardry:agility.desc=Grants the caster faster movement speed and greater jump height for 30 seconds. +spell.wizardry:arc.desc=Fires a spark of lightning at the target. +spell.wizardry:arcane_jammer.desc=Prevents the target from using magic for 15 seconds. +spell.wizardry:arrow_rain.desc="Archers, fire!" +spell.wizardry:banish.desc=Teleports the target against its will to a random location within a certain range. +spell.wizardry:black_hole.desc=Tear reality asunder. +spell.wizardry:blink.desc=Teleports the caster over a short distance to where they are pointing. +spell.wizardry:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed. +spell.wizardry:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged. +spell.wizardry:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice. +spell.wizardry:clairvoyance.desc=Reveals the path to a remembered location. With this spell selected, sneak-right-click on a block to set the location. Cast this spell normally to reveal the path. The path will fade after 90 seconds. +spell.wizardry:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken. +spell.wizardry:conjure_armour.desc=Creates spectral armor around the caster which offers protection equal to that of iron armor. The armor lasts for 60 seconds. The caster must have an empty armor slot. +spell.wizardry:conjure_bow.desc=Creates a spectral bow with unlimited arrows that lasts for 30 seconds. +spell.wizardry:conjure_pickaxe.desc=Creates a spectral pickaxe of equal strength to an iron pickaxe that lasts for 30 seconds. +spell.wizardry:conjure_sword.desc=Creates a spectral sword of equal strength to an iron sword that lasts for 30 seconds. +spell.wizardry:cure_effects.desc=Removes all potion effects currently affecting the caster, good or bad. +spell.wizardry:curse_of_soulbinding.desc=Causes the target's soul to be inextricably bound to that of the caster, meaning all damage dealt to the caster is also dealt to the victim. Lasts until either the victim or the caster dies. +spell.wizardry:darkness_orb.desc=Fires a slow moving bolt of dark energy in the direction you are pointing, which withers whatever it hits. +spell.wizardry:darkvision.desc=Grants the caster night vision for 45 seconds. +spell.wizardry:dart.desc=Fires a dart in the direction you are pointing which damages and weakens its target. +spell.wizardry:decay.desc=Creates a patch of decay on the ground which infects any creature that touches it, causing lingering damage over time and spreading more decay wherever it walks. +spell.wizardry:decoy.desc=Creates an illusory clone of the caster which tricks mobs into attacking it instead. The decoy will vanish after 30 seconds. +spell.wizardry:detonate.desc=Causes an explosion where you are pointing, damaging all nearby creatures - including the caster, if they are too close. +spell.wizardry:diamondflesh.desc="Your arrows are no match for me!" +spell.wizardry:earthquake.desc=A true master of earth magic can move mountains. +spell.wizardry:entrapment.desc=Traps the target in a sphere of darkness which pulls it helplessly upwards and continually damages it. +spell.wizardry:fireball.desc=Launches a fireball in the direction you are pointing. +spell.wizardry:firebolt.desc=Shoots a jet of fire a short distance in front of you. +spell.wizardry:firebomb.desc=Lanches a firebomb in the direction you are pointing which explodes on impact, setting targets on fire. +spell.wizardry:fire_resistance.desc=Grants the caster fire resistance for 30 seconds. +spell.wizardry:fire_sigil.desc=Places a magical fire trap on the ground which damages and sets on fire the creature that triggers it. +spell.wizardry:fireskin.desc=Cloaks the caster in flames for 30 seconds, causing anything that attacks them to catch fire. +spell.wizardry:firestorm.desc="I am the dragon." +spell.wizardry:flame_ray.desc=Creates a stream of flames in the direction you are pointing which sets on fire and continually damages targets. +spell.wizardry:flaming_axe.desc=Creates a flaming axe which sets enemies on fire when hit. Lasts for 30 seconds. +spell.wizardry:flaming_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of flame, causing it to set fire to its victims. The magic wears off after 45 seconds. +spell.wizardry:flight.desc=Soar like an eagle. +spell.wizardry:font_of_mana.desc="We were filled with an intense magical energy appearing to emanate from the centre of the..." - Extract from the journal of a forgotten mage; the rest of the page has been burnt away. +spell.wizardry:font_of_vitality.desc=It feels amazing. +spell.wizardry:force_arrow.desc=Shoots an arrow of force in the direction you are pointing. +spell.wizardry:forcefield.desc=Creates a forcefield around the caster which repels creatures and deflects projectiles. +spell.wizardry:force_orb.desc=Launches a sphere of force which damages and repels nearby creatures on impact. +spell.wizardry:forests_curse.desc="How dare you enter my forest!" +spell.wizardry:freeze.desc=Freezes the target for 10 seconds. Will also freeze water and create snow on the ground. +spell.wizardry:freezing_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of frost, causing it to freeze its victims. The magic wears off after 45 seconds. +spell.wizardry:frost_axe.desc=Creates a frozen axe which freezes enemies when hit. Lasts for 30 seconds. +spell.wizardry:frost_ray.desc=Creates a stream of frost in the direction you are pointing which slows and continually damages targets. +spell.wizardry:frost_sigil.desc=Places a magical ice trap on the ground which damages and freezes the creature that triggers it. +spell.wizardry:glide.desc=Allows the caster to glide downwards while in the air and holding the use item button. +spell.wizardry:greater_fireball.desc=Launches a large fireball in the direction you are pointing which explodes on impact. +spell.wizardry:greater_heal.desc=Heals the caster by 4 hearts. +spell.wizardry:group_heal.desc=Heals the caster and all nearby allies and summoned creatures by 3 hearts. +spell.wizardry:growth_aura.desc=Grows all crops near the caster. Also grows tall grass and flowers on grass. +spell.wizardry:hailstorm.desc=It was during the great winter of the third age that the ice mages discovered their true power. +spell.wizardry:heal.desc=Heals the caster by 2 hearts. +spell.wizardry:heal_ally.desc=Heals the target by 2 and a half hearts. +spell.wizardry:healing_aura.desc=Creates a zone of healing energy which regenerates the health of any ally inside it. Any undead inside the healing aura will slowly take damage. +spell.wizardry:homing_spark.desc=Creates a floating spark which moves towards enemies. +spell.wizardry:ice_age.desc="You shall be frozen for an eternity!" +spell.wizardry:ice_charge.desc=Launches an ice charge which explodes on impact, freezing nearby creatures and releasing shards in all directions. +spell.wizardry:ice_lance.desc=Fires a great spear of ice in the direction you are pointing which overpenetrates targets, damaging and freezing them in the process. +spell.wizardry:ice_shard.desc=Fires a shard of ice in the direction you are pointing which damages and slows targets when hit. +spell.wizardry:ice_shroud.desc=Creates a shroud of cold around the caster for 30 seconds, causing anything that attacks them to be frozen. +spell.wizardry:ice_spikes.desc=Causes razor-sharp ice spikes to rise from the ground where you are pointing, skewering any creatures caught amongst them. +spell.wizardry:ice_statue.desc=Freezes the target solid for 20 seconds or until broken out. The target cannot move or do anything while frozen but is also impervious to all damage. +spell.wizardry:ignite.desc=Sets the target on fire for 10 seconds. Also works like a flint and steel. +spell.wizardry:imbue_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with magic, rendering it more effective. The magic wears off after 45 seconds. +spell.wizardry:intimidate.desc=Emits an intimidating growl which causes nearby creatures to run away in fear. Fear stricken creatures will recover after 30 seconds. +spell.wizardry:invigorating_presence.desc=Grants the caster and all nearby allies increased strength for 45 seconds. +spell.wizardry:invisibility.desc=Makes the caster invisible for 30 seconds. +spell.wizardry:invoke_weather.desc=Changes the weather in the world. +spell.wizardry:ironflesh.desc=Greatly improves the caster's damage resistance for 30 seconds. +spell.wizardry:leap.desc=Causes the caster to jump upwards several blocks and slightly forward. +spell.wizardry:levitation.desc=Raises the caster upwards while the use item button is held. Will also negate fall damage if used before hitting the ground. +spell.wizardry:life_drain.desc=Creates a stream of withering energy in the direction you are pointing which drains the life of the target and uses it to gradually regenerate your health. +spell.wizardry:light.desc=Creates a magical point of light which illuminates the surrounding area. Lasts for 30 seconds. +spell.wizardry:lightning_arrow.desc=Shoots an arrow of lightning in the direction you are pointing. +spell.wizardry:lightning_bolt.desc=Causes lightning to strike where you are pointing. +spell.wizardry:lightning_disc.desc=Sends a disk of lightning flying off in the direction you are pointing, which seeks targets. +spell.wizardry:lightning_hammer.desc="I smite you by the wrath of the heavens!" +spell.wizardry:lightning_pulse.desc=Charges the ground around the caster with lightning, damaging and repelling nearby creatures. +spell.wizardry:lightning_ray.desc=Creates a stream of lightning in the direction you are pointing which continually damages targets. +spell.wizardry:lightning_sigil.desc=Places a magical lightning trap on the ground which damages the creature that triggers it and chains lightning to other nearby creatures. +spell.wizardry:lightning_web.desc="Focus. Channel the storm in your mind through your wand and unleash its fury." +spell.wizardry:magic_missile.desc=Fires a bolt of magical energy in the direction you are pointing. +spell.wizardry:metamorphosis.desc=Changes the target into another form. Only works on some creatures. +spell.wizardry:meteor.desc=Some wizards just want to see the world burn... +spell.wizardry:mind_control.desc=Takes control of the target's mind for 30 seconds, causing it switch sides and fight for the caster instead. Will not work on creatures that are too strong-willed. +spell.wizardry:mind_trick.desc=Confuses and disorients the target for 15 seconds, rendering it unable to attack effectively. The effect will be dispelled if the target takes damage. +spell.wizardry:none.desc=To get a spell book with the /give command, use metadata: /give [player] wizardry:spell_book 1 [spell id] (if you found this book in a chest, some other mod has messed things up). +spell.wizardry:oakflesh.desc=Improves the caster's damage resistance for 30 seconds. +spell.wizardry:petrify.desc=Turns the target to stone until broken out, with a chance for it to break out when it is dark. The target cannot move or do anything while petrified but is also impervious to all damage. +spell.wizardry:phase_step.desc=Teleports the caster through a 1 block thick wall in front of them. Range upgrades will increase the thickness you can teleport through. +spell.wizardry:plague_of_darkness.desc=The darkness will consume them all... +spell.wizardry:pocket_furnace.desc=Smelts up to 5 smeltable items in the caster's inventory. Items on the hotbar will be smelted first. +spell.wizardry:pocket_workbench.desc=Allows the caster to craft items as if they were at a crafting table. +spell.wizardry:poison.desc=Fires poison in the direction you are pointing. +spell.wizardry:poison_bomb.desc=Lanches a poison bomb in the direction you are pointing which explodes on impact, poisoning nearby creatures. +spell.wizardry:replenish_hunger.desc=Replenishes the caster's food level by 6 hunger points. +spell.wizardry:ring_of_fire.desc=Creates a ring of fire around the caster, damaging all nearby enemies and setting them on fire. +spell.wizardry:shadow_ward.desc=Creates a wall of darkness in front of the caster which causes half of all incoming damage to be inflicted upon the attacker instead. +spell.wizardry:shield.desc=Creates a protective barrier of force that blocks projectiles and magic. Also grants the caster a weak resistance effect. +spell.wizardry:shockwave.desc=Boom. +spell.wizardry:silverfish_swarm.desc="Ahhhh! They're MULTIPLYING!" +spell.wizardry:sixth_sense.desc=Allows the caster to sense the locations of nearby creatures, even through walls, for 20 seconds. +spell.wizardry:slime.desc=Engulfs the target in slime which slows and continually damages it. The slime bursts after 10 seconds. +spell.wizardry:smoke_bomb.desc=Launches a smoke bomb in the direction you are pointing which explodes on impact, releasing smoke and blinding nearby creatures for a short time. +spell.wizardry:snare.desc=Sets a trap on the ground which damages and briefly slows the creature that triggers it. +spell.wizardry:snowball.desc=Launches a snowball in the direction you are pointing. +spell.wizardry:spark_bomb.desc=Launches a shock charge in the direction you are pointing which releases sparks at nearby enemies on impact. +spell.wizardry:spectral_pathway.desc=Creates an indestructible magical bridge in front of you which extends for 15 blocks. The bridge vanishes after 60 seconds. +spell.wizardry:spider_swarm.desc=Summons a swarm of venomous spiders to fight for you. The spiders will disappear after 30 seconds or if they are killed. +spell.wizardry:static_aura.desc=Surrounds the caster with lightning for 30 seconds, firing a spark of lightning at anything that hits them. +spell.wizardry:summon_blaze.desc=Summons a blaze to fight for you. The blaze will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_ice_giant.desc="Smash them!" +spell.wizardry:summon_ice_wraith.desc=Summons an ice wraith to fight for you. The ice wraith will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_iron_golem.desc=Automatic automated autonomous automaton. +spell.wizardry:summon_lightning_wraith.desc=Summons a lightning wraith to fight for you. The lightning wraith will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_phoenix.desc=From the ashes... +spell.wizardry:summon_shadow_wraith.desc=Summons a shadow wraith to fight for you. +spell.wizardry:summon_skeleton.desc=Summons a skeleton to fight for you. The skeleton will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_skeleton_legion.desc="Rise, undead army!" +spell.wizardry:summon_snow_golem.desc=Creates a snow golem to fight for you. Lasts until the snow golem dies. +spell.wizardry:summon_spirit_horse.desc=Summons a spirit horse for you to ride. The spirit horse will vanish a short while after it is dismounted, or you can dismiss it by shift-right-clicking on it with any wand. +spell.wizardry:summon_spirit_wolf.desc=Summons a spirit wolf companion to fight for you. The spirit wolf will only disappear if it is killed, or you can dismiss it by shift-right-clicking on it with any wand. +spell.wizardry:summon_storm_elemental.desc="Storm Elemental: An ancient manifestation of the elements, it can hardly contain the raw power churning within it." - The Wizard's Guide to Arcane Beings, Volume I_i +spell.wizardry:summon_wither_skeleton.desc=Summons a wither skeleton to fight for you. The wither skeleton will disappear after 30 seconds or if it is killed. +spell.wizardry:summon_zombie.desc=Summons a zombie to fight for you. The zombie will disappear after 30 seconds or if it is killed. +spell.wizardry:telekinesis.desc=Moves an item or other small object towards you, or right-clicks the block you are looking at. Can also be used to disarm players. +spell.wizardry:thunderbolt.desc=Shoots a bolt of thunder which knocks back targets. +spell.wizardry:thunderstorm.desc="Mwahahahahahaha!" +spell.wizardry:tornado.desc=Unleashes a tornado in the direction you are pointing which hurls anything in its path skywards. +spell.wizardry:transience.desc=Makes the caster transient for 20 seconds. The caster is immune to all damage while transient but cannot break or place blocks or cause any damage. +spell.wizardry:transportation.desc=Transports the caster to their remembered stone circle. To use this spell, make a circle of stones of transportation, then right click it with a wand. +spell.wizardry:vanishing_box.desc=Grants the caster access to their ender chest storage. +spell.wizardry:wall_of_frost.desc=Winter at your fingertips. +spell.wizardry:water_breathing.desc=Allows the caster to breathe underwater for 60 seconds. +spell.wizardry:whirlwind.desc=Causes the target to be blown upwards and away from you at speed. +spell.wizardry:wither.desc=Fires a ray of darkness which withers anything it touches. +spell.wizardry:wither_skull.desc=Launches a wither skull in the direction you are pointing. + +spell.wizardry:invoke_weather.sun=The rain begins to stop... +spell.wizardry:invoke_weather.rain=The heavens open... +spell.wizardry:transportation.missing=Your remembered stone circle is missing or obstructed... +spell.wizardry:transportation.undefined=You must remember the location of a stone circle first! +spell.wizardry:transportation.wrongdimension=Your remembered stone circle is in another dimension... +spell.wizardry:clairvoyance.searching=Searching... +spell.wizardry:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point +spell.wizardry:clairvoyance.outofrange=Your remembered location is too far away or inaccessible... +spell.wizardry:clairvoyance.undefined=You must remember a location first! +spell.wizardry:clairvoyance.wrongdimension=Your remembered location is in another dimension... + +potion.wizardry:frost=Frostbite +potion.wizardry:fireskin=Fireskin +potion.wizardry:ice_shroud=Ice Shroud +potion.wizardry:static_aura=Static Aura +potion.wizardry:transience=Transience +potion.wizardry:decay=Decay +potion.wizardry:sixth_sense=Sixth Sense +potion.wizardry:arcane_jammer=Arcane Jammer +potion.wizardry:mind_trick=Mind Trick +potion.wizardry:mind_control=Mind Control +potion.wizardry:font_of_mana=Font of Mana +potion.wizardry:fear=Fear + +enchantment.wizardry:magic_sword=Imbuement +enchantment.wizardry:magic_bow=Imbuement +enchantment.wizardry:flaming_weapon=Fire Imbuement +enchantment.wizardry:freezing_weapon=Frost Imbuement + +key.categories.wizardry=Wizardry + +key.wizardry:next_spell=Next Spell +key.wizardry:previous_spell=Previous Spell + +death.attack.wizardry_magic=%1$s was killed by %2$s using magic +death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic + +commands.wizardry:cast.usage=/%1$s [player] [damage multiplier] [range multiplier] [duration multiplier] [blast multiplier] +commands.wizardry:cast.success=Successfully cast %1$s +commands.wizardry:cast.success_continuous=Successfully cast %1$s; repeat the command to stop +commands.wizardry:cast.success_remote=Successfully cast %1$s as %2$s +commands.wizardry:cast.success_remote_continuous=Successfully cast %1$s as %2$s; repeat the command to stop +commands.wizardry:cast.fail=Unable to cast %1$s +commands.wizardry:cast.not_found=There is no such spell with ID %1$s +commands.wizardry:cast.tag_error=Data tag parsing failed: %s + +commands.wizardry:ally.usage=/%1$s [player] +commands.wizardry:ally.addally=%1$s has been added to %2$s's list of allies +commands.wizardry:ally.removeally=%1$s has been removed from %2$s's list of allies +commands.wizardry:ally.self=Players cannot be an ally of themselves! +commands.wizardry:ally.permission=You do not have permission to change other players' allies + +commands.wizardry:allies.usage=/%1$s [player] +commands.wizardry:allies.list=Players allied to you: %1$s +commands.wizardry:allies.list_other=Players allied to %1$s: %2$s +commands.wizardry:allies.permission=You do not have permission to view other players' allies +commands.wizardry:allies.none=None + +commands.wizardry:discoverspell.usage=/%1$s [player] +commands.wizardry:discoverspell.not_found=There is no such spell with ID %1$s +commands.wizardry:discoverspell.clear=Cleared all spell discovery data for %1$s +commands.wizardry:discoverspell.all=Added all spells to %1$s's spell discovery data +commands.wizardry:discoverspell.addspell=Added %1$s to %2$s's spell discovery data +commands.wizardry:discoverspell.removespell=Removed %1$s from %2$s's spell discovery data + +config.wizardry.title.general=Mod Options + +config.wizardry.category.spells=Configure Spells +config.wizardry.category.spells.tooltip=Select which spells are enabled +config.wizardry.title.spells=Spell Configuration +config.wizardry.subtitle.spells=Set a spell to false to disable it. + +config.wizardry.category.resistances=Configure Resistances +config.wizardry.category.resistances.tooltip=Configure which mobs are immune to different types of magic +config.wizardry.title.resistances=Resistance Configuration +config.wizardry.subtitle.resistances=See descriptions of individual options for more details. + +config.wizardry.category.ids=Configure IDs +config.wizardry.category.ids.tooltip=Change the IDs used by wizardry +config.wizardry.title.ids=ID Configuration +config.wizardry.subtitle.ids=Change these IDs if they conflict with another mod. + +config.wizardry.tower_rarity=Tower Rarity +config.wizardry.ore_dimensions=Ore Dimensions +config.wizardry.flower_dimensions=Flower Dimensions +config.wizardry.tower_dimensions=Tower Dimensions +config.wizardry.spell_book_drop_chance=Spell Book Drop Chance +config.wizardry.generate_loot=Generate Loot +config.wizardry.firebomb_is_craftable=Firebomb Is Craftable +config.wizardry.poison_bomb_is_craftable=Poison Bomb Is Craftable +config.wizardry.smoke_bomb_is_craftable=Smoke Bomb Is Craftable +config.wizardry.use_alternate_scroll_recipe=Use Alternate Scroll Recipe +config.wizardry.teleport_through_unbreakable_blocks=Teleport Through Unbreakable Blocks +config.wizardry.show_summoned_creature_names=Show Summoned Creature Names +config.wizardry.friendly_fire=Friendly Fire +config.wizardry.telekinetic_disarmament=Telekinetic Disarmament +config.wizardry.discovery_mode=Discovery Mode +config.wizardry.enable_shift_scrolling=Enable Shift-_scrolling +config.wizardry.minion_revenge_targeting=Minion Revenge Targeting +config.wizardry.player_damage_scaling=Player Damage Scaling Factor +config.wizardry.npc_damage_scaling=NPC Damage Scaling Factor +config.wizardry.cast_command_multiplier_limit=Cast Command Multiplier Limit +config.wizardry.summoned_creature_targets_whitelist=Summoned Creature Target Whitelist +config.wizardry.summoned_creature_targets_blacklist=Summoned Creature Target Blacklist +config.wizardry.spell_hud_position=Spell HUD Position +config.wizardry.cast_command_name=Cast Spell Command Name +config.wizardry.discoverspell_command_name=Discover Spell Command Name +config.wizardry.ally_command_name=Set Ally Command Name +config.wizardry.allies_command_name=View Allies Command Name + +config.wizardry.mobs_immune_to_fire=Mobs Immune To Fire +config.wizardry.mobs_immune_to_ice=Mobs Immune To Ice +config.wizardry.mobs_immune_to_lightning=Mobs Immune To Lightning +config.wizardry.mobs_immune_to_wither=Mobs Immune To Wither +config.wizardry.mobs_immune_to_poison=Mobs Immune To Poison + +config.wizardry.tower_rarity.tooltip=Rarity of wizard towers. Higher numbers are rarer. Set to 0 to disable wizard towers completely. +config.wizardry.ore_dimensions.tooltip=List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play! +config.wizardry.flower_dimensions.tooltip=List of dimension ids in which crystal flowers will generate. +config.wizardry.tower_dimensions.tooltip=List of dimension ids in which wizard towers will generate. +config.wizardry.spell_book_drop_chance.tooltip=The chance for mobs to drop a spell book when killed. The greater this number, the more often they will drop. Set to 0 to disable spell book drops. Set to 200 for guaranteed drops. +config.wizardry.generate_loot.tooltip=Whether to generate wizardry loot in dungeon chests. +config.wizardry.firebomb_is_craftable.tooltip=Whether firebombs can be crafted or not. +config.wizardry.poison_bomb_is_craftable.tooltip=Whether poison bombs can be crafted or not. +config.wizardry.smoke_bomb_is_craftable.tooltip=Whether smoke bombs can be crafted or not. +config.wizardry.use_alternate_scroll_recipe.tooltip=Whether to require a magic crystal in the shapeless crafting recipe for blank scrolls. Set to true if another mod adds a conflicting recipe. +config.wizardry.teleport_through_unbreakable_blocks.tooltip=Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. +config.wizardry.show_summoned_creature_names.tooltip=Whether to show summoned creatures' names and owners above their heads. +config.wizardry.friendly_fire.tooltip=Whether to allow players to damage their designated allies using magic. +config.wizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell.wizardry: Set to false to prevent stealing of items. +config.wizardry.discovery_mode.tooltip=For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false. +config.wizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. +config.wizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge attack their owner if their owner attacks them. +config.wizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. +config.wizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. +config.wizardry.cast_command_multiplier_limit.tooltip=Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned! +config.wizardry.summoned_creature_targets_whitelist.tooltip=List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.summoned_creature_targets_blacklist.tooltip=List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.spell_hud_position.tooltip=The position of the spell HUD. +config.wizardry.cast_command_name.tooltip=The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead. +config.wizardry.discoverspell_command_name.tooltip=The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead. +config.wizardry.ally_command_name.tooltip=The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead. +config.wizardry.allies_command_name.tooltip=The name of the /allies command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /allies you would type /magic instead. + +config.wizardry.mobs_immune_to_fire.tooltip=List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.mobs_immune_to_ice.tooltip=List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.mobs_immune_to_lightning.tooltip=List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.mobs_immune_to_wither.tooltip=List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). +config.wizardry.mobs_immune_to_poison.tooltip=List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry.wizard). + +wizard.debug=%1$s, %2$s, %3$s \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/lang/es_ES.lang b/src/main/resources/assets/wizardry/lang/es_ES.lang new file mode 100644 index 00000000..7608a50f --- /dev/null +++ b/src/main/resources/assets/wizardry/lang/es_ES.lang @@ -0,0 +1,736 @@ +tile.wizardry:arcane_workbench.name=Mesa de Trabajo Arcana +tile.wizardry:crystal_ore.name=Mena de Cristal Magico +tile.wizardry:petrified_stone.name=Piedra Petrificada +tile.wizardry:ice_statue.name=Estatua de Hielo +tile.wizardry:crystal_flower.name=Flor de Cristal Magico +tile.wizardry:snare.name=Trampa +tile.wizardry:transportation_stone.name=Piedra de Transportacion +tile.wizardry:spectral_block.name=Bloque Espectral +tile.wizardry:crystal_block.name=Bloque de Cristal Magico + +item.wizardry:magic_crystal.name=Cristal Magico +item.wizardry:magic_wand.name=Varita Magica +item.wizardry:apprentice_wand.name=Varita de Aprendiz +item.wizardry:advanced_wand.name=Varita Avanzada +item.wizardry:master_wand.name=Varita de Maestro +item.wizardry:spell_book.name=Libro de Hechizo + +item.wizardry:arcane_tome.name=Tomo de lo Arcano +item.wizardry:arcane_tome.desc1=Mejora cualquier %1$s +item.wizardry:arcane_tome.desc2=varita a nivel %1$s + +item.wizardry:wizard_handbook.name=El Manual del Hechizero +item.wizardry:wizard_handbook.desc=por %1$s + +item.wizardry:wand.buff=+%1$s %2$s de potencia +item.wizardry:wand.spell=Hechizo actual: %1$s +item.wizardry:wand.mana=Mana: %1$s/%2$s + +item.wizardry:wand.addally=%1$s ha sido anadido a tu lista de aliados +item.wizardry:wand.removeally=%1$s ha sido removido a tu lista de aliados + +item.wizardry:basic_fire_wand.name=Varita de Ascuas +item.wizardry:basic_ice_wand.name=Varita de Escarcha +item.wizardry:basic_lightning_wand.name=Varita de Chispas +item.wizardry:basic_necromancy_wand.name=Varita de las Sombras +item.wizardry:basic_earth_wand.name=Varita del Bosque +item.wizardry:basic_sorcery_wand.name=Varita del Misterio +item.wizardry:basic_healing_wand.name=Varita de la Curacion + +item.wizardry:apprentice_fire_wand.name=Varita del Piromano Aprendiz +item.wizardry:apprentice_ice_wand.name=Varita del Mago de Hielo Aprendiz +item.wizardry:apprentice_lightning_wand.name=Varita del Mago de Tormenta Aprendiz +item.wizardry:apprentice_necromancy_wand.name=Varita del Nigromante Aprendiz +item.wizardry:apprentice_earth_wand.name=Varita del Mago de Tierra Aprendiz +item.wizardry:apprentice_sorcery_wand.name=Varita del Hechicero Aprendiz +item.wizardry:apprentice_healing_wand.name=Varita del Sanador Aprendiz + +item.wizardry:advanced_fire_wand.name=Varita del Piromano +item.wizardry:advanced_ice_wand.name=Varita del Mago de Hielo +item.wizardry:advanced_lightning_wand.name=Varita del Mago de Tormenta +item.wizardry:advanced_necromancy_wand.name=Varita del Nigromante +item.wizardry:advanced_earth_wand.name=Varita del Mago de Tierra +item.wizardry:advanced_sorcery_wand.name=Varita del Hechicero +item.wizardry:advanced_healing_wand.name=Varita del Sanador + +item.wizardry:master_fire_wand.name=Varita del Piromano Maestro +item.wizardry:master_ice_wand.name=Varita del Mago de Hielo Maestro +item.wizardry:master_lightning_wand.name=Varita del Mago de Tormenta Maestro +item.wizardry:master_necromancy_wand.name=Varita del Nigromante Maestro +item.wizardry:master_earth_wand.name=Varita del Mago de Tierra Maestro +item.wizardry:master_sorcery_wand.name=Varita del Hechicero Maestro +item.wizardry:master_healing_wand.name=Varita del Sanador Maestro + +item.wizardry:spectral_sword.name=Espada Espectral +item.wizardry:spectral_pickaxe.name=Pico Espectral +item.wizardry:spectral_bow.name=Arco Espectral + +item.wizardry:mana_flask.name=Frasco de Mana +item.wizardry:storage_upgrade.name=Mejora de Almacenamiento para Varita +item.wizardry:siphon_upgrade.name=Mejora de Sifon para Varita +item.wizardry:condenser_upgrade.name=Mejora de Condensador para Varita +item.wizardry:range_upgrade.name=Mejora de Rango para Varita +item.wizardry:duration_upgrade.name=Mejora de Duracion para Varita +item.wizardry:cooldown_upgrade.name=Mejora de Tiempo de Reactivacion para Varita +item.wizardry:blast_upgrade.name=Mejora de Explosion para Varita +item.wizardry:attunement_upgrade.name=Mejora de Sintonizacion para Varita + +item.wizardry:flaming_axe.name=Hacha Llameante +item.wizardry:frost_axe.name=Hacha Escarchada + +item.wizardry:firebomb.name=Bomba de fuego +item.wizardry:poison_bomb.name=Bomba de veneno +item.wizardry:smoke_bomb.name=Bomba de humo + +item.wizardry:blank_scroll.name=Pergamino en blanco +item.wizardry:scroll.name=Pergamino de %1$s +item.wizardry:scroll.undiscovered.name=Pergamino "%1$s" +item.wizardry:identification_scroll.name=Pergamino de la Identificacion +item.wizardry:identification_scroll.desc1=%1$sIdentifica un libro o pergamino +item.wizardry:identification_scroll.desc2=%1$sdesconocido +item.wizardry:identification_scroll.nothing_to_identify=Nada que identificar! + +item.wizardry:armour_upgrade.name=Sello Arcano de la Proteccion +item.wizardry:armour_upgrade.desc1=%1$sMejora cualquier armadura +item.wizardry:armour_upgrade.desc2=%1$spara volverla %2$slegendaria + +item.wizardry:magic_silk.name=Seda Magica + +item.wizardry:wizard_armour.legendary=Legendario +item.wizardry:wizard_armour.buff=-%1$s %2$s costo +item.wizardry:wizard_armour.mana=Mana: %1$s/%2$s + +item.wizardry:wizard_hat.name=Sombrero de Mago +item.wizardry:wizard_robe.name=Tunica de Mago +item.wizardry:wizard_leggings.name=Pantalones de Mago +item.wizardry:wizard_boots.name=Botas de Mago + +item.wizardry:wizard_hat_fire.name=Sombrero de Piromano +item.wizardry:wizard_robe_fire.name=Tunica de Piromano +item.wizardry:wizard_leggings_fire.name=Pantalones de Piromano +item.wizardry:wizard_boots_fire.name=Botas de Piromano + +item.wizardry:wizard_hat_ice.name=Sombrero de Mago de Hielo +item.wizardry:wizard_robe_ice.name=Tunica de Mago de Hielo +item.wizardry:wizard_leggings_ice.name=Pantalones de Mago de Hielo +item.wizardry:wizard_boots_ice.name=Botas de Mago de Hielo + +item.wizardry:wizard_hat_lightning.name=Sombrero de Mago de Tormenta +item.wizardry:wizard_robe_lightning.name=Tunica de Mago de Tormenta +item.wizardry:wizard_leggings_lightning.name=Pantalones de Mago de Tormenta +item.wizardry:wizard_boots_lightning.name=Botas de Mago de Tormenta + +item.wizardry:wizard_hat_necromancy.name=Sombrero de Nigromante +item.wizardry:wizard_robe_necromancy.name=Tunica de Nigromante +item.wizardry:wizard_leggings_necromancy.name=Pantalones de Nigromante +item.wizardry:wizard_boots_necromancy.name=Botas de Nigromante + +item.wizardry:wizard_hat_earth.name=Sombrero de Mago de Tierra +item.wizardry:wizard_robe_earth.name=Tunica de Mago de Tierra +item.wizardry:wizard_leggings_earth.name=Pantalones de Mago de Tierra +item.wizardry:wizard_boots_earth.name=Botas de Mago de Tierra + +item.wizardry:wizard_hat_sorcery.name=Sombrero de Hechicero +item.wizardry:wizard_robe_sorcery.name=Tunica de Hechicero +item.wizardry:wizard_leggings_sorcery.name=Pantalones de Hechicero +item.wizardry:wizard_boots_sorcery.name=Botas de Hechicero + +item.wizardry:wizard_hat_healing.name=Sombrero de Sanador +item.wizardry:wizard_robe_healing.name=Tunica de Sanador +item.wizardry:wizard_leggings_healing.name=Pantalones de Sanador +item.wizardry:wizard_boots_healing.name=Botas de Sanador + +item.wizardry:spawn_wizard.name=Invocar Mago +item.wizardry:spawn_evil_wizard.name=Invocar Mago Malvado + +item.wizardry:spectral_helmet.name=Casco Espectral +item.wizardry:spectral_chestplate.name=Pechera Espectral +item.wizardry:spectral_leggings.name=Grebas Espectrales +item.wizardry:spectral_boots.name=Botas Espectrales + +entity.wizardry.summonedcreature.nameplate=%2$s de %1$s + +entity.wizardry.zombie_minion.name=Zombi +entity.wizardry.skeleton_minion.name=Esqueleto +entity.wizardry.spider_minion.name=Arana +entity.wizardry.blaze_minion.name=Blaze +entity.wizardry.ice_wraith.name=Espectro de Hielo +entity.wizardry.lightning_wraith.name=Espectro de Relampago +entity.wizardry.shadow_wraith.name=Espectro de las Sombras +entity.wizardry.spirit_wolf.name=Lobo Espiritual +entity.wizardry.spirit_horse.name=Caballo Espiritual +entity.wizardry.ice_giant.name=Gigante de Hielo +entity.wizardry.phoenix.name=Fenix +entity.wizardry.wizard.name=Mago +entity.wizardry.magic_slime.name=Slime Magico +entity.wizardry.silverfish_minion.name=Lepisma +entity.wizardry.storm_elemental.name=Elemental de Tormenta +entity.wizardry.evil_wizard.name=Mago Malvado +entity.wizardry.decoy.name=Senuelo + +entity.wizardry.magic_missile.name=Magia +entity.wizardry.arc.name=Magia +entity.wizardry.spark_bomb.name=Magia +entity.wizardry.ice_shard.name=Magia +entity.wizardry.firebomb.name=Magic +entity.wizardry.poison_bomb.name=Magia +entity.wizardry.force_orb.name=Magia +entity.wizardry.spark.name=Magia +entity.wizardry.darkness_orb.name=Magia +entity.wizardry.fire_sigil.name=Magia +entity.wizardry.frost_sigil.name=Magia +entity.wizardry.lightning_sigil.name=Magia +entity.wizardry.lightning_arrow.name=Magia +entity.wizardry.firebolt.name=Magia +entity.wizardry.ice_charge.name=Magia +entity.wizardry.force_arrow.name=Magia +entity.wizardry.dart.name=Magia +entity.wizardry.lightning_disc.name=Magia +entity.wizardry.thunderbolt.name=Magia +entity.wizardry.decay.name=Magia +entity.wizardry.ice_lance.name=Magia +entity.wizardry.smoke_bomb.name=Magia +entity.wizardry.ice_spike.name=Magia + +entity.wizardry.black_hole.name=Agujero Negro +entity.wizardry.shield.name=Escudo +entity.wizardry.meteor.name=Meteoro +entity.wizardry.blizzard.name=Ventisca +entity.wizardry.bubble.name=Burbuja +entity.wizardry.tornado.name=Tornado +entity.wizardry.lightning_hammer.name=Martillo Relampago +entity.wizardry.arrow_rain.name=Lluvia de Flechas +entity.wizardry.healing_aura.name=Aura Curador +entity.wizardry.forcefield.name=Campo de Fuerza +entity.wizardry.ring_of_fire.name=Anillo de Fuego +entity.wizardry.earthquake.name=Terremoto +entity.wizardry.falling_grass.name=Hierba Descendiente +entity.wizardry.hailstorm.name=Tormenta de Granizo +entity.wizardry.lightning_pulse.name=Pulso de Relampago + +item_group.wizardry=Wizardry +item_group.wizardryspells=Hechizos de Wizardry + +achievement.crystal=Un Cristral Curioso... +achievement.crystal.desc=Pica un Cristal Magico +achievement.arcane_initiate=Inicio Arcano +achievement.arcane_initiate.desc=Craftea una varita magica con una pepita de oro, un palo y un cristal magico +achievement.apprentice=Aprendiz de Mago +achievement.apprentice.desc=Usa un tomo de lo arcano para mejorar tu varita +achievement.master=Maestro Arcano +achievement.master.desc=Obten una varita de maestro +achievement.all_spells=Mago de Todos los Oficios +achievement.all_spells.desc=Lanza todos los hechizos disponibles +achievement.wizard_trade=Comercio Magico +achievement.wizard_trade.desc=Compra un objeto a un mago +achievement.buy_master_spell=El Conocimiento es Poder +achievement.buy_master_spell.wizardry:desc=Compra un hechizo maestro a un mago +achievement.freeze_blaze=Ya No Estas Tan Caliente +achievement.freeze_blaze.desc=Congela a un blaze +achievement.charge_creeper=Va a Explotar!! +achievement.charge_creeper.desc='Accidentalmente' carga un creeper +achievement.frankenstein=Frankenstein +achievement.frankenstein.desc=Convierte a un cerdo en un hombrecerdo zombi usando el hechizo de rayo +achievement.special_upgrade=Remiendo Arcano +achievement.special_upgrade.desc=Aplica una mejora a una varita +achievement.craft_flask=Es Magia, Embotellada! +achievement.craft_flask.desc=Craftea un frasco de mana +achievement.elemental=Elemental +achievement.elemental.desc=Obten una varita elemental +achievement.armour_set=Now Eres un Mago Apropiado +achievement.armour_set.desc=Craftea y equipa el set completo de armadura de mago +achievement.legendary=Legendario +achievement.legendary.desc=Obten una pieza de armadura de mago legendaria +achievement.self_destruct=Tiro por la culata +achievement.self_destruct.desc=Muere por tu propia magia +achievement.pig_tornado=No De Nuevo... +achievement.pig_tornado.desc=Monta un cerdo hacia un tornado +achievement.jam_wizard=Sesion de Interferencia +achievement.jam_wizard.desc=Usa el hechizo arcano de interferencia en un mago +achievement.slime_skeleton=Situacion Pegajosa +achievement.slime_skeleton.desc=Sumerge un esqueleto en slime +achievement.anger_wizard=Te Arrepentiras de Eso +achievement.anger_wizard.desc=Haz que un mago se enoje +achievement.defeat_evil_wizard=Justicia +achievement.defeat_evil_wizard.desc=Derrota a un mago malvado +achievement.max_out_wand=Equipada Al Maximo! +achievement.max_out_wand.desc=Aplica el maximo numero de mejoras a una varita maestra +achievement.element_master=Maestria Elemental +achievement.element_master.desc=Lanza todos los hechizos de cualquier elemento +achievement.identify_spell=Apreciacion Arcana +achievement.identify_spell.wizardry:desc=Usa un pergamino de la identificacion para identificar un libro de hechizos o pergamino + +tile.wizardry:transportation_stone.confirm=A partir de ahora retornaras a este lugar cuando lances %1$s +tile.wizardry:transportation_stone.invalid=Primero debes hacer un circulo con 8 piedras de transportacion! + +container.wizardry:arcane_workbench=Mesa de Trabajo Arcana +container.wizardry:arcane_workbench.apply=Aplicar +container.wizardry:arcane_workbench.mana=Mana: +container.wizardry:arcane_workbench.upgrades=Mejoras Aplicadas: + +tier.basic=Novato +tier.apprentice=Aprendiz +tier.advanced=Avanzado +tier.master=Maestro + +element.simple=Ninguno +element.fire=Fuego +element.ice=Hielo +element.lightning=Rayo +element.necromancy=Nigromancia +element.earth=Tierra +element.sorcery=Hechiceria +element.healing=Curacion + +element.simple.wizard=Mago +element.fire.wizard=Piromano +element.ice.wizard=Mago de Hielo +element.lightning.wizard=Mago de Tormenta +element.necromancy.wizard=Nigromante +element.earth.wizard=Mago de Tierra +element.sorcery.wizard=Hechicero +element.healing.wizard=Curador + +spelltype.attack=Ataque +spelltype.defence=Defensa +spelltype.utility=Utilidad +spelltype.minion=Secuaz + +spell.disabled=%1$s ha sido desactivado en la configuracion +spell.resist=%1$s resistio %2$s +spell.discover=Descubrio el hechizo %1$s! + +spell.wizardry:agility=Agilidad +spell.wizardry:arc=Arco Electrico +spell.wizardry:arcane_jammer=Perturbador Arcano +spell.wizardry:arrow_rain=Lluvia de Flechas +spell.wizardry:banish=Desaparecer +spell.wizardry:black_hole=Agujero Negro +spell.wizardry:blink=Parpadeo +spell.wizardry:blizzard=Ventisca +spell.wizardry:bubble=Burbuja +spell.wizardry:chain_lightning=Cadena de Rayos +spell.wizardry:clairvoyance=Clarividencia +spell.wizardry:cobwebs=Telas de Araña +spell.wizardry:conjure_armour=Conjurar Armadura +spell.wizardry:conjure_bow=Conjurar Arco +spell.wizardry:conjure_pickaxe=Conjurar Pico +spell.wizardry:conjure_sword=Conjurar Espada +spell.wizardry:cure_effects=Purificar Efectos +spell.wizardry:curse_of_soulbinding=Maldicion de Atadura al Alma +spell.wizardry:darkness_orb=Orbe de la Oscuridad +spell.wizardry:darkvision=Vision Oscura +spell.wizardry:dart=Dardo +spell.wizardry:decay=Deterioro +spell.wizardry:decoy=Senuelo +spell.wizardry:detonate=Detonar +spell.wizardry:diamondflesh=Piel de Diamante +spell.wizardry:earthquake=Terremoto +spell.wizardry:entrapment=Atrapamiento +spell.wizardry:fireball=Bola de Fuego +spell.wizardry:firebolt=Disparo de Fuego +spell.wizardry:firebomb=Bomba de Fuego +spell.wizardry:fire_resistance=Resistencia al Fuego +spell.wizardry:fire_sigil=Sigilo de Fuego +spell.wizardry:fireskin=Piel de Fuego +spell.wizardry:firestorm=Tormenta de Fuego +spell.wizardry:flame_ray=Rayo de Fuego +spell.wizardry:flaming_axe=Hacha Llameante +spell.wizardry:flaming_weapon=Arma Llameante +spell.wizardry:flight=Vuelo +spell.wizardry:font_of_mana=Fuente de Mana +spell.wizardry:font_of_vitality=Fuente de Vitalidad +spell.wizardry:force_arrow=Flecha de Fuerza +spell.wizardry:forcefield=Campo de Fuerza +spell.wizardry:force_orb=Orbe de Fuerza +spell.wizardry:forests_curse=Maldicion del Bosque +spell.wizardry:freeze=Congelar +spell.wizardry:freezing_weapon=Arma Congelante +spell.wizardry:frost_axe=Hacha Escarchada +spell.wizardry:frost_ray=Rayo de Escarcha +spell.wizardry:frost_sigil=Sigilo de Escarcha +spell.wizardry:glide=Planear +spell.wizardry:greater_fireball=Bola de Fuego Mayor +spell.wizardry:greater_heal=Curacion Mayor +spell.wizardry:group_heal=Curacion Grupal +spell.wizardry:growth_aura= Aura de Crecimiento +spell.wizardry:hailstorm=Tormenta de Granizo +spell.wizardry:heal=Curar +spell.wizardry:heal_ally=curar Aliado +spell.wizardry:healing_aura=Aura de Curacion +spell.wizardry:homing_spark=Chispa Dirigida +spell.wizardry:ice_age=Era de Hielo +spell.wizardry:ice_charge=Carga de Hielo +spell.wizardry:ice_lance=Lanza de Hielo +spell.wizardry:ice_shard=Fragmento de Hielo +spell.wizardry:ice_shroud=Velo de Hielo +spell.wizardry:ice_spikes=Pinchos de Hielo +spell.wizardry:ice_statue=Estatua de Hielo +spell.wizardry:ignite=Encender +spell.wizardry:imbue_weapon=Imbuir Arma +spell.wizardry:intimidate=Intimidar +spell.wizardry:invigorating_presence=Presencia Vigorizante +spell.wizardry:invisibility=Invisibilidad +spell.wizardry:invoke_weather=Invocar clima +spell.wizardry:ironflesh=Piel de Hierro +spell.wizardry:leap=Salto +spell.wizardry:levitation=Levitacion +spell.wizardry:life_drain=Drenaje de Vida +spell.wizardry:light=Luz +spell.wizardry:lightning_arrow=Flecha de Rayo +spell.wizardry:lightning_bolt=Disparo de Rayo +spell.wizardry:lightning_disc=Disco de Rayo +spell.wizardry:lightning_hammer=Martillo Relampago +spell.wizardry:lightning_pulse=Pulso Electrico +spell.wizardry:lightning_ray=Rayo Electrico +spell.wizardry:lightning_sigil=Sigilo Electrico +spell.wizardry:lightning_web=Red Electrica +spell.wizardry:magic_missile=Misil Magico +spell.wizardry:metamorphosis=Metamorfosis +spell.wizardry:meteor=Meteoro +spell.wizardry:mind_control=Control Mental +spell.wizardry:mind_trick=Truco Mental +spell.wizardry:none=[Espacio Vacio] +spell.wizardry:oakflesh=Piel de Roble +spell.wizardry:petrify=Petrificar +spell.wizardry:phase_step=Paso de Fase +spell.wizardry:plague_of_darkness=Plaga de la Oscuridad +spell.wizardry:pocket_furnace=Horno del Bolsillo +spell.wizardry:pocket_workbench=Mesa de Trabajo de Bolsillo +spell.wizardry:poison=Veneno +spell.wizardry:poison_bomb=Bomba de Veneno +spell.wizardry:replenish_hunger=Rellenar hambre +spell.wizardry:ring_of_fire=Anillo de Fuego +spell.wizardry:shadow_ward=Guarda de las Sombras +spell.wizardry:shield=Escudo +spell.wizardry:shockwave=Onda de Choque +spell.wizardry:silverfish_swarm=Emjambre de Lepismas +spell.wizardry:sixth_sense=Sexto Sentido +spell.wizardry:slime=Slime +spell.wizardry:smoke_bomb=Bomba de Humo +spell.wizardry:snare=Trampa +spell.wizardry:snowball=Bola de Nieve +spell.wizardry:spark_bomb=Bomba de Chispa +spell.wizardry:spectral_pathway=Camino Espectral +spell.wizardry:spider_swarm=Emjambre de Arañas +spell.wizardry:static_aura=Aura Estatica +spell.wizardry:summon_blaze=Invocar Blaze +spell.wizardry:summon_ice_giant=Invocar Gigante de Hielo +spell.wizardry:summon_ice_wraith=Invocar Espectro de Hielo +spell.wizardry:summon_iron_golem=Invocar Golem de Hierro +spell.wizardry:summon_lightning_wraith=Invocar Espectro de Rayo +spell.wizardry:summon_phoenix=Invocar Fenix +spell.wizardry:summon_shadow_wraith=Invocar Espectro de las Sombras +spell.wizardry:summon_skeleton=Invocar Esqueleto +spell.wizardry:summon_skeleton_legion=Invocar Legion de Esqueletos +spell.wizardry:summon_snow_golem=Invocar Golem de Nieve +spell.wizardry:summon_spirit_horse=Invocar Caballo Espiritual +spell.wizardry:summon_spirit_wolf=Invocar Lobo Espiritual +spell.wizardry:summon_storm_elemental=Invocar Elemental del Rayo +spell.wizardry:summon_wither_skeleton=Invocar Esqueleto del Wither +spell.wizardry:summon_zombie=Invocar Zombi +spell.wizardry:telekinesis=Telequinesis +spell.wizardry:thunderbolt=Rayo +spell.wizardry:thunderstorm=Tormenta Electrica +spell.wizardry:tornado=Tornado +spell.wizardry:transience=Transitoriedad +spell.wizardry:transportation=Transportacion +spell.wizardry:vanishing_box=Caja Desvaneciente +spell.wizardry:wall_of_frost=Pared de Escarcha +spell.wizardry:water_breathing=Respiracion Acuatica +spell.wizardry:whirlwind=Remolino de Viento +spell.wizardry:wither=Marchitar +spell.wizardry:wither_skull=Craneo de Wither + +spell.wizardry:agility.desc=Concede al mago velocidad de movimiento incrementada y un salto mas alto por 30 segundos. +spell.wizardry:arc.desc=Dispara una chispa de rayo al objetivo. +spell.wizardry:arcane_jammer.desc=No permite que el usuario use magia en los proximos 15 segundos. +spell.wizardry:arrow_rain.desc="Arqueros, disparen!" +spell.wizardry:banish.desc=Teletransporta al objetivo una posicion cercana aleatoria en contra de su voluntad. +spell.wizardry:black_hole.desc=Desgarra la realidad. +spell.wizardry:blink.desc=Teletransporta al mago a la posicion que estan apuntando. +spell.wizardry:blizzard.desc=Crea una zona de aire frio, la cual ralentiza y hiere continuamente a cualquiera en su interior. El creador del hechizo es inmune al dano pero no al efecto. +spell.wizardry:bubble.desc=Dispara un chorro de burbujas que causa que lo primero que toque flote hacia el cielo. La burbuja explota despues de un tiempo o si el objetivo es golpeado. +spell.wizardry:chain_lightning.desc=Dispara un relampago a un objetivo, el cual hace cadena con objetivos cercanos hasta dos veces. +spell.wizardry:clairvoyance.desc=Revela el camino hacia una localizacion guardada. Con este hechizo seleccionado, haga shift-clic derecho en un bloque para guardarlo. Lanza este hechizo para revelar el camino. El camino desaparecera despues de 90 segundos. +spell.wizardry:cobwebs.desc=Crea telas de arana en la direccion a la cual estas apuntando, lo cual limita la movilidad de tu objetivo. Las telas de arana despareceran en 20 segundos o si son rotas. +spell.wizardry:conjure_armour.desc=Crea Armadura Espectral alrededor del mago lo cual ofrece proteccion similar a la armadura de hierro. La armadura dura 60 segundos. El mago debe tener el espacio de armadura vacio. +spell.wizardry:conjure_bow.desc=Crea un Arco Espectral con flechas ilimitadas que dura 30 segundos. +spell.wizardry:conjure_pickaxe.desc=Crea un Pico Espectral con fuerza igual a la de un Pico de Hierro, el cual dura 30 segundos. +spell.wizardry:conjure_sword.desc=Crea una Espada Espectral con igual fuerza que una de hierro y dura 30 segundos. +spell.wizardry:cure_effects.desc=Purifica al usuario de todos los efectos de pocion, ya sean buenos o malos. +spell.wizardry:curse_of_soulbinding.desc=Provoca que el alma del objetivo esta ligada al del mago, lo que significa que todo el dano que recibe el mago lo recibe el objetivo. La maldicion dura hasta que uno de los dos muera. +spell.wizardry:darkness_orb.desc=Dispara una bala de energia oscura en la direccion que apuntes, la cual aplicar wither. +spell.wizardry:darkvision.desc=Concede vision nocturna por 45 segundos. +spell.wizardry:dart.desc=Dispara un dardo en la direccion que estas apuntando el cual hiere y debilita al objetivo. +spell.wizardry:decay.desc=Crea un pezado de deterioro en el suelo lo cual infecta y hiere a cualquier criatura que lo pise, tambien causa que estas criatura sigan esparciendo el deterioro por donde caminen. +spell.wizardry:decoy.desc=Crea un clon ilusorio del mago que atrae a los enemigos. El senuelo desaparecera en 30 segundos. +spell.wizardry:detonate.desc=Causa un explosion donde estes mirando, hiriendo a todas las criaturas cercanas - incluyendo al mago si se encuentra muy cerca. +spell.wizardry:diamondflesh.desc="Tus flechas no son nada contra mi!" +spell.wizardry:earthquake.desc=Un verdadero de Mago de Tierra puede mover montanas. +spell.wizardry:entrapment.desc=Atrpa al objetivo en una esfera de oscuridad que lo eleva y hiere continuamente. +spell.wizardry:fireball.desc=Lanza una bola de fuego en la direccion a la que apuntes. +spell.wizardry:firebolt.desc=Dispara un chorro de fuego a corta distancia en frente de ti. +spell.wizardry:firebomb.desc=Lanza una bomba de fuego, la cual detona cuando impacta quemando todo a su alrededor. +spell.wizardry:fire_resistance.desc=Concede resistencia al fuego al mago por 30 segundos. +spell.wizardry:fire_sigil.desc=Coloca una trampa de fuego que quema y hiere a la criatura que la pise. +spell.wizardry:fireskin.desc=Envuelve al mago en fuego por 30 segundos, provocando que cualquier que lo toque se queme. +spell.wizardry:firestorm.desc="Yo soy el dragon." +spell.wizardry:flame_ray.desc=Crea una corriente de llamas en la direccion a la que apuntas, la cual quema todo a su paso. +spell.wizardry:flaming_axe.desc=Crea una Hacha Llameante que quema a todos los enemigos que golpees. Dura 30 segundos. +spell.wizardry:flaming_weapon.desc=Imbuye con llamas la primera arma en el inventario del mago, la magia de deshace despues de 45 segundos. +spell.wizardry:flight.desc=Vuela como un aguila. +spell.wizardry:font_of_mana.desc="Fuimos llenados con una intensa energia magica que parecia emanar del centro del..." - Extraido del diario de un mago olvidado; el resto de la pagina esta quemada. +spell.wizardry:font_of_vitality.desc=Se siente increible. +spell.wizardry:force_arrow.desc=Dispara una flecha de fuerza en la direccion que apuntes. +spell.wizardry:forcefield.desc=Crea un campo de fuerza alrededor del mago que repele criaturas y proyectiles. +spell.wizardry:force_orb.desc=Lanza una esfera de fuerza que hiere y empuja criaturas cuando impacta. +spell.wizardry:forests_curse.desc="Como te atreves a entrar en mi bosque!" +spell.wizardry:freeze.desc=Congela al objetivo por 10 segundos. Tambien congela el agua y crea nieve en el suelo. +spell.wizardry:freezing_weapon.desc=Imbuye el poder del frio a la primera arma en el inventario del mago, provocando que el arma congela a sus objetivos. La magia deshace despues de 45 segundos. +spell.wizardry:frost_axe.desc=Crea un Hacha Escarchada la cual congela los enemigos que golpees. Dura 30 segundos. +spell.wizardry:frost_ray.desc=Crea un corriente de hielo en la direccion que apuntes la cual ralentiza y hiere continuamente al objetivo. +spell.wizardry:frost_sigil.desc=Coloca un trampa de hielo en el suelo el cual hiere y congela al cualquiera que la pise. +spell.wizardry:glide.desc=Permite que el mago planee en el aire. Debe mantenerse el boton presionado. +spell.wizardry:greater_fireball.desc=Lanza una bola de fuego de mayor tamano. +spell.wizardry:greater_heal.desc=Cura 4 corazones del mago. +spell.wizardry:group_heal.desc=Cura 3 corazones al mago, a aliados cercanos y a criaturas invocadas. +spell.wizardry:growth_aura.desc=Crece todos los cultivos cercanos al mago. Tambien hace crecer flores y hierba alta. +spell.wizardry:hailstorm.desc=Fue durante el Gran Invierno de la 3era Edad que los Magos de Hielo descubrieron su verdadero potencial. +spell.wizardry:heal.desc=Cura 2 corazones del usuario. +spell.wizardry:heal_ally.desc=Cura 2.5 corazones al objetivo. +spell.wizardry:healing_aura.desc=Crea una zona de energia curadora que regenera la salud de todos los alidados cercanos. Los No-_muertos dentro reciben dano. +spell.wizardry:homing_spark.desc=Crea una chispa flotante que persigue enemigos. +spell.wizardry:ice_age.desc="Seras congelado por toda la eternidad!" +spell.wizardry:ice_charge.desc=Lanza una carga de hielo que explota cuando impacta, congelando todas las criaturas y soltando fragmentos en todas las direcciones. +spell.wizardry:ice_lance.desc=Dispara una gran lanza de hielo en la direccion a la que estas apuntando, la cual atraviesa los objetivos hieriendo y congelandolos. +spell.wizardry:ice_shard.desc=Dispara un fragemento de hielo que hace dano y ralentiza +spell.wizardry:ice_shroud.desc=Cubre al mago con hielo, lo que ocasiona que cualquier que lo ataque sea congelado. +spell.wizardry:ice_spikes.desc=Causa que pinchos de hielo crezcan desde el suelo hiriendo a los enemigos. +spell.wizardry:ice_statue.desc=Congela al objetivo durante 20 segundos. El objetivo no se puede mover ni atacar pero tambien es inmune al dano. +spell.wizardry:ignite.desc=Quema al objetivo. Tambien funciona como un mechero. +spell.wizardry:imbue_weapon.desc=Imbuye la primera arma en el inventario con magia, haciendola mas efectiva. La magia se deshace despues de 45 segundos. +spell.wizardry:intimidate.desc=Emite un grunido intimidante el cual provoca que las criaturas espacen. +spell.wizardry:invigorating_presence.desc=Concede al mago y a los aliados cercanos fuerza incrementada por 45 segundos. +spell.wizardry:invisibility.desc=Le otorga invisibilidad al mago por 30 segundos. +spell.wizardry:invoke_weather.desc=Cambia el clima del mundo. +spell.wizardry:ironflesh.desc=Mejora grandemente la resistencia del mago por 30 segundos. +spell.wizardry:leap.desc=Causa que el mago salte alto y se mueve levemente hacia adelante. +spell.wizardry:levitation.desc=Levanta al mago hacia el cielo mientras el boton siga presionado. Si es usando antes de golpear el suelo, anula el dano por caida. +spell.wizardry:life_drain.desc=Crea una correinte de energia oscura que drena la vida de tu objetivo y te cura. +spell.wizardry:light.desc=Crea una esfera de luz que alumbra el area. Dura 30 segundos. +spell.wizardry:lightning_arrow.desc=Lanza una flecha electrificada en la direccion que apuntes. +spell.wizardry:lightning_bolt.desc=Causa que un trueno caiga en la direccion que apuntes. +spell.wizardry:lightning_disc.desc=Envia un disco electrico en la direccion que apuntes, el cual busca objetivos. +spell.wizardry:lightning_hammer.desc="Te golpeare con la ira de los cielos!" +spell.wizardry:lightning_pulse.desc=Carga el suelo cerca del mago con corriente electrica, hiriendo y repeliendo criaturas cercanas. +spell.wizardry:lightning_ray.desc=Crea una corriente de energia electrica que hiere a tus objetivos continuamente. +spell.wizardry:lightning_sigil.desc=Coloca una trampa electrificada que electrocuta a la criatura que la pise. +spell.wizardry:lightning_web.desc="Concentrare. Canaliza la tormenta en tu mente a traves de tu varita y liberala." +spell.wizardry:magic_missile.desc=Dispara una bala de energia magica. +spell.wizardry:metamorphosis.desc=Cambia la forma del objetivo. Solo funciona en algunas criaturas. +spell.wizardry:meteor.desc=Algunos magos solo quieren ver el mundo arder... +spell.wizardry:mind_control.desc=Toma control de la mente del objetivo por 30 segundos, provocando que cambie de bando y peleen a tu favor. No funciona con criaturas de voluntad muy fuerte. +spell.wizardry:mind_trick.desc=Confunde y desorienta al objetivo por 15 segundos, volviendolo incapaz de atacar. El efecto se desactiva si el objetivo recibe dano. +spell.wizardry:none.desc=Para obtener un libro de hechizo con el comando /give, usa la metadata: /give [player] wizardry:spell_book 1 [spell id] (_si encontraste este libro en un cofre significa que otro mod esta alterando las cosas). +spell.wizardry:oakflesh.desc=Mejora la resistencia del amgo durante 30 segundos. +spell.wizardry:petrify.desc=Convierte al objetivo en piedra hasta que se libere, con un chance de liberarse cuando se pone de noche. El objetivo no se puede mover ni atacar y no puede ser atacado. +spell.wizardry:phase_step.desc=Transporta al mago a traves de una pared de 1 bloque de grosor. El rango mejora el grosor por el cual te puedes transportar. +spell.wizardry:plague_of_darkness.desc=La Oscuridad los consumira a todos... +spell.wizardry:pocket_furnace.desc=Cocina 5 objetos en el inventario. Los objetos en la barra seran cocinados primero. +spell.wizardry:pocket_workbench.desc=Permite al mago craftear objetos. +spell.wizardry:poison.desc=Dispara veneno en la direccion que apuntes. +spell.wizardry:poison_bomb.desc=Lanza una bomba de veneno, la cual detona esparciendo mas veneno. +spell.wizardry:replenish_hunger.desc=Rellena 6 puntos de hambre del mago. +spell.wizardry:ring_of_fire.desc=Crea un anillo de fuego alrededor del mago, hiriendo y quemando a los objetivos cercanos. +spell.wizardry:shadow_ward.desc=Crea una pared de oscurdiad en frente del mago lo cual hace que la mitad del dano recibido sea aplicado al atacante. +spell.wizardry:shield.desc=Crea una barrera protectora que bloquea proyectiles y magia. Tambien concede al mago un efecto debil de resistencia. +spell.wizardry:shockwave.desc=Boom. +spell.wizardry:silverfish_swarm.desc="Ahhhh! Se estan multiplicando!!" +spell.wizardry:sixth_sense.desc=Le permite al mago sentir las criaturas cercanas a el, incluso a traves de paredes, durante 20 segundos. +spell.wizardry:slime.desc=Envuelve al objetivo en slime lo cual ralentiza y hiere continuamente. El slime explota despues de 10 segundos. +spell.wizardry:smoke_bomb.desc=Lanza una bomba de humo la cual explota cuando impacta. Creando una nube de humo y dandole ceguera a las criaturas en el area de impacto. +spell.wizardry:snare.desc=Coloca un trampa en el suelo que hiere y ralentiza al que la pise. +spell.wizardry:snowball.desc=Lanza una bola de nieve. +spell.wizardry:spark_bomb.desc=Lanza una bomba electrica que electrocuta a los objetivos cerca de su zona de impacto. +spell.wizardry:spectral_pathway.desc=Crea un puente magico indestructible al frente del mago que se extiende a 15 bloques. El puente desaperece luego de 60 segundos. +spell.wizardry:spider_swarm.desc=Invoca un emjambre de aranas venenosas. Desapareceran despues de 3o segundos o si son eliminadas. +spell.wizardry:static_aura.desc=Rodea al mago de electricidad durante 30 segundos, disparando chispa de rayo a cualquiera que lo golpee. +spell.wizardry:summon_blaze.desc=Invoca un Blaze que pelea por ti. El blaze desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_ice_giant.desc="Smash them!" +spell.wizardry:summon_ice_wraith.desc=Invoca un Espectro de Hielo que pelea por ti. El Espectro de Hielo desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_iron_golem.desc=Autómata autónomo automatizado automático. +spell.wizardry:summon_lightning_wraith.desc=Invoca un Espectro de Rayo que pelea por ti. El Espectro de Rayo desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_phoenix.desc=Desde las cenizas... +spell.wizardry:summon_shadow_wraith.desc=Invoca un Espectro de las Sombras que pelea por ti. +spell.wizardry:summon_skeleton.desc=Invoca un Esqueleto que pelea por ti. El esqueleto desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_skeleton_legion.desc="Levantate, Ejercito No-_muerto!" +spell.wizardry:summon_snow_golem.desc=Crea un Golem de Nieve que pelea por ti. Dura hasta que el golem muera. +spell.wizardry:summon_spirit_horse.desc=Invoca un Caballo Espectral para que lo montes. El caballo desparecera despues de que dure mucho tiempo sin ser montado o hagas shift-clic derecho con cualquier varita. +spell.wizardry:summon_spirit_wolf.desc=Invoca un Lobo Espiritual que pelea por ti. El lobo solo desparecera si es matado o haces shift-clic derecho con cualquier varita. +spell.wizardry:summon_storm_elemental.desc="Elemental de Rayo: Una manifestacion antigua de los elementos, difícilmente puede contener la energía que se agita dentro de el." - Guia del Mago sobre Entidades Arcanas, Volumen I_i +spell.wizardry:summon_wither_skeleton.desc=Invoca un Esqueleto del Wither que pelea por ti. El esqueleto del wither desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_zombie.desc=Invoca un Zombi que pelea por ti. El zombi desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:telekinesis.desc=Mueve un item o un objeto pequeno hacia ti si haces clic derecho sobre el bloque. Tambien puede desarmar jugadores. +spell.wizardry:thunderbolt.desc=Dispara una bala de trueno que empuja los enemigos. +spell.wizardry:thunderstorm.desc="Mwahahahahahaha!" +spell.wizardry:tornado.desc=Libera un tornado en la direccion que mires, el cual atrae y levanta a todos las criaturas en su paso. +spell.wizardry:transience.desc=Hace que el mago transcienda, volviendo inmune a todo dano pero volviendo incapaz de atacar, interactuar o romper bloques +spell.wizardry:transportation.desc=Teletransporta al mago a su circulo de piedra. Para guardar un circulo de piedra haz clic derecho con el hechizo seleccionado. +spell.wizardry:vanishing_box.desc=Le permite al mago accesar a su cofre de Ender. +spell.wizardry:wall_of_frost.desc=El invierno en la punta de tus dedos. +spell.wizardry:water_breathing.desc=Le permite al mago respirar debajo del agua durante 60 segundos. +spell.wizardry:whirlwind.desc=Causa que el objetivo sea soplado lejos de ti a gran velocidad. +spell.wizardry:wither.desc=Dispara un rayo de oscuridad que aplica wither a todo lo que toque. +spell.wizardry:wither_skull.desc=Lanza una Cabeza de Wither en la direccion que apuntes. + +spell.wizardry:invoke_weather.sun=La lluvia empieza a parar... +spell.wizardry:invoke_weather.rain=El cielo se abre... +spell.wizardry:transportation.missing=Tu circulo de piedra no se encuentra o esta siendo obstruido... +spell.wizardry:transportation.undefined=Debes guardar un circulo de piedra primero! +spell.wizardry:transportation.wrongdimension=Tu circulo de piedra se encuentra en otra dimension... +spell.wizardry:clairvoyance.searching=Buscando... +spell.wizardry:clairvoyance.confirm=El camino revelado al lanzar %1$s ahora te llevara a este punto +spell.wizardry:clairvoyance.outofrange=Tu punto guardado esta muy lejos o es inaccesible... +spell.wizardry:clairvoyance.undefined=Debes guardar una localizacion primero! +spell.wizardry:clairvoyance.wrongdimension=Tu localizacion guardada esta en otra dimension... + +potion.wizardry:frost=Congelacion +potion.wizardry:fireskin=Piel de Fuego +potion.wizardry:ice_shroud=Manto de Hielo +potion.wizardry:static_aura=Aura Estatica +potion.wizardry:transience=Transitoriedad +potion.wizardry:decay=Deterioro +potion.wizardry:sixth_sense=Sexto Sentido +potion.wizardry:arcane_jammer=Perturbador Arcano +potion.wizardry:mind_trick=Truco Mental +potion.wizardry:mind_control=Control Mental +potion.wizardry:font_of_mana=Fuente de Mana +potion.wizardry:fear=Miedo + +enchantment.wizardry:magic_sword=Impregnacion +enchantment.wizardry:magic_bow=Impregnacion +enchantment.wizardry:flaming_weapon=Impregnacion de Fuego +enchantment.wizardry:freezing_weapon=Impregnacion de Fuego + +key.categories.wizardry=Wizardry + +key.wizardry:next_spell=Hechizo siguiente +key.wizardry:previous_spell=Hechizo anterior + +death.attack.wizardry_magic=%1$s fue matado por %2$s usando magia +death.attack.indirect_wizardry_magic=%1$s fue matado por %2$s usando magia + +commands.wizardry:cast.usage=/%1$s [player] [damage multiplier] [range multiplier] [duration multiplier] [blast multiplier] +commands.wizardry:cast.success=Lanzado con exito %1$s +commands.wizardry:cast.success_continuous=Lanzado con exito %1$s; repite el comando para parar +commands.wizardry:cast.success_remote=Lanzado con exito %1$s como %2$s +commands.wizardry:cast.success_remote_continuous=Lanzado con exito %1$s como %2$s; repite el comando para parar +commands.wizardry:cast.fail=Imposible lanzar %1$s +commands.wizardry:cast.not_found=No hay ningun hechizo con ID %1$s + +commands.wizardry:ally.usage=/%1$s [player] +commands.wizardry:ally.addally=%1$s ha sido anadido a la lista de aliados de %2$s +commands.wizardry:ally.removeally=%1$s ha sido removido de la lista de aliados de %2$s +commands.wizardry:ally.self=Los jugadores no pueden ser aliados de si mismos! +commands.wizardry:ally.permission=No tienes permiso para cambiar los aliados de otros jugadores + +commands.wizardry:allies.usage=/%1$s [player] +commands.wizardry:allies.list=Jugadores que son aliados: %1$s +commands.wizardry:allies.list_other=Jugadores que son aliados de %1$s: %2$s +commands.wizardry:allies.permission=No tienes permiso para ver los aliados de otros jugadores +commands.wizardry:allies.none=Ninguno + +commands.wizardry:discoverspell.usage=/%1$s [player] +commands.wizardry:discoverspell.not_found=There is no such spell with ID %1$s +commands.wizardry:discoverspell.clear=Cleared all spell discovery data for %1$s +commands.wizardry:discoverspell.all=Added all spells to %1$s's spell discovery data +commands.wizardry:discoverspell.addspell=Added %1$s to %2$s's spell discovery data +commands.wizardry:discoverspell.removespell=Removed %1$s from %2$s's spell discovery data + +config.wizardry.title.general=Mod Options + +config.wizardry.category.spells=Configurar Hechizos +config.wizardry.category.spells.tooltip=Seleccionar que hechizos estan activados +config.wizardry.title.spells=Configuracion de Hechizos +config.wizardry.subtitle.spells=Establece un hechizo en falso para desactivarlo. + +config.wizardry.category.resistances=Configurar Resistencias +config.wizardry.category.resistances.tooltip=Configura cuales mobs son inmunes a los tipos de magia +config.wizardry.title.resistances=Configuracion de Resistencias +config.wizardry.subtitle.resistances=Ve las descripciones de opciones individuales para mas detalles. + +config.wizardry.category.ids=Configurar IDs +config.wizardry.category.ids.tooltip=Cambiar los IDs usados por Wizardry +config.wizardry.title.ids=Configuracion de IDs +config.wizardry.subtitle.ids=Cambia estos IDs si tienen conflicto con otro mod. + +config.wizardry.tower_rarity=Rareza de Torres +config.wizardry.ore_dimensions=Dimensiones de Mena +config.wizardry.flower_dimensions=Dimensiones de Flores +config.wizardry.tower_dimensions=Dimensiones de Torres +config.wizardry.spell_book_drop_chance=Oportunidad de Dropeo de Libro de Hechizo +config.wizardry.generate_loot=Generar Botin +config.wizardry.firebomb_is_craftable=Bomba de Fuego es crafteable +config.wizardry.poison_bomb_is_craftable=Bomba de Veneno es crafteable +config.wizardry.smoke_bomb_is_craftable=Bomba de Humo es crafteable +config.wizardry.use_alternate_scroll_recipe=Usa la receta alternativa de pergamino +config.wizardry.teleport_through_unbreakable_blocks=Teletransportarte a traves de bloques indestructibles +config.wizardry.show_summoned_creature_names=Mostrar los nombres de las criaturas invocadas +config.wizardry.friendly_fire=Fuego Amigo +config.wizardry.telekinetic_disarmament=Desarme Telequinetico +config.wizardry.discovery_mode=Modo Descubrir +config.wizardry.enable_shift_scrolling=Permitir shift-rueda del raton para cambiar de hechizo +config.wizardry.minion_revenge_targeting=Enfoque de venganza de minion +config.wizardry.player_damage_scaling=Factor de escala de dano del Jugador +config.wizardry.npc_damage_scaling=Factor de escala de dano de NPC +config.wizardry.cast_command_multiplier_limit=Limite del Multiplicador de lanzamiento de hechizo por Comando +config.wizardry.summoned_creature_targets_whitelist=Lista blanca de objetivos de criaturas invocadas +config.wizardry.summoned_creature_targets_blacklist=Lista negra de objetivos de criaturas invocadas +config.wizardry.spell_hud_position=Posicion del HUD de hechizos +config.wizardry.cast_command_name=Nombre del Hechizo lanzado por comando +config.wizardry.discoverspell_command_name=Descubrir el nombre del hechizo lanzado por comando +config.wizardry.ally_command_name=Colocar el nombre del comando de aliado +config.wizardry.allies_command_name=Ver el nombre del comandod de aliado + +config.wizardry.mobs_immune_to_fire=Mobs Inmunes Al Fuego +config.wizardry.mobs_immune_to_ice=Mobs Inmunees Al Frio +config.wizardry.mobs_immune_to_lightning=Mobs Inmunes Al Rayo +config.wizardry.mobs_immune_to_wither=Mobs Inmunes Al Wither +config.wizardry.mobs_immune_to_poison=Mobs Inmunes Al Veneno + +config.wizardry.tower_rarity.tooltip=Rareza para las torres de magos. Numeros mayores suben la rareza. Coloque un 0 para desactivarlas. +config.wizardry.ore_dimensions.tooltip=Lista de dimensiones en las cuales la Mena de Cristal Magico aparecera. +config.wizardry.flower_dimensions.tooltip=Lista de dimensiones en las cuales apareceran flores de cristal magico. +config.wizardry.tower_dimensions.tooltip=Lista de dimensiones donde se generaran torres de magos. +config.wizardry.spell_book_drop_chance.tooltip=La probabilidad de que un mob arroje un libro de hechizos cuando muera. Mientras mas alto sea el numero, mas chance tendras. Coloca un 0 para desactivar el dropeo de libros. Coloque 200 para asegurar el dropeo 100%. +config.wizardry.generate_loot.tooltip=Si se debe generar botin del mod en cofres de mazmorras. +config.wizardry.firebomb_is_craftable.tooltip=Si las bombas de fuego son crafteables o no. +config.wizardry.poison_bomb_is_craftable.tooltip=Si las bombas de veneno son crafteables o no. +config.wizardry.smoke_bomb_is_craftable.tooltip=Si las bombas de humo son crafteables o no. +config.wizardry.use_alternate_scroll_recipe.tooltip=Si se requiere cristal magico para craftear pergaminos vacioes. Utilice esta opcion si otro mod tiene conflicto. +config.wizardry.teleport_through_unbreakable_blocks.tooltip=Si los jugadores son capaces de pasar a traves de bloques indestructibles (bedrock) usando Paso de Fase. +config.wizardry.show_summoned_creature_names.tooltip=Si mostrar los nombres de las criaturas invocadas y sus duenos sobre su cabeza. +config.wizardry.friendly_fire.tooltip=Permitir que los aliados se puedan herir con magia. +config.wizardry.telekinetic_disarmament.tooltip=Permitir que los jugadores puedan desarmar otros jugadores con el hechizo de Telequinesis. +config.wizardry.discovery_mode.tooltip=Para aquellos que le guste el misterio! Si esta en verdadero, los hechizos que no se hayan conjurado seran ilegibles. No tiene efecto en creativo. +config.wizardry.enable_shift_scrolling.tooltip=Si eres capaz de cambiar de hechizos al agacharte y usar la rueda del raton. Nota: Esta funcionalidad es del lado cliente, otros jugadores no dependen de esta, deben configurar su propia opcion. +config.wizardry.minion_revenge_targeting.tooltip=Si las criaturas invocadas atacan a su invocador si este los ataca. +config.wizardry.player_damage_scaling.tooltip=Factor de incremento de dano global para el dano hecho por jugadores, relativo a 1. +config.wizardry.npc_damage_scaling.tooltip=Factor de incremento de dano global para el dano hecho por NPCs, relativo a 1. +config.wizardry.cast_command_multiplier_limit.tooltip=Limite maximo usado con el comando /cast. Esto esta aqui para evitar que accidentalmente destruyan un mundo o servidor. +config.wizardry.summoned_creature_targets_whitelist.tooltip=Lista de nombres de entidades que los magos y criaturas invocadas pueden atacar. +config.wizardry.summoned_creature_targets_blacklist.tooltip=Lista de nombres de entidades que los magos y criaturas invocadas no pueden atacar. Si eliminas creeper hazlo bajo tu responsabilidad!! +config.wizardry.spell_hud_position.tooltip=La posicion de la interfaz de hechizos. +config.wizardry.cast_command_name.tooltip=El nombre del comando /cast. Esto es lo que escribes luego de /; por ejemplo si esto dijera 'magia', entonces el comando seria /magia. +config.wizardry.discoverspell_command_name.tooltip=El nombre del comando /discoverspell. Esto es lo que escribes luego de /; por ejemplo si esto dijera 'descubrir', entonces el comando seria /descubrir. +config.wizardry.ally_command_name.tooltip=El nombre del comando /ally. Esto es lo que escribes luego de /; por ejemplo si esto dijera 'aliado', entonces el comando seria /aliado. +config.wizardry.allies_command_name.tooltip=El nombre del comando /allies command. Esto es lo que escribes luego de /; por ejemplo si esto dijera 'aliados', entonces el comando seria /aliados. + +config.wizardry.mobs_immune_to_fire.tooltip=Lista de nombres de entidades que son inmunes al fuego, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al fuego. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). +config.wizardry.mobs_immune_to_ice.tooltip=Lista de nombres de entidades que son inmunes al frio, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al frio. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). +config.wizardry.mobs_immune_to_lightning.tooltip=Lista de nombres de entidades que son inmunes al rayo, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al rayo. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). +config.wizardry.mobs_immune_to_wither.tooltip=Lista de nombres de entidades que son inmunes al wither, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al wither. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). +config.wizardry.mobs_immune_to_poison.tooltip=Lista de nombres de entidades que son inmunes al veneno, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al veneno. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). + +wizard.debug=%1$s, %2$s, %3$s \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/lang/es_MX.lang b/src/main/resources/assets/wizardry/lang/es_MX.lang new file mode 100644 index 00000000..7608a50f --- /dev/null +++ b/src/main/resources/assets/wizardry/lang/es_MX.lang @@ -0,0 +1,736 @@ +tile.wizardry:arcane_workbench.name=Mesa de Trabajo Arcana +tile.wizardry:crystal_ore.name=Mena de Cristal Magico +tile.wizardry:petrified_stone.name=Piedra Petrificada +tile.wizardry:ice_statue.name=Estatua de Hielo +tile.wizardry:crystal_flower.name=Flor de Cristal Magico +tile.wizardry:snare.name=Trampa +tile.wizardry:transportation_stone.name=Piedra de Transportacion +tile.wizardry:spectral_block.name=Bloque Espectral +tile.wizardry:crystal_block.name=Bloque de Cristal Magico + +item.wizardry:magic_crystal.name=Cristal Magico +item.wizardry:magic_wand.name=Varita Magica +item.wizardry:apprentice_wand.name=Varita de Aprendiz +item.wizardry:advanced_wand.name=Varita Avanzada +item.wizardry:master_wand.name=Varita de Maestro +item.wizardry:spell_book.name=Libro de Hechizo + +item.wizardry:arcane_tome.name=Tomo de lo Arcano +item.wizardry:arcane_tome.desc1=Mejora cualquier %1$s +item.wizardry:arcane_tome.desc2=varita a nivel %1$s + +item.wizardry:wizard_handbook.name=El Manual del Hechizero +item.wizardry:wizard_handbook.desc=por %1$s + +item.wizardry:wand.buff=+%1$s %2$s de potencia +item.wizardry:wand.spell=Hechizo actual: %1$s +item.wizardry:wand.mana=Mana: %1$s/%2$s + +item.wizardry:wand.addally=%1$s ha sido anadido a tu lista de aliados +item.wizardry:wand.removeally=%1$s ha sido removido a tu lista de aliados + +item.wizardry:basic_fire_wand.name=Varita de Ascuas +item.wizardry:basic_ice_wand.name=Varita de Escarcha +item.wizardry:basic_lightning_wand.name=Varita de Chispas +item.wizardry:basic_necromancy_wand.name=Varita de las Sombras +item.wizardry:basic_earth_wand.name=Varita del Bosque +item.wizardry:basic_sorcery_wand.name=Varita del Misterio +item.wizardry:basic_healing_wand.name=Varita de la Curacion + +item.wizardry:apprentice_fire_wand.name=Varita del Piromano Aprendiz +item.wizardry:apprentice_ice_wand.name=Varita del Mago de Hielo Aprendiz +item.wizardry:apprentice_lightning_wand.name=Varita del Mago de Tormenta Aprendiz +item.wizardry:apprentice_necromancy_wand.name=Varita del Nigromante Aprendiz +item.wizardry:apprentice_earth_wand.name=Varita del Mago de Tierra Aprendiz +item.wizardry:apprentice_sorcery_wand.name=Varita del Hechicero Aprendiz +item.wizardry:apprentice_healing_wand.name=Varita del Sanador Aprendiz + +item.wizardry:advanced_fire_wand.name=Varita del Piromano +item.wizardry:advanced_ice_wand.name=Varita del Mago de Hielo +item.wizardry:advanced_lightning_wand.name=Varita del Mago de Tormenta +item.wizardry:advanced_necromancy_wand.name=Varita del Nigromante +item.wizardry:advanced_earth_wand.name=Varita del Mago de Tierra +item.wizardry:advanced_sorcery_wand.name=Varita del Hechicero +item.wizardry:advanced_healing_wand.name=Varita del Sanador + +item.wizardry:master_fire_wand.name=Varita del Piromano Maestro +item.wizardry:master_ice_wand.name=Varita del Mago de Hielo Maestro +item.wizardry:master_lightning_wand.name=Varita del Mago de Tormenta Maestro +item.wizardry:master_necromancy_wand.name=Varita del Nigromante Maestro +item.wizardry:master_earth_wand.name=Varita del Mago de Tierra Maestro +item.wizardry:master_sorcery_wand.name=Varita del Hechicero Maestro +item.wizardry:master_healing_wand.name=Varita del Sanador Maestro + +item.wizardry:spectral_sword.name=Espada Espectral +item.wizardry:spectral_pickaxe.name=Pico Espectral +item.wizardry:spectral_bow.name=Arco Espectral + +item.wizardry:mana_flask.name=Frasco de Mana +item.wizardry:storage_upgrade.name=Mejora de Almacenamiento para Varita +item.wizardry:siphon_upgrade.name=Mejora de Sifon para Varita +item.wizardry:condenser_upgrade.name=Mejora de Condensador para Varita +item.wizardry:range_upgrade.name=Mejora de Rango para Varita +item.wizardry:duration_upgrade.name=Mejora de Duracion para Varita +item.wizardry:cooldown_upgrade.name=Mejora de Tiempo de Reactivacion para Varita +item.wizardry:blast_upgrade.name=Mejora de Explosion para Varita +item.wizardry:attunement_upgrade.name=Mejora de Sintonizacion para Varita + +item.wizardry:flaming_axe.name=Hacha Llameante +item.wizardry:frost_axe.name=Hacha Escarchada + +item.wizardry:firebomb.name=Bomba de fuego +item.wizardry:poison_bomb.name=Bomba de veneno +item.wizardry:smoke_bomb.name=Bomba de humo + +item.wizardry:blank_scroll.name=Pergamino en blanco +item.wizardry:scroll.name=Pergamino de %1$s +item.wizardry:scroll.undiscovered.name=Pergamino "%1$s" +item.wizardry:identification_scroll.name=Pergamino de la Identificacion +item.wizardry:identification_scroll.desc1=%1$sIdentifica un libro o pergamino +item.wizardry:identification_scroll.desc2=%1$sdesconocido +item.wizardry:identification_scroll.nothing_to_identify=Nada que identificar! + +item.wizardry:armour_upgrade.name=Sello Arcano de la Proteccion +item.wizardry:armour_upgrade.desc1=%1$sMejora cualquier armadura +item.wizardry:armour_upgrade.desc2=%1$spara volverla %2$slegendaria + +item.wizardry:magic_silk.name=Seda Magica + +item.wizardry:wizard_armour.legendary=Legendario +item.wizardry:wizard_armour.buff=-%1$s %2$s costo +item.wizardry:wizard_armour.mana=Mana: %1$s/%2$s + +item.wizardry:wizard_hat.name=Sombrero de Mago +item.wizardry:wizard_robe.name=Tunica de Mago +item.wizardry:wizard_leggings.name=Pantalones de Mago +item.wizardry:wizard_boots.name=Botas de Mago + +item.wizardry:wizard_hat_fire.name=Sombrero de Piromano +item.wizardry:wizard_robe_fire.name=Tunica de Piromano +item.wizardry:wizard_leggings_fire.name=Pantalones de Piromano +item.wizardry:wizard_boots_fire.name=Botas de Piromano + +item.wizardry:wizard_hat_ice.name=Sombrero de Mago de Hielo +item.wizardry:wizard_robe_ice.name=Tunica de Mago de Hielo +item.wizardry:wizard_leggings_ice.name=Pantalones de Mago de Hielo +item.wizardry:wizard_boots_ice.name=Botas de Mago de Hielo + +item.wizardry:wizard_hat_lightning.name=Sombrero de Mago de Tormenta +item.wizardry:wizard_robe_lightning.name=Tunica de Mago de Tormenta +item.wizardry:wizard_leggings_lightning.name=Pantalones de Mago de Tormenta +item.wizardry:wizard_boots_lightning.name=Botas de Mago de Tormenta + +item.wizardry:wizard_hat_necromancy.name=Sombrero de Nigromante +item.wizardry:wizard_robe_necromancy.name=Tunica de Nigromante +item.wizardry:wizard_leggings_necromancy.name=Pantalones de Nigromante +item.wizardry:wizard_boots_necromancy.name=Botas de Nigromante + +item.wizardry:wizard_hat_earth.name=Sombrero de Mago de Tierra +item.wizardry:wizard_robe_earth.name=Tunica de Mago de Tierra +item.wizardry:wizard_leggings_earth.name=Pantalones de Mago de Tierra +item.wizardry:wizard_boots_earth.name=Botas de Mago de Tierra + +item.wizardry:wizard_hat_sorcery.name=Sombrero de Hechicero +item.wizardry:wizard_robe_sorcery.name=Tunica de Hechicero +item.wizardry:wizard_leggings_sorcery.name=Pantalones de Hechicero +item.wizardry:wizard_boots_sorcery.name=Botas de Hechicero + +item.wizardry:wizard_hat_healing.name=Sombrero de Sanador +item.wizardry:wizard_robe_healing.name=Tunica de Sanador +item.wizardry:wizard_leggings_healing.name=Pantalones de Sanador +item.wizardry:wizard_boots_healing.name=Botas de Sanador + +item.wizardry:spawn_wizard.name=Invocar Mago +item.wizardry:spawn_evil_wizard.name=Invocar Mago Malvado + +item.wizardry:spectral_helmet.name=Casco Espectral +item.wizardry:spectral_chestplate.name=Pechera Espectral +item.wizardry:spectral_leggings.name=Grebas Espectrales +item.wizardry:spectral_boots.name=Botas Espectrales + +entity.wizardry.summonedcreature.nameplate=%2$s de %1$s + +entity.wizardry.zombie_minion.name=Zombi +entity.wizardry.skeleton_minion.name=Esqueleto +entity.wizardry.spider_minion.name=Arana +entity.wizardry.blaze_minion.name=Blaze +entity.wizardry.ice_wraith.name=Espectro de Hielo +entity.wizardry.lightning_wraith.name=Espectro de Relampago +entity.wizardry.shadow_wraith.name=Espectro de las Sombras +entity.wizardry.spirit_wolf.name=Lobo Espiritual +entity.wizardry.spirit_horse.name=Caballo Espiritual +entity.wizardry.ice_giant.name=Gigante de Hielo +entity.wizardry.phoenix.name=Fenix +entity.wizardry.wizard.name=Mago +entity.wizardry.magic_slime.name=Slime Magico +entity.wizardry.silverfish_minion.name=Lepisma +entity.wizardry.storm_elemental.name=Elemental de Tormenta +entity.wizardry.evil_wizard.name=Mago Malvado +entity.wizardry.decoy.name=Senuelo + +entity.wizardry.magic_missile.name=Magia +entity.wizardry.arc.name=Magia +entity.wizardry.spark_bomb.name=Magia +entity.wizardry.ice_shard.name=Magia +entity.wizardry.firebomb.name=Magic +entity.wizardry.poison_bomb.name=Magia +entity.wizardry.force_orb.name=Magia +entity.wizardry.spark.name=Magia +entity.wizardry.darkness_orb.name=Magia +entity.wizardry.fire_sigil.name=Magia +entity.wizardry.frost_sigil.name=Magia +entity.wizardry.lightning_sigil.name=Magia +entity.wizardry.lightning_arrow.name=Magia +entity.wizardry.firebolt.name=Magia +entity.wizardry.ice_charge.name=Magia +entity.wizardry.force_arrow.name=Magia +entity.wizardry.dart.name=Magia +entity.wizardry.lightning_disc.name=Magia +entity.wizardry.thunderbolt.name=Magia +entity.wizardry.decay.name=Magia +entity.wizardry.ice_lance.name=Magia +entity.wizardry.smoke_bomb.name=Magia +entity.wizardry.ice_spike.name=Magia + +entity.wizardry.black_hole.name=Agujero Negro +entity.wizardry.shield.name=Escudo +entity.wizardry.meteor.name=Meteoro +entity.wizardry.blizzard.name=Ventisca +entity.wizardry.bubble.name=Burbuja +entity.wizardry.tornado.name=Tornado +entity.wizardry.lightning_hammer.name=Martillo Relampago +entity.wizardry.arrow_rain.name=Lluvia de Flechas +entity.wizardry.healing_aura.name=Aura Curador +entity.wizardry.forcefield.name=Campo de Fuerza +entity.wizardry.ring_of_fire.name=Anillo de Fuego +entity.wizardry.earthquake.name=Terremoto +entity.wizardry.falling_grass.name=Hierba Descendiente +entity.wizardry.hailstorm.name=Tormenta de Granizo +entity.wizardry.lightning_pulse.name=Pulso de Relampago + +item_group.wizardry=Wizardry +item_group.wizardryspells=Hechizos de Wizardry + +achievement.crystal=Un Cristral Curioso... +achievement.crystal.desc=Pica un Cristal Magico +achievement.arcane_initiate=Inicio Arcano +achievement.arcane_initiate.desc=Craftea una varita magica con una pepita de oro, un palo y un cristal magico +achievement.apprentice=Aprendiz de Mago +achievement.apprentice.desc=Usa un tomo de lo arcano para mejorar tu varita +achievement.master=Maestro Arcano +achievement.master.desc=Obten una varita de maestro +achievement.all_spells=Mago de Todos los Oficios +achievement.all_spells.desc=Lanza todos los hechizos disponibles +achievement.wizard_trade=Comercio Magico +achievement.wizard_trade.desc=Compra un objeto a un mago +achievement.buy_master_spell=El Conocimiento es Poder +achievement.buy_master_spell.wizardry:desc=Compra un hechizo maestro a un mago +achievement.freeze_blaze=Ya No Estas Tan Caliente +achievement.freeze_blaze.desc=Congela a un blaze +achievement.charge_creeper=Va a Explotar!! +achievement.charge_creeper.desc='Accidentalmente' carga un creeper +achievement.frankenstein=Frankenstein +achievement.frankenstein.desc=Convierte a un cerdo en un hombrecerdo zombi usando el hechizo de rayo +achievement.special_upgrade=Remiendo Arcano +achievement.special_upgrade.desc=Aplica una mejora a una varita +achievement.craft_flask=Es Magia, Embotellada! +achievement.craft_flask.desc=Craftea un frasco de mana +achievement.elemental=Elemental +achievement.elemental.desc=Obten una varita elemental +achievement.armour_set=Now Eres un Mago Apropiado +achievement.armour_set.desc=Craftea y equipa el set completo de armadura de mago +achievement.legendary=Legendario +achievement.legendary.desc=Obten una pieza de armadura de mago legendaria +achievement.self_destruct=Tiro por la culata +achievement.self_destruct.desc=Muere por tu propia magia +achievement.pig_tornado=No De Nuevo... +achievement.pig_tornado.desc=Monta un cerdo hacia un tornado +achievement.jam_wizard=Sesion de Interferencia +achievement.jam_wizard.desc=Usa el hechizo arcano de interferencia en un mago +achievement.slime_skeleton=Situacion Pegajosa +achievement.slime_skeleton.desc=Sumerge un esqueleto en slime +achievement.anger_wizard=Te Arrepentiras de Eso +achievement.anger_wizard.desc=Haz que un mago se enoje +achievement.defeat_evil_wizard=Justicia +achievement.defeat_evil_wizard.desc=Derrota a un mago malvado +achievement.max_out_wand=Equipada Al Maximo! +achievement.max_out_wand.desc=Aplica el maximo numero de mejoras a una varita maestra +achievement.element_master=Maestria Elemental +achievement.element_master.desc=Lanza todos los hechizos de cualquier elemento +achievement.identify_spell=Apreciacion Arcana +achievement.identify_spell.wizardry:desc=Usa un pergamino de la identificacion para identificar un libro de hechizos o pergamino + +tile.wizardry:transportation_stone.confirm=A partir de ahora retornaras a este lugar cuando lances %1$s +tile.wizardry:transportation_stone.invalid=Primero debes hacer un circulo con 8 piedras de transportacion! + +container.wizardry:arcane_workbench=Mesa de Trabajo Arcana +container.wizardry:arcane_workbench.apply=Aplicar +container.wizardry:arcane_workbench.mana=Mana: +container.wizardry:arcane_workbench.upgrades=Mejoras Aplicadas: + +tier.basic=Novato +tier.apprentice=Aprendiz +tier.advanced=Avanzado +tier.master=Maestro + +element.simple=Ninguno +element.fire=Fuego +element.ice=Hielo +element.lightning=Rayo +element.necromancy=Nigromancia +element.earth=Tierra +element.sorcery=Hechiceria +element.healing=Curacion + +element.simple.wizard=Mago +element.fire.wizard=Piromano +element.ice.wizard=Mago de Hielo +element.lightning.wizard=Mago de Tormenta +element.necromancy.wizard=Nigromante +element.earth.wizard=Mago de Tierra +element.sorcery.wizard=Hechicero +element.healing.wizard=Curador + +spelltype.attack=Ataque +spelltype.defence=Defensa +spelltype.utility=Utilidad +spelltype.minion=Secuaz + +spell.disabled=%1$s ha sido desactivado en la configuracion +spell.resist=%1$s resistio %2$s +spell.discover=Descubrio el hechizo %1$s! + +spell.wizardry:agility=Agilidad +spell.wizardry:arc=Arco Electrico +spell.wizardry:arcane_jammer=Perturbador Arcano +spell.wizardry:arrow_rain=Lluvia de Flechas +spell.wizardry:banish=Desaparecer +spell.wizardry:black_hole=Agujero Negro +spell.wizardry:blink=Parpadeo +spell.wizardry:blizzard=Ventisca +spell.wizardry:bubble=Burbuja +spell.wizardry:chain_lightning=Cadena de Rayos +spell.wizardry:clairvoyance=Clarividencia +spell.wizardry:cobwebs=Telas de Araña +spell.wizardry:conjure_armour=Conjurar Armadura +spell.wizardry:conjure_bow=Conjurar Arco +spell.wizardry:conjure_pickaxe=Conjurar Pico +spell.wizardry:conjure_sword=Conjurar Espada +spell.wizardry:cure_effects=Purificar Efectos +spell.wizardry:curse_of_soulbinding=Maldicion de Atadura al Alma +spell.wizardry:darkness_orb=Orbe de la Oscuridad +spell.wizardry:darkvision=Vision Oscura +spell.wizardry:dart=Dardo +spell.wizardry:decay=Deterioro +spell.wizardry:decoy=Senuelo +spell.wizardry:detonate=Detonar +spell.wizardry:diamondflesh=Piel de Diamante +spell.wizardry:earthquake=Terremoto +spell.wizardry:entrapment=Atrapamiento +spell.wizardry:fireball=Bola de Fuego +spell.wizardry:firebolt=Disparo de Fuego +spell.wizardry:firebomb=Bomba de Fuego +spell.wizardry:fire_resistance=Resistencia al Fuego +spell.wizardry:fire_sigil=Sigilo de Fuego +spell.wizardry:fireskin=Piel de Fuego +spell.wizardry:firestorm=Tormenta de Fuego +spell.wizardry:flame_ray=Rayo de Fuego +spell.wizardry:flaming_axe=Hacha Llameante +spell.wizardry:flaming_weapon=Arma Llameante +spell.wizardry:flight=Vuelo +spell.wizardry:font_of_mana=Fuente de Mana +spell.wizardry:font_of_vitality=Fuente de Vitalidad +spell.wizardry:force_arrow=Flecha de Fuerza +spell.wizardry:forcefield=Campo de Fuerza +spell.wizardry:force_orb=Orbe de Fuerza +spell.wizardry:forests_curse=Maldicion del Bosque +spell.wizardry:freeze=Congelar +spell.wizardry:freezing_weapon=Arma Congelante +spell.wizardry:frost_axe=Hacha Escarchada +spell.wizardry:frost_ray=Rayo de Escarcha +spell.wizardry:frost_sigil=Sigilo de Escarcha +spell.wizardry:glide=Planear +spell.wizardry:greater_fireball=Bola de Fuego Mayor +spell.wizardry:greater_heal=Curacion Mayor +spell.wizardry:group_heal=Curacion Grupal +spell.wizardry:growth_aura= Aura de Crecimiento +spell.wizardry:hailstorm=Tormenta de Granizo +spell.wizardry:heal=Curar +spell.wizardry:heal_ally=curar Aliado +spell.wizardry:healing_aura=Aura de Curacion +spell.wizardry:homing_spark=Chispa Dirigida +spell.wizardry:ice_age=Era de Hielo +spell.wizardry:ice_charge=Carga de Hielo +spell.wizardry:ice_lance=Lanza de Hielo +spell.wizardry:ice_shard=Fragmento de Hielo +spell.wizardry:ice_shroud=Velo de Hielo +spell.wizardry:ice_spikes=Pinchos de Hielo +spell.wizardry:ice_statue=Estatua de Hielo +spell.wizardry:ignite=Encender +spell.wizardry:imbue_weapon=Imbuir Arma +spell.wizardry:intimidate=Intimidar +spell.wizardry:invigorating_presence=Presencia Vigorizante +spell.wizardry:invisibility=Invisibilidad +spell.wizardry:invoke_weather=Invocar clima +spell.wizardry:ironflesh=Piel de Hierro +spell.wizardry:leap=Salto +spell.wizardry:levitation=Levitacion +spell.wizardry:life_drain=Drenaje de Vida +spell.wizardry:light=Luz +spell.wizardry:lightning_arrow=Flecha de Rayo +spell.wizardry:lightning_bolt=Disparo de Rayo +spell.wizardry:lightning_disc=Disco de Rayo +spell.wizardry:lightning_hammer=Martillo Relampago +spell.wizardry:lightning_pulse=Pulso Electrico +spell.wizardry:lightning_ray=Rayo Electrico +spell.wizardry:lightning_sigil=Sigilo Electrico +spell.wizardry:lightning_web=Red Electrica +spell.wizardry:magic_missile=Misil Magico +spell.wizardry:metamorphosis=Metamorfosis +spell.wizardry:meteor=Meteoro +spell.wizardry:mind_control=Control Mental +spell.wizardry:mind_trick=Truco Mental +spell.wizardry:none=[Espacio Vacio] +spell.wizardry:oakflesh=Piel de Roble +spell.wizardry:petrify=Petrificar +spell.wizardry:phase_step=Paso de Fase +spell.wizardry:plague_of_darkness=Plaga de la Oscuridad +spell.wizardry:pocket_furnace=Horno del Bolsillo +spell.wizardry:pocket_workbench=Mesa de Trabajo de Bolsillo +spell.wizardry:poison=Veneno +spell.wizardry:poison_bomb=Bomba de Veneno +spell.wizardry:replenish_hunger=Rellenar hambre +spell.wizardry:ring_of_fire=Anillo de Fuego +spell.wizardry:shadow_ward=Guarda de las Sombras +spell.wizardry:shield=Escudo +spell.wizardry:shockwave=Onda de Choque +spell.wizardry:silverfish_swarm=Emjambre de Lepismas +spell.wizardry:sixth_sense=Sexto Sentido +spell.wizardry:slime=Slime +spell.wizardry:smoke_bomb=Bomba de Humo +spell.wizardry:snare=Trampa +spell.wizardry:snowball=Bola de Nieve +spell.wizardry:spark_bomb=Bomba de Chispa +spell.wizardry:spectral_pathway=Camino Espectral +spell.wizardry:spider_swarm=Emjambre de Arañas +spell.wizardry:static_aura=Aura Estatica +spell.wizardry:summon_blaze=Invocar Blaze +spell.wizardry:summon_ice_giant=Invocar Gigante de Hielo +spell.wizardry:summon_ice_wraith=Invocar Espectro de Hielo +spell.wizardry:summon_iron_golem=Invocar Golem de Hierro +spell.wizardry:summon_lightning_wraith=Invocar Espectro de Rayo +spell.wizardry:summon_phoenix=Invocar Fenix +spell.wizardry:summon_shadow_wraith=Invocar Espectro de las Sombras +spell.wizardry:summon_skeleton=Invocar Esqueleto +spell.wizardry:summon_skeleton_legion=Invocar Legion de Esqueletos +spell.wizardry:summon_snow_golem=Invocar Golem de Nieve +spell.wizardry:summon_spirit_horse=Invocar Caballo Espiritual +spell.wizardry:summon_spirit_wolf=Invocar Lobo Espiritual +spell.wizardry:summon_storm_elemental=Invocar Elemental del Rayo +spell.wizardry:summon_wither_skeleton=Invocar Esqueleto del Wither +spell.wizardry:summon_zombie=Invocar Zombi +spell.wizardry:telekinesis=Telequinesis +spell.wizardry:thunderbolt=Rayo +spell.wizardry:thunderstorm=Tormenta Electrica +spell.wizardry:tornado=Tornado +spell.wizardry:transience=Transitoriedad +spell.wizardry:transportation=Transportacion +spell.wizardry:vanishing_box=Caja Desvaneciente +spell.wizardry:wall_of_frost=Pared de Escarcha +spell.wizardry:water_breathing=Respiracion Acuatica +spell.wizardry:whirlwind=Remolino de Viento +spell.wizardry:wither=Marchitar +spell.wizardry:wither_skull=Craneo de Wither + +spell.wizardry:agility.desc=Concede al mago velocidad de movimiento incrementada y un salto mas alto por 30 segundos. +spell.wizardry:arc.desc=Dispara una chispa de rayo al objetivo. +spell.wizardry:arcane_jammer.desc=No permite que el usuario use magia en los proximos 15 segundos. +spell.wizardry:arrow_rain.desc="Arqueros, disparen!" +spell.wizardry:banish.desc=Teletransporta al objetivo una posicion cercana aleatoria en contra de su voluntad. +spell.wizardry:black_hole.desc=Desgarra la realidad. +spell.wizardry:blink.desc=Teletransporta al mago a la posicion que estan apuntando. +spell.wizardry:blizzard.desc=Crea una zona de aire frio, la cual ralentiza y hiere continuamente a cualquiera en su interior. El creador del hechizo es inmune al dano pero no al efecto. +spell.wizardry:bubble.desc=Dispara un chorro de burbujas que causa que lo primero que toque flote hacia el cielo. La burbuja explota despues de un tiempo o si el objetivo es golpeado. +spell.wizardry:chain_lightning.desc=Dispara un relampago a un objetivo, el cual hace cadena con objetivos cercanos hasta dos veces. +spell.wizardry:clairvoyance.desc=Revela el camino hacia una localizacion guardada. Con este hechizo seleccionado, haga shift-clic derecho en un bloque para guardarlo. Lanza este hechizo para revelar el camino. El camino desaparecera despues de 90 segundos. +spell.wizardry:cobwebs.desc=Crea telas de arana en la direccion a la cual estas apuntando, lo cual limita la movilidad de tu objetivo. Las telas de arana despareceran en 20 segundos o si son rotas. +spell.wizardry:conjure_armour.desc=Crea Armadura Espectral alrededor del mago lo cual ofrece proteccion similar a la armadura de hierro. La armadura dura 60 segundos. El mago debe tener el espacio de armadura vacio. +spell.wizardry:conjure_bow.desc=Crea un Arco Espectral con flechas ilimitadas que dura 30 segundos. +spell.wizardry:conjure_pickaxe.desc=Crea un Pico Espectral con fuerza igual a la de un Pico de Hierro, el cual dura 30 segundos. +spell.wizardry:conjure_sword.desc=Crea una Espada Espectral con igual fuerza que una de hierro y dura 30 segundos. +spell.wizardry:cure_effects.desc=Purifica al usuario de todos los efectos de pocion, ya sean buenos o malos. +spell.wizardry:curse_of_soulbinding.desc=Provoca que el alma del objetivo esta ligada al del mago, lo que significa que todo el dano que recibe el mago lo recibe el objetivo. La maldicion dura hasta que uno de los dos muera. +spell.wizardry:darkness_orb.desc=Dispara una bala de energia oscura en la direccion que apuntes, la cual aplicar wither. +spell.wizardry:darkvision.desc=Concede vision nocturna por 45 segundos. +spell.wizardry:dart.desc=Dispara un dardo en la direccion que estas apuntando el cual hiere y debilita al objetivo. +spell.wizardry:decay.desc=Crea un pezado de deterioro en el suelo lo cual infecta y hiere a cualquier criatura que lo pise, tambien causa que estas criatura sigan esparciendo el deterioro por donde caminen. +spell.wizardry:decoy.desc=Crea un clon ilusorio del mago que atrae a los enemigos. El senuelo desaparecera en 30 segundos. +spell.wizardry:detonate.desc=Causa un explosion donde estes mirando, hiriendo a todas las criaturas cercanas - incluyendo al mago si se encuentra muy cerca. +spell.wizardry:diamondflesh.desc="Tus flechas no son nada contra mi!" +spell.wizardry:earthquake.desc=Un verdadero de Mago de Tierra puede mover montanas. +spell.wizardry:entrapment.desc=Atrpa al objetivo en una esfera de oscuridad que lo eleva y hiere continuamente. +spell.wizardry:fireball.desc=Lanza una bola de fuego en la direccion a la que apuntes. +spell.wizardry:firebolt.desc=Dispara un chorro de fuego a corta distancia en frente de ti. +spell.wizardry:firebomb.desc=Lanza una bomba de fuego, la cual detona cuando impacta quemando todo a su alrededor. +spell.wizardry:fire_resistance.desc=Concede resistencia al fuego al mago por 30 segundos. +spell.wizardry:fire_sigil.desc=Coloca una trampa de fuego que quema y hiere a la criatura que la pise. +spell.wizardry:fireskin.desc=Envuelve al mago en fuego por 30 segundos, provocando que cualquier que lo toque se queme. +spell.wizardry:firestorm.desc="Yo soy el dragon." +spell.wizardry:flame_ray.desc=Crea una corriente de llamas en la direccion a la que apuntas, la cual quema todo a su paso. +spell.wizardry:flaming_axe.desc=Crea una Hacha Llameante que quema a todos los enemigos que golpees. Dura 30 segundos. +spell.wizardry:flaming_weapon.desc=Imbuye con llamas la primera arma en el inventario del mago, la magia de deshace despues de 45 segundos. +spell.wizardry:flight.desc=Vuela como un aguila. +spell.wizardry:font_of_mana.desc="Fuimos llenados con una intensa energia magica que parecia emanar del centro del..." - Extraido del diario de un mago olvidado; el resto de la pagina esta quemada. +spell.wizardry:font_of_vitality.desc=Se siente increible. +spell.wizardry:force_arrow.desc=Dispara una flecha de fuerza en la direccion que apuntes. +spell.wizardry:forcefield.desc=Crea un campo de fuerza alrededor del mago que repele criaturas y proyectiles. +spell.wizardry:force_orb.desc=Lanza una esfera de fuerza que hiere y empuja criaturas cuando impacta. +spell.wizardry:forests_curse.desc="Como te atreves a entrar en mi bosque!" +spell.wizardry:freeze.desc=Congela al objetivo por 10 segundos. Tambien congela el agua y crea nieve en el suelo. +spell.wizardry:freezing_weapon.desc=Imbuye el poder del frio a la primera arma en el inventario del mago, provocando que el arma congela a sus objetivos. La magia deshace despues de 45 segundos. +spell.wizardry:frost_axe.desc=Crea un Hacha Escarchada la cual congela los enemigos que golpees. Dura 30 segundos. +spell.wizardry:frost_ray.desc=Crea un corriente de hielo en la direccion que apuntes la cual ralentiza y hiere continuamente al objetivo. +spell.wizardry:frost_sigil.desc=Coloca un trampa de hielo en el suelo el cual hiere y congela al cualquiera que la pise. +spell.wizardry:glide.desc=Permite que el mago planee en el aire. Debe mantenerse el boton presionado. +spell.wizardry:greater_fireball.desc=Lanza una bola de fuego de mayor tamano. +spell.wizardry:greater_heal.desc=Cura 4 corazones del mago. +spell.wizardry:group_heal.desc=Cura 3 corazones al mago, a aliados cercanos y a criaturas invocadas. +spell.wizardry:growth_aura.desc=Crece todos los cultivos cercanos al mago. Tambien hace crecer flores y hierba alta. +spell.wizardry:hailstorm.desc=Fue durante el Gran Invierno de la 3era Edad que los Magos de Hielo descubrieron su verdadero potencial. +spell.wizardry:heal.desc=Cura 2 corazones del usuario. +spell.wizardry:heal_ally.desc=Cura 2.5 corazones al objetivo. +spell.wizardry:healing_aura.desc=Crea una zona de energia curadora que regenera la salud de todos los alidados cercanos. Los No-_muertos dentro reciben dano. +spell.wizardry:homing_spark.desc=Crea una chispa flotante que persigue enemigos. +spell.wizardry:ice_age.desc="Seras congelado por toda la eternidad!" +spell.wizardry:ice_charge.desc=Lanza una carga de hielo que explota cuando impacta, congelando todas las criaturas y soltando fragmentos en todas las direcciones. +spell.wizardry:ice_lance.desc=Dispara una gran lanza de hielo en la direccion a la que estas apuntando, la cual atraviesa los objetivos hieriendo y congelandolos. +spell.wizardry:ice_shard.desc=Dispara un fragemento de hielo que hace dano y ralentiza +spell.wizardry:ice_shroud.desc=Cubre al mago con hielo, lo que ocasiona que cualquier que lo ataque sea congelado. +spell.wizardry:ice_spikes.desc=Causa que pinchos de hielo crezcan desde el suelo hiriendo a los enemigos. +spell.wizardry:ice_statue.desc=Congela al objetivo durante 20 segundos. El objetivo no se puede mover ni atacar pero tambien es inmune al dano. +spell.wizardry:ignite.desc=Quema al objetivo. Tambien funciona como un mechero. +spell.wizardry:imbue_weapon.desc=Imbuye la primera arma en el inventario con magia, haciendola mas efectiva. La magia se deshace despues de 45 segundos. +spell.wizardry:intimidate.desc=Emite un grunido intimidante el cual provoca que las criaturas espacen. +spell.wizardry:invigorating_presence.desc=Concede al mago y a los aliados cercanos fuerza incrementada por 45 segundos. +spell.wizardry:invisibility.desc=Le otorga invisibilidad al mago por 30 segundos. +spell.wizardry:invoke_weather.desc=Cambia el clima del mundo. +spell.wizardry:ironflesh.desc=Mejora grandemente la resistencia del mago por 30 segundos. +spell.wizardry:leap.desc=Causa que el mago salte alto y se mueve levemente hacia adelante. +spell.wizardry:levitation.desc=Levanta al mago hacia el cielo mientras el boton siga presionado. Si es usando antes de golpear el suelo, anula el dano por caida. +spell.wizardry:life_drain.desc=Crea una correinte de energia oscura que drena la vida de tu objetivo y te cura. +spell.wizardry:light.desc=Crea una esfera de luz que alumbra el area. Dura 30 segundos. +spell.wizardry:lightning_arrow.desc=Lanza una flecha electrificada en la direccion que apuntes. +spell.wizardry:lightning_bolt.desc=Causa que un trueno caiga en la direccion que apuntes. +spell.wizardry:lightning_disc.desc=Envia un disco electrico en la direccion que apuntes, el cual busca objetivos. +spell.wizardry:lightning_hammer.desc="Te golpeare con la ira de los cielos!" +spell.wizardry:lightning_pulse.desc=Carga el suelo cerca del mago con corriente electrica, hiriendo y repeliendo criaturas cercanas. +spell.wizardry:lightning_ray.desc=Crea una corriente de energia electrica que hiere a tus objetivos continuamente. +spell.wizardry:lightning_sigil.desc=Coloca una trampa electrificada que electrocuta a la criatura que la pise. +spell.wizardry:lightning_web.desc="Concentrare. Canaliza la tormenta en tu mente a traves de tu varita y liberala." +spell.wizardry:magic_missile.desc=Dispara una bala de energia magica. +spell.wizardry:metamorphosis.desc=Cambia la forma del objetivo. Solo funciona en algunas criaturas. +spell.wizardry:meteor.desc=Algunos magos solo quieren ver el mundo arder... +spell.wizardry:mind_control.desc=Toma control de la mente del objetivo por 30 segundos, provocando que cambie de bando y peleen a tu favor. No funciona con criaturas de voluntad muy fuerte. +spell.wizardry:mind_trick.desc=Confunde y desorienta al objetivo por 15 segundos, volviendolo incapaz de atacar. El efecto se desactiva si el objetivo recibe dano. +spell.wizardry:none.desc=Para obtener un libro de hechizo con el comando /give, usa la metadata: /give [player] wizardry:spell_book 1 [spell id] (_si encontraste este libro en un cofre significa que otro mod esta alterando las cosas). +spell.wizardry:oakflesh.desc=Mejora la resistencia del amgo durante 30 segundos. +spell.wizardry:petrify.desc=Convierte al objetivo en piedra hasta que se libere, con un chance de liberarse cuando se pone de noche. El objetivo no se puede mover ni atacar y no puede ser atacado. +spell.wizardry:phase_step.desc=Transporta al mago a traves de una pared de 1 bloque de grosor. El rango mejora el grosor por el cual te puedes transportar. +spell.wizardry:plague_of_darkness.desc=La Oscuridad los consumira a todos... +spell.wizardry:pocket_furnace.desc=Cocina 5 objetos en el inventario. Los objetos en la barra seran cocinados primero. +spell.wizardry:pocket_workbench.desc=Permite al mago craftear objetos. +spell.wizardry:poison.desc=Dispara veneno en la direccion que apuntes. +spell.wizardry:poison_bomb.desc=Lanza una bomba de veneno, la cual detona esparciendo mas veneno. +spell.wizardry:replenish_hunger.desc=Rellena 6 puntos de hambre del mago. +spell.wizardry:ring_of_fire.desc=Crea un anillo de fuego alrededor del mago, hiriendo y quemando a los objetivos cercanos. +spell.wizardry:shadow_ward.desc=Crea una pared de oscurdiad en frente del mago lo cual hace que la mitad del dano recibido sea aplicado al atacante. +spell.wizardry:shield.desc=Crea una barrera protectora que bloquea proyectiles y magia. Tambien concede al mago un efecto debil de resistencia. +spell.wizardry:shockwave.desc=Boom. +spell.wizardry:silverfish_swarm.desc="Ahhhh! Se estan multiplicando!!" +spell.wizardry:sixth_sense.desc=Le permite al mago sentir las criaturas cercanas a el, incluso a traves de paredes, durante 20 segundos. +spell.wizardry:slime.desc=Envuelve al objetivo en slime lo cual ralentiza y hiere continuamente. El slime explota despues de 10 segundos. +spell.wizardry:smoke_bomb.desc=Lanza una bomba de humo la cual explota cuando impacta. Creando una nube de humo y dandole ceguera a las criaturas en el area de impacto. +spell.wizardry:snare.desc=Coloca un trampa en el suelo que hiere y ralentiza al que la pise. +spell.wizardry:snowball.desc=Lanza una bola de nieve. +spell.wizardry:spark_bomb.desc=Lanza una bomba electrica que electrocuta a los objetivos cerca de su zona de impacto. +spell.wizardry:spectral_pathway.desc=Crea un puente magico indestructible al frente del mago que se extiende a 15 bloques. El puente desaperece luego de 60 segundos. +spell.wizardry:spider_swarm.desc=Invoca un emjambre de aranas venenosas. Desapareceran despues de 3o segundos o si son eliminadas. +spell.wizardry:static_aura.desc=Rodea al mago de electricidad durante 30 segundos, disparando chispa de rayo a cualquiera que lo golpee. +spell.wizardry:summon_blaze.desc=Invoca un Blaze que pelea por ti. El blaze desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_ice_giant.desc="Smash them!" +spell.wizardry:summon_ice_wraith.desc=Invoca un Espectro de Hielo que pelea por ti. El Espectro de Hielo desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_iron_golem.desc=Autómata autónomo automatizado automático. +spell.wizardry:summon_lightning_wraith.desc=Invoca un Espectro de Rayo que pelea por ti. El Espectro de Rayo desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_phoenix.desc=Desde las cenizas... +spell.wizardry:summon_shadow_wraith.desc=Invoca un Espectro de las Sombras que pelea por ti. +spell.wizardry:summon_skeleton.desc=Invoca un Esqueleto que pelea por ti. El esqueleto desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_skeleton_legion.desc="Levantate, Ejercito No-_muerto!" +spell.wizardry:summon_snow_golem.desc=Crea un Golem de Nieve que pelea por ti. Dura hasta que el golem muera. +spell.wizardry:summon_spirit_horse.desc=Invoca un Caballo Espectral para que lo montes. El caballo desparecera despues de que dure mucho tiempo sin ser montado o hagas shift-clic derecho con cualquier varita. +spell.wizardry:summon_spirit_wolf.desc=Invoca un Lobo Espiritual que pelea por ti. El lobo solo desparecera si es matado o haces shift-clic derecho con cualquier varita. +spell.wizardry:summon_storm_elemental.desc="Elemental de Rayo: Una manifestacion antigua de los elementos, difícilmente puede contener la energía que se agita dentro de el." - Guia del Mago sobre Entidades Arcanas, Volumen I_i +spell.wizardry:summon_wither_skeleton.desc=Invoca un Esqueleto del Wither que pelea por ti. El esqueleto del wither desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:summon_zombie.desc=Invoca un Zombi que pelea por ti. El zombi desparecera despues de 30 segundos o si es derrotado. +spell.wizardry:telekinesis.desc=Mueve un item o un objeto pequeno hacia ti si haces clic derecho sobre el bloque. Tambien puede desarmar jugadores. +spell.wizardry:thunderbolt.desc=Dispara una bala de trueno que empuja los enemigos. +spell.wizardry:thunderstorm.desc="Mwahahahahahaha!" +spell.wizardry:tornado.desc=Libera un tornado en la direccion que mires, el cual atrae y levanta a todos las criaturas en su paso. +spell.wizardry:transience.desc=Hace que el mago transcienda, volviendo inmune a todo dano pero volviendo incapaz de atacar, interactuar o romper bloques +spell.wizardry:transportation.desc=Teletransporta al mago a su circulo de piedra. Para guardar un circulo de piedra haz clic derecho con el hechizo seleccionado. +spell.wizardry:vanishing_box.desc=Le permite al mago accesar a su cofre de Ender. +spell.wizardry:wall_of_frost.desc=El invierno en la punta de tus dedos. +spell.wizardry:water_breathing.desc=Le permite al mago respirar debajo del agua durante 60 segundos. +spell.wizardry:whirlwind.desc=Causa que el objetivo sea soplado lejos de ti a gran velocidad. +spell.wizardry:wither.desc=Dispara un rayo de oscuridad que aplica wither a todo lo que toque. +spell.wizardry:wither_skull.desc=Lanza una Cabeza de Wither en la direccion que apuntes. + +spell.wizardry:invoke_weather.sun=La lluvia empieza a parar... +spell.wizardry:invoke_weather.rain=El cielo se abre... +spell.wizardry:transportation.missing=Tu circulo de piedra no se encuentra o esta siendo obstruido... +spell.wizardry:transportation.undefined=Debes guardar un circulo de piedra primero! +spell.wizardry:transportation.wrongdimension=Tu circulo de piedra se encuentra en otra dimension... +spell.wizardry:clairvoyance.searching=Buscando... +spell.wizardry:clairvoyance.confirm=El camino revelado al lanzar %1$s ahora te llevara a este punto +spell.wizardry:clairvoyance.outofrange=Tu punto guardado esta muy lejos o es inaccesible... +spell.wizardry:clairvoyance.undefined=Debes guardar una localizacion primero! +spell.wizardry:clairvoyance.wrongdimension=Tu localizacion guardada esta en otra dimension... + +potion.wizardry:frost=Congelacion +potion.wizardry:fireskin=Piel de Fuego +potion.wizardry:ice_shroud=Manto de Hielo +potion.wizardry:static_aura=Aura Estatica +potion.wizardry:transience=Transitoriedad +potion.wizardry:decay=Deterioro +potion.wizardry:sixth_sense=Sexto Sentido +potion.wizardry:arcane_jammer=Perturbador Arcano +potion.wizardry:mind_trick=Truco Mental +potion.wizardry:mind_control=Control Mental +potion.wizardry:font_of_mana=Fuente de Mana +potion.wizardry:fear=Miedo + +enchantment.wizardry:magic_sword=Impregnacion +enchantment.wizardry:magic_bow=Impregnacion +enchantment.wizardry:flaming_weapon=Impregnacion de Fuego +enchantment.wizardry:freezing_weapon=Impregnacion de Fuego + +key.categories.wizardry=Wizardry + +key.wizardry:next_spell=Hechizo siguiente +key.wizardry:previous_spell=Hechizo anterior + +death.attack.wizardry_magic=%1$s fue matado por %2$s usando magia +death.attack.indirect_wizardry_magic=%1$s fue matado por %2$s usando magia + +commands.wizardry:cast.usage=/%1$s [player] [damage multiplier] [range multiplier] [duration multiplier] [blast multiplier] +commands.wizardry:cast.success=Lanzado con exito %1$s +commands.wizardry:cast.success_continuous=Lanzado con exito %1$s; repite el comando para parar +commands.wizardry:cast.success_remote=Lanzado con exito %1$s como %2$s +commands.wizardry:cast.success_remote_continuous=Lanzado con exito %1$s como %2$s; repite el comando para parar +commands.wizardry:cast.fail=Imposible lanzar %1$s +commands.wizardry:cast.not_found=No hay ningun hechizo con ID %1$s + +commands.wizardry:ally.usage=/%1$s [player] +commands.wizardry:ally.addally=%1$s ha sido anadido a la lista de aliados de %2$s +commands.wizardry:ally.removeally=%1$s ha sido removido de la lista de aliados de %2$s +commands.wizardry:ally.self=Los jugadores no pueden ser aliados de si mismos! +commands.wizardry:ally.permission=No tienes permiso para cambiar los aliados de otros jugadores + +commands.wizardry:allies.usage=/%1$s [player] +commands.wizardry:allies.list=Jugadores que son aliados: %1$s +commands.wizardry:allies.list_other=Jugadores que son aliados de %1$s: %2$s +commands.wizardry:allies.permission=No tienes permiso para ver los aliados de otros jugadores +commands.wizardry:allies.none=Ninguno + +commands.wizardry:discoverspell.usage=/%1$s [player] +commands.wizardry:discoverspell.not_found=There is no such spell with ID %1$s +commands.wizardry:discoverspell.clear=Cleared all spell discovery data for %1$s +commands.wizardry:discoverspell.all=Added all spells to %1$s's spell discovery data +commands.wizardry:discoverspell.addspell=Added %1$s to %2$s's spell discovery data +commands.wizardry:discoverspell.removespell=Removed %1$s from %2$s's spell discovery data + +config.wizardry.title.general=Mod Options + +config.wizardry.category.spells=Configurar Hechizos +config.wizardry.category.spells.tooltip=Seleccionar que hechizos estan activados +config.wizardry.title.spells=Configuracion de Hechizos +config.wizardry.subtitle.spells=Establece un hechizo en falso para desactivarlo. + +config.wizardry.category.resistances=Configurar Resistencias +config.wizardry.category.resistances.tooltip=Configura cuales mobs son inmunes a los tipos de magia +config.wizardry.title.resistances=Configuracion de Resistencias +config.wizardry.subtitle.resistances=Ve las descripciones de opciones individuales para mas detalles. + +config.wizardry.category.ids=Configurar IDs +config.wizardry.category.ids.tooltip=Cambiar los IDs usados por Wizardry +config.wizardry.title.ids=Configuracion de IDs +config.wizardry.subtitle.ids=Cambia estos IDs si tienen conflicto con otro mod. + +config.wizardry.tower_rarity=Rareza de Torres +config.wizardry.ore_dimensions=Dimensiones de Mena +config.wizardry.flower_dimensions=Dimensiones de Flores +config.wizardry.tower_dimensions=Dimensiones de Torres +config.wizardry.spell_book_drop_chance=Oportunidad de Dropeo de Libro de Hechizo +config.wizardry.generate_loot=Generar Botin +config.wizardry.firebomb_is_craftable=Bomba de Fuego es crafteable +config.wizardry.poison_bomb_is_craftable=Bomba de Veneno es crafteable +config.wizardry.smoke_bomb_is_craftable=Bomba de Humo es crafteable +config.wizardry.use_alternate_scroll_recipe=Usa la receta alternativa de pergamino +config.wizardry.teleport_through_unbreakable_blocks=Teletransportarte a traves de bloques indestructibles +config.wizardry.show_summoned_creature_names=Mostrar los nombres de las criaturas invocadas +config.wizardry.friendly_fire=Fuego Amigo +config.wizardry.telekinetic_disarmament=Desarme Telequinetico +config.wizardry.discovery_mode=Modo Descubrir +config.wizardry.enable_shift_scrolling=Permitir shift-rueda del raton para cambiar de hechizo +config.wizardry.minion_revenge_targeting=Enfoque de venganza de minion +config.wizardry.player_damage_scaling=Factor de escala de dano del Jugador +config.wizardry.npc_damage_scaling=Factor de escala de dano de NPC +config.wizardry.cast_command_multiplier_limit=Limite del Multiplicador de lanzamiento de hechizo por Comando +config.wizardry.summoned_creature_targets_whitelist=Lista blanca de objetivos de criaturas invocadas +config.wizardry.summoned_creature_targets_blacklist=Lista negra de objetivos de criaturas invocadas +config.wizardry.spell_hud_position=Posicion del HUD de hechizos +config.wizardry.cast_command_name=Nombre del Hechizo lanzado por comando +config.wizardry.discoverspell_command_name=Descubrir el nombre del hechizo lanzado por comando +config.wizardry.ally_command_name=Colocar el nombre del comando de aliado +config.wizardry.allies_command_name=Ver el nombre del comandod de aliado + +config.wizardry.mobs_immune_to_fire=Mobs Inmunes Al Fuego +config.wizardry.mobs_immune_to_ice=Mobs Inmunees Al Frio +config.wizardry.mobs_immune_to_lightning=Mobs Inmunes Al Rayo +config.wizardry.mobs_immune_to_wither=Mobs Inmunes Al Wither +config.wizardry.mobs_immune_to_poison=Mobs Inmunes Al Veneno + +config.wizardry.tower_rarity.tooltip=Rareza para las torres de magos. Numeros mayores suben la rareza. Coloque un 0 para desactivarlas. +config.wizardry.ore_dimensions.tooltip=Lista de dimensiones en las cuales la Mena de Cristal Magico aparecera. +config.wizardry.flower_dimensions.tooltip=Lista de dimensiones en las cuales apareceran flores de cristal magico. +config.wizardry.tower_dimensions.tooltip=Lista de dimensiones donde se generaran torres de magos. +config.wizardry.spell_book_drop_chance.tooltip=La probabilidad de que un mob arroje un libro de hechizos cuando muera. Mientras mas alto sea el numero, mas chance tendras. Coloca un 0 para desactivar el dropeo de libros. Coloque 200 para asegurar el dropeo 100%. +config.wizardry.generate_loot.tooltip=Si se debe generar botin del mod en cofres de mazmorras. +config.wizardry.firebomb_is_craftable.tooltip=Si las bombas de fuego son crafteables o no. +config.wizardry.poison_bomb_is_craftable.tooltip=Si las bombas de veneno son crafteables o no. +config.wizardry.smoke_bomb_is_craftable.tooltip=Si las bombas de humo son crafteables o no. +config.wizardry.use_alternate_scroll_recipe.tooltip=Si se requiere cristal magico para craftear pergaminos vacioes. Utilice esta opcion si otro mod tiene conflicto. +config.wizardry.teleport_through_unbreakable_blocks.tooltip=Si los jugadores son capaces de pasar a traves de bloques indestructibles (bedrock) usando Paso de Fase. +config.wizardry.show_summoned_creature_names.tooltip=Si mostrar los nombres de las criaturas invocadas y sus duenos sobre su cabeza. +config.wizardry.friendly_fire.tooltip=Permitir que los aliados se puedan herir con magia. +config.wizardry.telekinetic_disarmament.tooltip=Permitir que los jugadores puedan desarmar otros jugadores con el hechizo de Telequinesis. +config.wizardry.discovery_mode.tooltip=Para aquellos que le guste el misterio! Si esta en verdadero, los hechizos que no se hayan conjurado seran ilegibles. No tiene efecto en creativo. +config.wizardry.enable_shift_scrolling.tooltip=Si eres capaz de cambiar de hechizos al agacharte y usar la rueda del raton. Nota: Esta funcionalidad es del lado cliente, otros jugadores no dependen de esta, deben configurar su propia opcion. +config.wizardry.minion_revenge_targeting.tooltip=Si las criaturas invocadas atacan a su invocador si este los ataca. +config.wizardry.player_damage_scaling.tooltip=Factor de incremento de dano global para el dano hecho por jugadores, relativo a 1. +config.wizardry.npc_damage_scaling.tooltip=Factor de incremento de dano global para el dano hecho por NPCs, relativo a 1. +config.wizardry.cast_command_multiplier_limit.tooltip=Limite maximo usado con el comando /cast. Esto esta aqui para evitar que accidentalmente destruyan un mundo o servidor. +config.wizardry.summoned_creature_targets_whitelist.tooltip=Lista de nombres de entidades que los magos y criaturas invocadas pueden atacar. +config.wizardry.summoned_creature_targets_blacklist.tooltip=Lista de nombres de entidades que los magos y criaturas invocadas no pueden atacar. Si eliminas creeper hazlo bajo tu responsabilidad!! +config.wizardry.spell_hud_position.tooltip=La posicion de la interfaz de hechizos. +config.wizardry.cast_command_name.tooltip=El nombre del comando /cast. Esto es lo que escribes luego de /; por ejemplo si esto dijera 'magia', entonces el comando seria /magia. +config.wizardry.discoverspell_command_name.tooltip=El nombre del comando /discoverspell. Esto es lo que escribes luego de /; por ejemplo si esto dijera 'descubrir', entonces el comando seria /descubrir. +config.wizardry.ally_command_name.tooltip=El nombre del comando /ally. Esto es lo que escribes luego de /; por ejemplo si esto dijera 'aliado', entonces el comando seria /aliado. +config.wizardry.allies_command_name.tooltip=El nombre del comando /allies command. Esto es lo que escribes luego de /; por ejemplo si esto dijera 'aliados', entonces el comando seria /aliados. + +config.wizardry.mobs_immune_to_fire.tooltip=Lista de nombres de entidades que son inmunes al fuego, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al fuego. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). +config.wizardry.mobs_immune_to_ice.tooltip=Lista de nombres de entidades que son inmunes al frio, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al frio. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). +config.wizardry.mobs_immune_to_lightning.tooltip=Lista de nombres de entidades que son inmunes al rayo, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al rayo. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). +config.wizardry.mobs_immune_to_wither.tooltip=Lista de nombres de entidades que son inmunes al wither, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al wither. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). +config.wizardry.mobs_immune_to_poison.tooltip=Lista de nombres de entidades que son inmunes al veneno, a parte de los que estan por defecto. Agrega criaturas de otros mods si quieres que sean inmunes al veneno. Los nombres de la entidades no llevan mayusculas. Para entidades de mods, usa el ID del mod como prefijo (e.g. wizardry:_mago). + +wizard.debug=%1$s, %2$s, %3$s \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/lang/ru_RU.lang b/src/main/resources/assets/wizardry/lang/ru_RU.lang new file mode 100644 index 00000000..3bd59b0c --- /dev/null +++ b/src/main/resources/assets/wizardry/lang/ru_RU.lang @@ -0,0 +1,519 @@ +tile.wizardry:arcane_workbench.name=ЧародейÑкий Стол +tile.wizardry:crystal_ore.name=КриÑÑ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ð ÑƒÐ´Ð° +tile.wizardry:petrified_stone.name=Окаменелый Камень +tile.wizardry:ice_statue.name=ЛедÑÐ½Ð°Ñ Ð¡Ñ‚Ð°Ñ‚ÑƒÑ +tile.wizardry:crystal_flower.name=КриÑтальный Цветок +tile.wizardry:snare.name=Ловушка +tile.wizardry:transportation_stone.name=Камень ТранÑпортировки +tile.wizardry:spectral_block.name=Спектральный Блок +tile.wizardry:crystal_block.name=КриÑтальный Блок + +item.wizardry:magic_crystal.name=МагичеÑкий КриÑталл +item.wizardry:magic_wand.name=Волшебный Жезл +item.wizardry:apprentice_wand.name=Жезл Ученика +item.wizardry:advanced_wand.name=Продвинутый Жезл +item.wizardry:master_wand.name=Жезл МаÑтера +item.wizardry:spell_book.name=Книга Заклинаний + +item.wizardry:arcane_tome.name=Фолиант Ðрканы +item.wizardry:arcane_tome.desc1=Улучшает любые %1$s +item.wizardry:arcane_tome.desc2=жезл %1$s уровень + +item.wizardry:wizard_handbook.name=Книга Волшебника +item.wizardry:wizard_handbook.desc=от %1$s + +item.wizardry:wand.buff=+%1$s %2$s ÑффективноÑть +item.wizardry:wand.spell=Текущее Заклинание: %1$s +item.wizardry:wand.mana=Мана: %1$s/%2$s + +item.wizardry:basic_fire_wand.name=Жезл ÐžÐ³Ð½Ñ +item.wizardry:basic_ice_wand.name=Жезл Мороза +item.wizardry:basic_lightning_wand.name=Жезл ИÑкр +item.wizardry:basic_necromancy_wand.name=Жезл Теней +item.wizardry:basic_earth_wand.name=Жезл ЛеÑа +item.wizardry:basic_sorcery_wand.name=Жезл Тайн +item.wizardry:basic_healing_wand.name=Жезл Ð›ÐµÑ‡ÐµÐ½Ð¸Ñ + +item.wizardry:apprentice_fire_wand.name=Жезл Ученика Пироманта +item.wizardry:apprentice_ice_wand.name=Жезл Ученика ЛедÑного Мага +item.wizardry:apprentice_lightning_wand.name=Жезл Ученика Штормового Мага +item.wizardry:apprentice_necromancy_wand.name=Жезл Ученика Ðекроманта +item.wizardry:apprentice_earth_wand.name=Жезл Ученика ЗемлÑного Мага +item.wizardry:apprentice_sorcery_wand.name=Жезл Ученика Колдуна +item.wizardry:apprentice_healing_wand.name=Жезл Ученика Ð¦ÐµÐ»Ð¸Ñ‚ÐµÐ»Ñ + +item.wizardry:advanced_fire_wand.name=Жезл Пироманта +item.wizardry:advanced_ice_wand.name=Жезл ЛедÑного Мага +item.wizardry:advanced_lightning_wand.name=Жезл Штормового Мага +item.wizardry:advanced_necromancy_wand.name=Жезл Ðекроманта +item.wizardry:advanced_earth_wand.name=Жезл ЗемлÑного Мага +item.wizardry:advanced_sorcery_wand.name=Жезл Колдуна +item.wizardry:advanced_healing_wand.name=Жезл Ð¦ÐµÐ»Ð¸Ñ‚ÐµÐ»Ñ + +item.wizardry:master_fire_wand.name=Жезл МаÑтера Пироманта +item.wizardry:master_ice_wand.name=Жезл МаÑтера ЛедÑного Мага +item.wizardry:master_lightning_wand.name=Жезл МаÑтера Штормового Мага +item.wizardry:master_necromancy_wand.name=Жезл МаÑтера Ðекроманта +item.wizardry:master_earth_wand.name=Жезл МаÑтера ЗемлÑного Мага +item.wizardry:master_sorcery_wand.name=Жезл МаÑтера Колдуна +item.wizardry:master_healing_wand.name=Жезл МаÑтера Ð¦ÐµÐ»Ð¸Ñ‚ÐµÐ»Ñ + +item.wizardry:spectral_sword.name=Спектральный Меч +item.wizardry:spectral_pickaxe.name=Ð¡Ð¿ÐµÐºÑ‚Ñ€Ð°Ð»ÑŒÐ½Ð°Ñ ÐšÐ¸Ñ€ÐºÐ° +item.wizardry:spectral_bow.name=Спектральный Лук + +item.wizardry:mana_flask.name=Бутылка Маны +item.wizardry:storage_upgrade.name=Улучшение Хранилища Жезла +item.wizardry:siphon_upgrade.name=Улучшение Сифона Жезла +item.wizardry:condenser_upgrade.name=Улучшение КонденÑатора Жезла +item.wizardry:range_upgrade.name=Улучшение РадиуÑа Жезла +item.wizardry:duration_upgrade.name=Улучшение ДлительноÑти Жезла +item.wizardry:cooldown_upgrade.name=Улучшение Кулдауна Жезла +item.wizardry:blast_upgrade.name=Улучшение ÐžÐ±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð–ÐµÐ·Ð»Ð° + +item.wizardry:flaming_axe.name=Огненный Топор +item.wizardry:frost_axe.name=ЛедÑной Топор + +item.wizardry:firebomb.name=ÐžÐ³Ð½ÐµÐ½Ð½Ð°Ñ Ð‘Ð¾Ð¼Ð±Ð° +item.wizardry:poison_bomb.name=Ð¯Ð´Ð¾Ð²Ð¸Ñ‚Ð°Ñ Ð‘Ð¾Ð¼Ð±Ð° + +item.wizardry:blank_scroll.name=ПуÑтой Свиток +item.wizardry:scroll.name=Свиток %1$s + +item.wizardry:armour_upgrade.name=Печать МагичеÑкой Защиты +item.wizardry:armour_upgrade.desc1=%1$sУлучшает Любые ОдеÑÐ½Ð¸Ñ ÐœÐ°Ð³Ð° +item.wizardry:armour_upgrade.desc2=%1$sÑделать Ñто %2$sлегендарным + +item.wizardry:magic_silk.name=МагичеÑкий Шёлк + +item.wizardry:wizard_armour.legendary=Легендарный +item.wizardry:wizard_armour.buff=-%1$s %2$s ÑтоимоÑть +item.wizardry:wizard_armour.mana=Мана: %1$s/%2$s + +item.wizardry:wizard_hat.name=ШлÑпа Волшебника +item.wizardry:wizard_robe.name=Роба Волшебника +item.wizardry:wizard_leggings.name=Поножи Волшебника +item.wizardry:wizard_boots.name=Ботинки Волшебника + +item.wizardry:wizard_hat_fire.name=ШлÑпа Пироманта +item.wizardry:wizard_robe_fire.name=Роба Пироманта +item.wizardry:wizard_leggings_fire.name=Поножи Пироманта +item.wizardry:wizard_boots_fire.name=Ботинки Пироманта + +item.wizardry:wizard_hat_ice.name=ШлÑпа ЛедÑного Мага +item.wizardry:wizard_robe_ice.name=Роба ЛедÑного Мага +item.wizardry:wizard_leggings_ice.name=Поножи ЛедÑного Мага +item.wizardry:wizard_boots_ice.name=Ботинки ЛедÑного Мага + +item.wizardry:wizard_hat_lightning.name=ШлÑпа Штормового Мага +item.wizardry:wizard_robe_lightning.name=Роба Штормового Мага +item.wizardry:wizard_leggings_lightning.name=Поножи Штормового Мага +item.wizardry:wizard_boots_lightning.name=Ботинки Штормового Мага + +item.wizardry:wizard_hat_necromancy.name=ШлÑпа Ðекроманта +item.wizardry:wizard_robe_necromancy.name=Роба Ðекроманта +item.wizardry:wizard_leggings_necromancy.name=Поножи Ðекроманта +item.wizardry:wizard_boots_necromancy.name=Ботинки Ðекроманта + +item.wizardry:wizard_hat_earth.name=ШлÑпа ЗемлÑного Мага +item.wizardry:wizard_robe_earth.name=Роба ЗемлÑного Мага +item.wizardry:wizard_leggings_earth.name=Поножи ЗемлÑного Мага +item.wizardry:wizard_boots_earth.name=Ботинки ЗемлÑного Мага + +item.wizardry:wizard_hat_sorcery.name=ШлÑпа Колдуна +item.wizardry:wizard_robe_sorcery.name=Роба Колдуна +item.wizardry:wizard_leggings_sorcery.name=Поножи Колдуна +item.wizardry:wizard_boots_sorcery.name=Ботинки Колдуна + +item.wizardry:wizard_hat_healing.name=ШлÑпа Ð¦ÐµÐ»Ð¸Ñ‚ÐµÐ»Ñ +item.wizardry:wizard_robe_healing.name=Роба Ð¦ÐµÐ»Ð¸Ñ‚ÐµÐ»Ñ +item.wizardry:wizard_leggings_healing.name=Поножи Ð¦ÐµÐ»Ð¸Ñ‚ÐµÐ»Ñ +item.wizardry:wizard_boots_healing.name=Ботинки Ð¦ÐµÐ»Ð¸Ñ‚ÐµÐ»Ñ + +item.wizardry:spawn_wizard.name=Спаун Волшебника + +entity.wizardry.zombie_minion.name=Зомби +entity.wizardry.skeleton_minion.name=Скелет +entity.wizardry.spider_minion.name=Паук +entity.wizardry.blaze_minion.name=Блейз +entity.wizardry.ice_wraith.name=ЛедÑной Призрак +entity.wizardry.lightning_wraith.name=Штормовой Призрак +entity.wizardry.shadow_wraith.name=Теневой Призрак +entity.wizardry.spirit_wolf.name=Призрачный Волк +entity.wizardry.spirit_horse.name=ÐŸÑ€Ð¸Ð·Ñ€Ð°Ñ‡Ð½Ð°Ñ Ð›Ð¾ÑˆÐ°Ð´ÑŒ +entity.wizardry.ice_giant.name=ЛедÑной Гигант +entity.wizardry.phoenix.name=Ð¤ÐµÐ½Ð¸ÐºÑ +entity.wizardry.wizard.name=Волшебник +entity.wizardry.magic_slime.name=МагичеÑкий Слизень +entity.wizardry.silverfish_minion.name=Чешуйница + +entity.wizardry.magic_missile.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.arc.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.spark_bomb.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.ice_shard.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.firebomb.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.poison_bomb.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.force_orb.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.spark.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.darkness_orb.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.fire_sigil.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.frost_sigil.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.lightning_sigil.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.lightning_arrow.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.firebolt.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.ice_charge.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.force_arrow.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.dart.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.lightning_disc.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.thunderbolt.name=ÐœÐ°Ð³Ð¸Ñ +entity.wizardry.decay.name=ÐœÐ°Ð³Ð¸Ñ + +entity.wizardry.black_hole.name=Ð§Ñ‘Ñ€Ð½Ð°Ñ Ð”Ñ‹Ñ€Ð° +entity.wizardry.shield.name=Щит +entity.wizardry.meteor.name=Метеор +entity.wizardry.blizzard.name=Метель +entity.wizardry.bubble.name=Пузыри +entity.wizardry.tornado.name=Торнадо +entity.wizardry.lightning_hammer.name=Молот Шторма +entity.wizardry.arrow_rain.name=Дождь Стрел +entity.wizardry.healing_aura.name=Ðура Ð›ÐµÑ‡ÐµÐ½Ð¸Ñ +entity.wizardry.forcefield.name=Силовое Поле +entity.wizardry.ring_of_fire.name=Кольцо ÐžÐ³Ð½Ñ + +item_group.wizardry=ВолшебÑтво +item_group.wizardryspells=Волшебные Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ + +achievement.crystal=Любопытный КриÑталл... +achievement.crystal.desc=Добудьте МагичеÑкий КриÑталл +achievement.arcane_initiate=ПоÑвÑщение Ð’ Магию +achievement.arcane_initiate.desc=Создайте Волшебную Палочку Из Золотого Самородка И МагичеÑкого КриÑталла +achievement.apprentice=Ученик Волшебника +achievement.apprentice.desc=ИÑпользуйте Фолиант Ðрканы Ð”Ð»Ñ Ð£Ð»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ð–ÐµÐ·Ð»Ð° +achievement.master=МаÑтер Магии +achievement.master.desc=Получите Жезл МаÑтера +achievement.all_spells=Маг Ð’Ñех ПрофеÑÑий +achievement.all_spells.desc=ИÑпользуйте Каждое Заклинание Ð’ Игре +achievement.wizard_trade=МагичеÑÐºÐ°Ñ Ð¡Ð´ÐµÐ»ÐºÐ° +achievement.wizard_trade.desc=Купите Предмет У Волшебника +achievement.buy_master_spell=Знание-Сила +achievement.buy_master_spell.wizardry:desc=Купите Заклинание МаÑтера У Волшебника +achievement.freeze_blaze=Ðе Так Жарко +achievement.freeze_blaze.desc=Заморозьте Блейза +achievement.charge_creeper=Это Ð¡ÐµÐ¹Ñ‡Ð°Ñ Ð’Ð·Ð¾Ñ€Ð²Ñ‘Ñ‚ÑÑ +achievement.charge_creeper.desc="Случайно" ЗарÑдите Крипира +achievement.frankenstein=Франкенштейн +achievement.frankenstein.desc=Привратите Свинью Ð’ Свинозомби С Помощью Молнии +achievement.special_upgrade=ЧародейÑкое РемеÑло +achievement.special_upgrade.desc=Применить Специальное Улучшение Ð”Ð»Ñ Ð–ÐµÐ·Ð»Ð° +achievement.craft_flask=Это ÐœÐ°Ð³Ð¸Ñ Ð’ Бутылке! +achievement.craft_flask.desc=Создайте Ману Ð’ Бутылке +achievement.elemental=Стихии +achievement.elemental.desc=Получите Стихийный Жезл +achievement.armour_set=Теперь Ты ÐаÑтоÑщий Волшебник +achievement.armour_set.desc=Создайте И Экипируйте Полный Ðабор ОдеÑÐ½Ð¸Ñ Ð’Ð¾Ð»ÑˆÐµÐ±Ð½Ð¸ÐºÐ° +achievement.legendary=Легендарный +achievement.legendary.desc=Получите ЧаÑть Легендарного ОдеÑÐ½Ð¸Ñ Ð’Ð¾Ð»ÑˆÐµÐ±Ð½Ð¸ÐºÐ° +achievement.self_destruct=Обратно +achievement.self_destruct.desc=УбейÑÑ Ð¡Ð¾Ð±Ñтвенной Магией +achievement.pig_tornado=Ðе СейчаÑ... +achievement.pig_tornado.desc=Заедьте Ðа Свинье Ð’ Торнадо + +tile.wizardry:transportation_stone.confirm=Теперь вы будете возвращены Ñюда при иÑпользовании Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ %1$s +tile.wizardry:transportation_stone.invalid=Сначала вы должны Ñделать круг из 8 камней транÑпортировки! + +container.wizardry:arcane_workbench=ЧародейÑкий Стол +container.wizardry:arcane_workbench.apply=Применить +container.wizardry:arcane_workbench.mana=Мана: +container.wizardry:arcane_workbench.upgrades=Применённые УлучшениÑ: + +tier.basic=Ðачинающий +tier.apprentice=Ученик +tier.advanced=Продвинутый +tier.master=МаÑтер + +element.simple=Ðет +element.fire=Огонь +element.ice=Лёд +element.lightning=ÐœÐ¾Ð»Ð½Ð¸Ñ +element.necromancy=ÐÐµÐºÑ€Ð¾Ð¼Ð°Ð½Ñ‚Ð¸Ñ +element.earth=Ð—ÐµÐ¼Ð»Ñ +element.sorcery=КолдовÑтво +element.healing=ИÑцеление + +element.simple.wizard=Волшебник +element.fire.wizard=Пиромант +element.ice.wizard=ЛедÑной Мага +element.lightning.wizard=Штормовой Маг +element.necromancy.wizard=Ðекромант +element.earth.wizard=ЗемлÑной Маг +element.sorcery.wizard=Колдун +element.healing.wizard=Целитель + +spelltype.attack=Ðтака +spelltype.defence=Защита +spelltype.utility=Утилита +spelltype.minion=Миньон + +spell.disabled=%1$s было отключенно в конфиге + +spell.wizardry:agility=ЛовкоÑть +spell.wizardry:arc=Дуга +spell.wizardry:arrow_rain=Дождь Стрел +spell.wizardry:black_hole=Ð§Ñ‘Ñ€Ð½Ð°Ñ Ð”Ñ‹Ñ€Ð° +spell.wizardry:blink=Блинк +spell.wizardry:blizzard=Метель +spell.wizardry:bubble=Пузыри +spell.wizardry:chain_lightning=Ð¦ÐµÐ¿Ð½Ð°Ñ ÐœÐ¾Ð»Ð½Ð¸Ñ +spell.wizardry:conjure_bow=Призвать Лук +spell.wizardry:conjure_pickaxe=Призвать Кирку +spell.wizardry:conjure_sword=Призвать Меч +spell.wizardry:cure_effects=Эффект Ð›ÐµÑ‡ÐµÐ½Ð¸Ñ +spell.wizardry:darkness_orb=Ð¢Ñ‘Ð¼Ð½Ð°Ñ Ð¡Ñ„ÐµÑ€Ð° +spell.wizardry:dart=Дротик +spell.wizardry:decay=Гниение +spell.wizardry:detonate=Взрыв +spell.wizardry:diamondflesh=ÐÐ»Ð¼Ð°Ð·Ð½Ð°Ñ ÐšÐ¾Ð¶Ð° +spell.wizardry:entrapment=Захват +spell.wizardry:fireball=Огненный Шар +spell.wizardry:firebolt=Огненный Болт +spell.wizardry:firebomb=ÐžÐ³ÐµÐ½Ð½Ð°Ñ Ð‘Ð¾Ð¼Ð±Ð° +spell.wizardry:fire_resistance=ОгеÑтойкоÑть +spell.wizardry:fire_sigil=ÐžÐ³Ð½ÐµÐ½Ð½Ð°Ñ ÐŸÐµÑ‡Ð°Ñ‚ÑŒ +spell.wizardry:fireskin=ÐžÐ³Ð½ÐµÐ½Ð½Ð°Ñ ÐšÐ¾Ð¶Ð° +spell.wizardry:firestorm=Огненный Шторм +spell.wizardry:flame_ray=Дождь ÐžÐ³Ð½Ñ +spell.wizardry:flaming_axe=Огненный Топор +spell.wizardry:flight=Полёт +spell.wizardry:font_of_vitality=ИÑточник Жизненной Силы +spell.wizardry:force_arrow=Ð¡Ð¸Ð»Ð¾Ð²Ð°Ñ Ð¡Ñ‚Ñ€ÐµÐ»Ð° +spell.wizardry:forcefield=Силовое Поле +spell.wizardry:force_orb=Ð¡Ð¸Ð»Ð¾Ð²Ð°Ñ Ð¡Ñ„ÐµÑ€Ð° +spell.wizardry:forests_curse=ПроклÑтие ЛеÑа +spell.wizardry:freeze=Замораживание +spell.wizardry:frost_axe=ЛедÑной Топор +spell.wizardry:frost_ray=ЛедÑной Луч +spell.wizardry:frost_sigil=ЛедÑÐ½Ð°Ñ ÐŸÐµÑ‡Ð°Ñ‚ÑŒ +spell.wizardry:glide=Скольжение +spell.wizardry:greater_heal=Великое ИÑцеление +spell.wizardry:growth_aura=Ðура РоÑта +spell.wizardry:heal=ИÑцеление +spell.wizardry:heal_ally=ИÑцеление Союзника +spell.wizardry:healing_aura=Ðура ИÑÑ†ÐµÐ»ÐµÐ½Ð¸Ñ +spell.wizardry:homing_spark=СамонаводÑщаÑÑÑ Ð˜Ñкра +spell.wizardry:ice_age=Ледниковый Период +spell.wizardry:ice_charge=ЛедÑной ЗарÑд +spell.wizardry:ice_shard=ЛедÑной ОÑколок +spell.wizardry:ice_shroud=ЛедÑÐ½Ð°Ñ ÐšÐ¾Ð¶Ð° +spell.wizardry:ice_statue=ЛедÑÐ½Ð°Ñ Ð¡Ñ‚Ð°Ñ‚ÑƒÑ +spell.wizardry:ignite=ВоÑпламенение +spell.wizardry:invisibility=ÐевидимоÑть +spell.wizardry:invoke_weather=Вызов Погоды +spell.wizardry:ironflesh=Ð–ÐµÐ»ÐµÐ·Ð½Ð°Ñ ÐšÐ¾Ð¶Ð° +spell.wizardry:levitation=Ð›ÐµÐ²Ð¸Ñ‚Ð°Ñ†Ð¸Ñ +spell.wizardry:life_drain=Похищение Жизни +spell.wizardry:light=Свет +spell.wizardry:lightning_arrow=Стрела Молнии +spell.wizardry:lightning_bolt=Удар Молнии +spell.wizardry:lightning_disc=ДиÑк Молнии +spell.wizardry:lightning_hammer=Молот Молнии +spell.wizardry:lightning_ray=Луч Молнии +spell.wizardry:lightning_sigil=Печать Молнии +spell.wizardry:magic_missile=МагичеÑÐºÐ°Ñ Ð Ð°ÐºÐµÑ‚Ð° +spell.wizardry:metamorphosis=Превращение +spell.wizardry:meteor=Метеор +spell.wizardry:mind_control=Контроль Разума +spell.wizardry:none=[ПуÑтой Слот] +spell.wizardry:petrify=Окаменение +spell.wizardry:phase_step=Фазовый Шаг +spell.wizardry:plague_of_darkness=Чума Темноты +spell.wizardry:poison=Отравление +spell.wizardry:poison_bomb=Ð¯Ð´Ð¾Ð²Ð¸Ñ‚Ð°Ñ Ð‘Ð¾Ð¼Ð±Ð° +spell.wizardry:replenish_hunger=ÐаÑыщение +spell.wizardry:ring_of_fire=Кольцо ÐžÐ³Ð½Ñ +spell.wizardry:shadow_ward=Ð¢ÐµÐ½ÐµÐ²Ð°Ñ Ð—Ð°Ñ‰Ð¸Ñ‚Ð° +spell.wizardry:shield=Щит +spell.wizardry:shockwave=Ð£Ð´Ð°Ñ€Ð½Ð°Ñ Ð’Ð¾Ð»Ð½Ð° +spell.wizardry:silverfish_swarm=Рой Чешуйниц +spell.wizardry:slime=Слизь +spell.wizardry:snare=Ловушка +spell.wizardry:snowball=Снежок +spell.wizardry:spark_bomb=Бомба ИÑкр +spell.wizardry:spectral_pathway=Спектральный Путь +spell.wizardry:spider_swarm=Рой Пауков +spell.wizardry:static_aura=СтатичеÑÐºÐ°Ñ Ðура +spell.wizardry:summon_blaze=Призыв Блейза +spell.wizardry:summon_ice_giant=Призыв ЛедÑного Гиганта +spell.wizardry:summon_ice_wraith=Призыв ЛедÑного Призрака +spell.wizardry:summon_iron_golem=Призыв Железного Голема +spell.wizardry:summon_lightning_wraith=Призыв Штормового Призрака +spell.wizardry:summon_phoenix=Призыв ФеникÑа +spell.wizardry:summon_shadow_wraith=Призыв Тёмного Призрака +spell.wizardry:summon_skeleton=Призыв Скелета +spell.wizardry:summon_skeleton_legion=Призыв Легиона Скелета +spell.wizardry:summon_snow_golem=Призыв Снеговика +spell.wizardry:summon_spirit_horse=Призыв Призрачной Лошади +spell.wizardry:summon_spirit_wolf=Призыв Призрачного Волка +spell.wizardry:summon_wither_skeleton=Призыв Скелета-ИÑÑÑƒÑˆÐ¸Ñ‚ÐµÐ»Ñ +spell.wizardry:summon_zombie=Призыв Зомби +spell.wizardry:telekinesis=Телекинез +spell.wizardry:thunderbolt=Штормовой Удар +spell.wizardry:thunderstorm=Гроза +spell.wizardry:tornado=Торнадо +spell.wizardry:transience=БыÑтрота +spell.wizardry:transportation=ТранÑпортировка +spell.wizardry:vanishing_box=ИÑÑ‡ÐµÐ·Ð°ÑŽÑ‰Ð°Ñ ÐšÐ¾Ñ€Ð¾Ð±ÐºÐ° +spell.wizardry:wall_of_frost=Стена Мороза +spell.wizardry:water_breathing=Дыхание Под Водой +spell.wizardry:whirlwind=Вихрь +spell.wizardry:wither=ИÑÑушение +spell.wizardry:wither_skull=Череп ИÑÑÑƒÑˆÐ¸Ñ‚ÐµÐ»Ñ + +spell.wizardry:agility.desc=Дает Заклинателю Более Ð’Ñ‹Ñокую СкороÑть ÐŸÐµÑ€ÐµÐ´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð˜ Большой Прижок на 30 Секунд. +spell.wizardry:arc.desc=Ð’Ñ‹Ñтреливает ИÑкрой Молнии Ð’ Цель +spell.wizardry:arrow_rain.desc="Лучники, огонь!" +spell.wizardry:black_hole.desc=Разрывай РеальноÑть Ðа ЧаÑти +spell.wizardry:blink.desc=Телепортирует Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ð’ Любой Блок, Ðа Который Он Указывает, Ð’ Определенном РадиуÑе. +spell.wizardry:blizzard.desc=Создает Зону Закрученного ЛедÑного Ветра, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð—Ð°Ð¼ÐµÐ´Ð»Ñет И ПоÑтоÑнно Повреждает Ð’Ñе, Что Попало Внутрь. Заклинатель ÐевоÑприимчив К Урону, Ðо Ð’Ñе Еще ЗамедлÑетÑÑ. +spell.wizardry:bubble.desc=СтрелÑет Потоком Пузырьков, Который Помещает СущеÑтво Ð’ Большой Пузырь, При Это Поднимает Его. Цель Будет Падать Или ПроÑто Получит Урон. +spell.wizardry:chain_lightning.desc=Ð’Ñ‹Ñтреливает ИÑкру Молнии У Цели, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð—Ð°Ñ‚ÐµÐ¼ ЦеплÑетÑÑ Ðš Дополнительным ЦелÑм До Двух Раз. +spell.wizardry:conjure_bow.desc=Создает Спектральный Лук С Ðеограниченными Стрелами, Который ДлитÑÑ 30 Секунд. +spell.wizardry:conjure_pickaxe.desc=Создает Спектральную Кирку Равной Силы Железной Кирке, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð”Ð»Ð¸Ñ‚ÑÑ 30 СÑекунд. +spell.wizardry:conjure_sword.desc=Создает Спектральный Меч Одинаковой Силы С Железным Мечом, Который ДлитÑÑ 30 Секунд. +spell.wizardry:cure_effects.desc=УдалÑет Ð’Ñе Эффекты Зелий, Которые Ð’ ÐаÑтоÑщее Ð’Ñ€ÐµÐ¼Ñ Ð’Ð¾Ð·Ð´ÐµÐ¹Ñтвуют Ðа ЗаклинателÑ, Хорошие Или Плохие. +spell.wizardry:darkness_orb.desc=Ð’Ñ‹Ñтреливает Медленно ПеремещающимÑÑ Ð‘Ð¾Ð»Ñ‚Ð¾Ð¼ Тёмной Энергии Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указываете, Которое Вызывает Гниение Ð’Ñего, Что Попадает. +spell.wizardry:dart.desc=Ð’Ñ‹Ñтреливает Дротик Ð’ Том Ðаправлении, Ð’ Котором Ð’Ñ‹ Указываете, Которое ÐаноÑит Урон И ОÑлаблÑет Его Цель. +spell.wizardry:decay.desc=Создает ПÑтно Гнили Ðа Земле, Которое Заражает Любое СущеÑтво, Которое Его КаÑаетÑÑ, Ð’Ñ‹Ð·Ñ‹Ð²Ð°Ñ Ð”Ð»Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ñ‹Ð¹ Урон Со Временем И РаÑпроÑтранÑÑ Ð‘Ð¾Ð»ÑŒÑˆÐµ Гнили, Где Бы Он Ðи Ходил. +spell.wizardry:detonate.desc=Вызывает Взрыв, Ð’ Указанном МеÑте, ÐаноÑÑ Ð£Ñ€Ð¾Ð½ Ð’Ñем ÐаходÑщимÑÑ ÐŸÐ¾Ð±Ð»Ð¸Ð·Ð¾Ñти СущеÑтвам, Ð’ÐºÐ»ÑŽÑ‡Ð°Ñ Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ, ЕÑли Они Слишком Близко. +spell.wizardry:diamondflesh.desc="Твои Стрелы Мне Ðе ПодходÑÑ‚!" +spell.wizardry:entrapment.desc=Заманивает Цель Ð’ Сферу Темноты, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÐŸÐ¾Ð´Ð½Ð¸Ð¼Ð°ÐµÑ‚ Её Вверх И ПоÑтоÑнно Её Повреждает. +spell.wizardry:fireball.desc=ЗапуÑкает Огненный Шар Ð’ Том Ðаправлении, Ð’ Которое Ð’Ñ‹ Указали. +spell.wizardry:firebolt.desc=СтрелÑет Ðа Ðебольшом РаÑÑтоÑнии От ВаÑ. +spell.wizardry:firebomb.desc=БраÑает Зажигательную Бомбу Ð’ Ðаправлении, Которое Ð’Ñ‹ Указываете, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð’Ð·Ñ€Ñ‹Ð²Ð°ÐµÑ‚ÑÑ ÐŸÑ€Ð¸ Ударе, ÐŸÐ¾Ð´Ð¶Ð¸Ð³Ð°Ñ Ð¦ÐµÐ»Ð¸. +spell.wizardry:fire_resistance.desc=Даёт Сопротивление Огню Ðа 30% +spell.wizardry:fire_sigil.desc=Помещает МагичеÑкую Ловушку ÐžÐ³Ð½Ñ Ðа Землю, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÐаноÑит Урон И Поджигает СущеÑтво, Которое ÐаÑтупило Ðа Ловушку +spell.wizardry:fireskin.desc=Покрывает Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ ÐžÐ³Ð½Ñ‘Ð¼ Ðа 30 Секунд. ЕÑли Заклинатель Будет Ðтакован, То Враг ЗагоритÑÑ. +spell.wizardry:firestorm.desc="Я Дракон." +spell.wizardry:flame_ray.desc=Создает Поток Пламени Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указали, Который Поджигает И ПоÑтоÑнно Повреждает Цели. +spell.wizardry:flaming_axe.desc=Создает Огненный Топор, Который Поджигает Врагов При Попадании. ДлитÑÑ 30 Секунд. +spell.wizardry:flight.desc=ПарÑщий, Как Орёл. +spell.wizardry:font_of_vitality.desc=Это ПотрÑÑающе. +spell.wizardry:force_arrow.desc=СтрелÑет Стрелой Силы Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указываете. +spell.wizardry:forcefield.desc=Создает Силовое Поле Вокруг ЗаклинателÑ, Который Отталкивает СущеÑтв И ОтклонÑет СнарÑды. +spell.wizardry:force_orb.desc=ЗапуÑкает Сферу Силы, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÐаноÑит Урон И ОтбраÑывает Близких СущеÑтв При Ударе. +spell.wizardry:forests_curse.desc="Как Ты ПоÑмел Войти Ð’ Мой ЛеÑ?!" +spell.wizardry:freeze.desc=Замораживает Цель Ðа 10 Секунд. Также Заморозит Воду И СоздаÑÑ‚ Снег Ðа Земле. +spell.wizardry:frost_axe.desc=Создает ЛедÑной Топор, Который Замораживает Врагов При Попадании. ДлитÑÑ 30 Секунд. +spell.wizardry:frost_ray.desc=Создает Поток Мороза Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указываете, Который ЗамедлÑет И ПоÑтоÑнно Повреждает Цели. +spell.wizardry:frost_sigil.desc=Помещает МагичеÑкую ЛедÑную Ловушку Ðа Землю, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÐаноÑит Урон И Замораживает СущеÑтво, Которое ÐаÑтупило Ðа Ðеё. +spell.wizardry:glide.desc=ПозволÑет Заклинателю Скользить Вниз, ÐаходÑÑÑŒ Ð’ Воздухе, Ð£Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°Ñ ÐšÐ½Ð¾Ð¿ÐºÑƒ ИÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐŸÑ€ÐµÐ´Ð¼ÐµÑ‚Ð°. +spell.wizardry:greater_heal.desc=ВоÑÑтанавливает Заклинателю 4 Сердца. +spell.wizardry:growth_aura.desc=Выращивает Ð’Ñе Зерновые Культуры РÑдом С Заклинателем. +spell.wizardry:heal.desc=ИÑцелÑет Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ðа 2 Сердца. +spell.wizardry:heal_ally.desc=ВоÑÑтанавливает Цели 2 С Половиной Сердца. +spell.wizardry:healing_aura.desc=Создает Зону ИÑцелÑющей Энергии, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð’Ð¾ÑÑтанавливает Здоровье Кого-либо Внутри Ðего, Кроме Ðежити, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÐœÐµÐ´Ð»ÐµÐ½Ð½Ð¾ Получает Урон. +spell.wizardry:homing_spark.desc=Создает Плавающую ИÑкру, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð”Ð²Ð¸Ð¶ÐµÑ‚ÑÑ Ðš Врагам. +spell.wizardry:ice_age.desc="Ð’Ñ‹ Замерзнете ÐавÑегда!" +spell.wizardry:ice_charge.desc=ЗапуÑкает ЗарÑд Льда, Который ВзрываетÑÑ ÐŸÑ€Ð¸ Ударе, Ð—Ð°Ð¼Ð¾Ñ€Ð°Ð¶Ð¸Ð²Ð°Ñ Ð‘Ð»Ð¸Ð·Ð»ÐµÐ¶Ð°Ñ‰Ð¸Ñ… СущеÑтв И ВыпуÑÐºÐ°Ñ ÐžÑколки Во Ð’Ñех ÐаправлениÑÑ…. +spell.wizardry:ice_shard.desc=Ð’Ñ‹Ñтреливает ЛедÑной ОÑколок Ð’ Том Ðаправлении, Ð’ Котором Ð’Ñ‹ Указали, Который ÐаноÑит Урон И ЗамедлÑет Цель При Попадании. +spell.wizardry:ice_shroud.desc=Окутывает Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ð’Ð¾ Льду Ðа 30 Секунд, Ð—Ð°Ð¼Ð¾Ñ€Ð°Ð¶Ð¸Ð²Ð°Ñ Ð’Ñе, Что Попадает Или Попадает. +spell.wizardry:ice_statue.desc=Замораживает Цель Ðа 20 Секунд Или До Тех Пор, Пока Она Ðе ВырветÑÑ Ðаружу. Цель Ðе Может ДвигатьÑÑ Ð˜Ð»Ð¸ Делать Что-либо Ð’ Замороженном СоÑтоÑнии, Ðо Также ÐевоÑприимчива К Любому Урону. +spell.wizardry:ignite.desc=УÑтанавливает Огонь Ð’ Течение 10 Секунд. Также Работает Как Кремень И Сталь. +spell.wizardry:invisibility.desc=Делает Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ðевидимым Ð’ Течение 30 Секунд. +spell.wizardry:invoke_weather.desc=ИзменÑет Погоду Ð’ Мире. +spell.wizardry:ironflesh.desc=Увеличивает Сопротивление К Оглушению Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ðа 30 Секунд. +spell.wizardry:levitation.desc=Поднимает Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ð’Ð²ÐµÑ€Ñ… При Ðажатой Кнопке ИÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐŸÑ€ÐµÐ´Ð¼ÐµÑ‚Ð°. Также Будет Ðейтрализован Урон От ПадениÑ, ЕÑли Он ИÑпользуетÑÑ Ð”Ð¾ Удара Об Землю. +spell.wizardry:life_drain.desc=Создает Поток ИÑÑушающей Энергии Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указываете, Который ИÑтощает Жизнь Цели И ИÑпользует Её Ð”Ð»Ñ ÐŸÐ¾Ñтепенного ВоÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð—Ð´Ð¾Ñ€Ð¾Ð²ÑŒÑ. +spell.wizardry:light.desc=Создает МагичеÑкую Точку Света, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÐžÑвещает Окружающую ОблаÑть. ДлитÑÑ 30 Секунд. +spell.wizardry:lightning_arrow.desc=СтрелÑет Стрелой Молнии Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указываете. +spell.wizardry:lightning_bolt.desc=ЗаÑтавлÑет Молнию Ударить Туда, Куда Ð’Ñ‹ Указываете. +spell.wizardry:lightning_disc.desc=ПоÑылает ДиÑк Молнии, ЛетÑщий Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указали И Ищет Цели. +spell.wizardry:lightning_hammer.desc="Я Поражу Ð¢ÐµÐ±Ñ Ð“Ð½ÐµÐ²Ð¾Ð¼ ÐебеÑ!" +spell.wizardry:lightning_ray.desc=Создает Поток Молнии Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указываете, Который ПоÑтоÑнно Повреждает Цели. +spell.wizardry:lightning_sigil.desc=Помещает МагичеÑкую МолниеноÑную Ловушку Ðа Землю, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÐаноÑит Урон СущеÑтву, Которое ÐаÑтупило Ðа Ловушку, И Приковывает Молнии К Другим Близлежащим СущеÑтвам. +spell.wizardry:magic_missile.desc=Ð’Ñ‹Ñтреливает МагичеÑкий ЗарÑд Ð’ Том Ðаправлении, Ð’ Котором Ð’Ñ‹ Указали. +spell.wizardry:metamorphosis.desc=ИзменÑет Цель Ð’ Другую Форму. Работает Только Ðа Ðекоторых СущеÑтвах. +spell.wizardry:meteor.desc=Ðекоторые Волшебники ПроÑто ХотÑÑ‚, Чтобы Мир Горел ... +spell.wizardry:mind_control.desc=Контролирует Ум Цели, ЗаÑтавлÑÑ Ð•Ñ‘ Ðтаковать Ближайшую Живую Цель, Отличную От ЗаклинателÑ. Когда Это СущеÑтво Будет Убито, Цель ВернетÑÑ Ðš Ðормальной Жизни. +spell.wizardry:none.desc=Чтобы Получить Книгу Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ /give command, иÑпользовать метаданные: /give [player] wizardry:spell_book 1 [spell id] (if you found this book in a chest, some other mod has messed things up). +spell.wizardry:petrify.desc=Повергает Цель Ð’ Камень До Следующего Заката Или Пока Ðе Будет Разбит. Цель Ðе Может ДвигатьÑÑ Ð˜Ð»Ð¸ Делать Что-либо, Пока Она Окаменела, Ðо Также ÐевоÑприимчива К Любому Урону. +spell.wizardry:phase_step.desc=Телепортирует Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ð§ÐµÑ€ÐµÐ· Стену Толщиной 1 Блок Перед Ðим. Улучшение ДальноÑти Увеличит Толщину, Через Которую Ð’Ñ‹ Сможете ТелепортироватьÑÑ. +spell.wizardry:plague_of_darkness.desc=Тьма Поглотит Их Ð’Ñех... +spell.wizardry:poison.desc=Ð’Ñ‹Ñтреливает Яд Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указываете. +spell.wizardry:poison_bomb.desc=БроÑает Ядовитую Бомбу Ð’ Ðаправлении, Которое Ð’Ñ‹ Указываете, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð’Ð·Ñ€Ñ‹Ð²Ð°ÐµÑ‚ÑÑ ÐŸÑ€Ð¸ Ударе, ОтравлÑÑ Ð‘Ð»Ð¸Ð·ÐºÐ¸Ñ… СущеÑтв. +spell.wizardry:replenish_hunger.desc=ПополнÑет Ð—Ð°Ð¿Ð°Ñ ÐŸÐ¸Ñ‰Ð¸ Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ðа 6 Пунктов Голода. +spell.wizardry:ring_of_fire.desc=Создает Огненное Кольцо Вокруг ЗаклинателÑ, ÐаноÑÑ Ð£Ñ€Ð¾Ð½ Ð’Ñем Ближайшим Противникам И ÐŸÐ¾Ð´Ð¶Ð¸Ð³Ð°Ñ Ð˜Ñ…. +spell.wizardry:shadow_ward.desc=Создает Стену Тьмы Перед Заклинателем, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÐаноÑит Ðападающему Половину Ð’Ñего ВходÑщего Урона. +spell.wizardry:shield.desc=Создает Защитный Барьер Силы, Который Блокирует СнарÑды И Магию. Также Дает Заклинателю Слабый Эффект СопротивлениÑ. +spell.wizardry:shockwave.desc=Бум. +spell.wizardry:silverfish_swarm.desc="ÐÐÐÐÐ! ИХ ОЧЕÐЬ МÐОГО!" +spell.wizardry:slime.desc=Охватывает Цель Слизью, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð—Ð°Ð¼ÐµÐ´Ð»Ñет И ПоÑтоÑнно Её Повреждает. Слизь РазрываетÑÑ Ð§ÐµÑ€ÐµÐ· 10 Секунд. +spell.wizardry:snare.desc=УÑтанавливает Ловушку Ðа Земле, ÐšÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÐаноÑит Урон И Кратко ЗамедлÑет СущеÑтво, Которое ÐаÑтупило Ðа Ловушку. +spell.wizardry:snowball.desc=Launches a snowball in the direction you are pointing. +spell.wizardry:spark_bomb.desc=ЗапуÑкает Бомбу ИÑкр Ð’ Том Ðаправлении, Ð’ Котором Ð’Ñ‹ Указываете. ИÑкры ПоÑвлÑÑŽÑ‚ÑÑ Ð£ Ближайших Противников При Ударе. +spell.wizardry:spectral_pathway.desc=Создает Перед Вами Ðеразрушимый МагичеÑкий МоÑÑ‚, Который ПроÑтираетÑÑ Ðа 15 Блоков. Через 60 Секунд МоÑÑ‚ ИÑчезает. +spell.wizardry:spider_swarm.desc=Призывает Рой Ядовитых Пауков, Чтобы СражатьÑÑ Ð—Ð° ВаÑ. Пауки ИÑчезнут Через 30 Секунд Или ЕÑли Они Будут Убиты. +spell.wizardry:static_aura.desc=Окружает Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ ÐœÐ¾Ð»Ð½Ð¸ÐµÐ¹ Ð’ Течение 30 Секунд, СтрелÑет ИÑкрами Молнии Во Ð’Ñе, Что Ударит ВаÑ. +spell.wizardry:summon_blaze.desc=Призывает Блейза, Чтобы СражатьÑÑ Ð—Ð° ВаÑ. Блейз ИÑчезнет Через 30 Секунд Или ЕÑли Он Будет Убит. +spell.wizardry:summon_ice_giant.desc="Разбей Их!" +spell.wizardry:summon_ice_wraith.desc=Призывает ЛедÑного Призрака, Который СражаетÑÑ Ð—Ð° ВаÑ. ЛедÑной Призрак ИÑчезнет Через 30 Секунд Или ЕÑли Он Будет Убит. +spell.wizardry:summon_iron_golem.desc=ÐвтоматичеÑкий Ðвтономный Ðвтомат. +spell.wizardry:summon_lightning_wraith.desc=Призывает МолниеноÑного Призрака СражатьÑÑ Ð—Ð° ВаÑ. МолниеноÑный Призрак ИÑчезнет Через 30 Секунд Или ЕÑли Он Будет Убит. +spell.wizardry:summon_phoenix.desc=Из Пепла... +spell.wizardry:summon_shadow_wraith.desc=Призывает Тёмного Призрака, Который Будет СражатьÑÑ Ð—Ð° ВаÑ. +spell.wizardry:summon_skeleton.desc=Призывает Скелета, Который СражаетÑÑ Ð—Ð° ваÑ. Скелет ИÑчезнет Через 30 Секунд Или ЕÑли Он Будет Убит. +spell.wizardry:summon_skeleton_legion.desc="ВоÑÑтань, ÐÑ€Ð¼Ð¸Ñ Ðежети!" +spell.wizardry:summon_snow_golem.desc=Создает Снежного Голема, Который СражаетÑÑ Ð—Ð° ВаÑ. ДлитÑÑ Ð”Ð¾ Тех Пор, Пока Ðе Умрет Снежный Голем. +spell.wizardry:summon_spirit_horse.desc=Призывает Ð”Ð»Ñ Ð’Ð°Ñ Ð’ÐµÑ€Ñ…Ð¾Ð²ÑƒÑŽ Лошадь. ÐŸÑ€Ð¸Ð·Ñ€Ð°Ñ‡Ð½Ð°Ñ Ð›Ð¾ÑˆÐ°Ð´ÑŒ ИÑчезнет Через Ðекоторое Ð’Ñ€ÐµÐ¼Ñ ÐŸÐ¾Ñле Того, Как Ð’Ñ‹ С Ðеё Слезите, Или Ð’Ñ‹ Можете Убрать Её С Помощью Жезла - Щелкните Правой Кнопкой Мыши Ðа Ðей. +spell.wizardry:summon_spirit_wolf.desc=Призывает Спутника Духа Волка, Который СражаетÑÑ Ð—Ð° ВаÑ. Призрачный Волк ИÑчезнет, Только ЕÑли Его Убьют, Или Ð’Ñ‹ Можете Его Убрать, Щелкнув Правой Кнопкой Мыши Ðа Ðём С Помощью Жезла. +spell.wizardry:summon_wither_skeleton.desc=Призывает Скелета-ИÑÑушителÑ, Который СражаетÑÑ Ð—Ð° ВаÑ. Скелет-ИÑÑушитель ИÑчезнет Через 30 Секунд Или ЕÑли Он Будет Убит. +spell.wizardry:summon_zombie.desc=Призывает Зомби, Который СражаетÑÑ Ð—Ð° ВаÑ. Зомби ИÑчезнет Через 30 Секунд Или ЕÑли Он Будет Убит. +spell.wizardry:telekinesis.desc=Перемещает Объект Или Другой Маленький Объект К Себе Или Щелкает Правой Кнопкой Мыши Ðа Блоке,Ðа Который Ð’Ñ‹ Смотрите. +spell.wizardry:thunderbolt.desc=СтрелÑет Громом, Который ОтбраÑывает Цели. +spell.wizardry:thunderstorm.desc="МУХÐÐ¥ÐÐ¥ÐÐ¥ÐÐ¥!" +spell.wizardry:tornado.desc=РазвÑзывает Торнадо Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указываете, Который БроÑает Что-либо Ðа Своем Пути Ð’ Ðебо. +spell.wizardry:transience.desc=Делает Переход Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ðа 20 Секунд. Заклинатель ÐевоÑприимчив Ко Ð’Ñему Урону Ð’ Переходный Период, Ðо Ðе Может Сломать Или ПомеÑтить Блоки Или ÐанеÑти Какой-либо Урон. +spell.wizardry:transportation.desc=ТранÑпортирует Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ð’ Запомненный Каменный Круг. Чтобы ИÑпользовать Это Заклинание, Сделайте Круг Камней ТранÑпортировки, Затем Щелкните Правой Кнопкой Мыши С Помощью Жезла. +spell.wizardry:vanishing_box.desc=Grants the caster access to their ender chest storage. +spell.wizardry:wall_of_frost.desc=Зима У Ð’Ð°Ñ ÐŸÐ¾Ð´ Рукой. +spell.wizardry:water_breathing.desc=ПозволÑет Заклинателю Дышать Под Водой Ð’ Течение 60 Секунд. +spell.wizardry:whirlwind.desc=ЗаÑтавлÑет Цель Взлететь Вверх Далеко От Ð’Ð°Ñ Ðа СкороÑти. +spell.wizardry:wither.desc=СтрелÑет Лучом Тьмы, Который УвÑдает Ð’ÑÑ‘, К Чему Он ПрикаÑаетÑÑ. +spell.wizardry:wither_skull.desc=ЗапуÑкает Череп ИÑÑÑƒÑˆÐ¸Ñ‚ÐµÐ»Ñ Ð’ Ðаправлении, Ðа Которое Ð’Ñ‹ Указываете. + +spell.wizardry:invoke_weather.sun=Дождь Ðачинает ОÑтанавливатьÑÑ ... +spell.wizardry:invoke_weather.rain=ÐебеÑа ОткрываютÑÑ ... +spell.wizardry:transportation.missing=Ваш Запомненный Каменный Круг ОтÑутÑтвует Или Затруднен ... +spell.wizardry:transportation.undefined=Ð’Ñ‹ Должны Сначала Запомнить МеÑтоположение Каменного Круга! +spell.wizardry:transportation.wrongdimension=Ваш Запомненный Каменный Круг ÐаходитÑÑ Ð’ Другом Измерении ... + +potion.wizardry:frost=Отморожение +potion.wizardry:fireskin=ÐžÐ³Ð½ÐµÐ½Ð½Ð°Ñ ÐšÐ¾Ð¶Ð° +potion.wizardry:ice_shroud=ЛедÑÐ½Ð°Ñ ÐšÐ¾Ð¶Ð° +potion.wizardry:static_aura=СтатичеÑÐºÐ°Ñ Ðура +potion.wizardry:transience=БыÑтрота +potion.wizardry:decay=Гниение + +key.categories.wizardry=Wizardry + +death.attack.wizardry_magic=%1$s был убит %2$s иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¼Ð°Ð³Ð¸ÑŽ +death.attack.indirect_wizardry_magic=%1$s был убит %2$s иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¼Ð°Ð³Ð¸ÑŽ + +config.wizardry.title.general=Mod Options +config.wizardry.title.spells=Spell Configuration +config.wizardry.subtitle.spells=Set a spell to false to disable it. + +config.wizardry.tower_rarity=Tower Rarity +config.wizardry.ore_dimensions=Ore Dimensions +config.wizardry.flower_dimensions=Flower Dimensions +config.wizardry.tower_dimensions=Tower Dimensions +config.wizardry.spell_book_drop_chance=Spell Book Drop Chance +config.wizardry.generate_loot=Generate Loot +config.wizardry.firebomb_is_craftable=Firebomb Is Craftable +config.wizardry.poison_bomb_is_craftable=Poison Bomb Is Craftable +config.wizardry.use_alternate_scroll_recipe=Use Alternate Scroll Recipe +config.wizardry.teleport_through_unbreakable_blocks=Teleport Through Unbreakable Blocks +config.wizardry.show_summoned_creature_names=Show Summoned Creature Names +config.wizardry.spell_hud_position=Spell HUD Position + +config.wizardry.category.spells=Configure Spells +config.wizardry.category.spells.tooltip=Select which spells are enabled. \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/loot_tables/chests/dungeon_additions.json b/src/main/resources/assets/wizardry/loot_tables/chests/dungeon_additions.json new file mode 100644 index 00000000..59c4bf30 --- /dev/null +++ b/src/main/resources/assets/wizardry/loot_tables/chests/dungeon_additions.json @@ -0,0 +1,92 @@ +{ + "pools": [ + { + "name": "wizardry", + "rolls": { + "min": 3, + "max": 7 + }, + "entries": [ + { + "type": "loot_table", + "name": "wizardry:subsets/novice_wands", + "weight": 3 + }, + { + "type": "loot_table", + "name": "wizardry:subsets/wizard_armour", + "weight": 6 + }, + { + "type": "loot_table", + "name": "wizardry:subsets/arcane_tomes", + "weight": 6 + }, + { + "type": "loot_table", + "name": "wizardry:subsets/wand_upgrades", + "weight": 2 + }, + { + "type": "item", + "name": "wizardry:magic_crystal", + "weight": 5, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ] + }, + { + "type": "item", + "name": "wizardry:spell_book", + "weight": 20, + "functions": [ + { + "function": "wizardry:random_spell" + } + ] + }, + { + "type": "item", + "name": "wizardry:scroll", + "weight": 10, + "functions": [ + { + "function": "wizardry:random_spell" + } + ] + }, + { + "type": "item", + "name": "wizardry:armour_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:identification_scroll", + "weight": 3 + }, + { + "type": "item", + "name": "wizardry:firebomb", + "weight": 4 + }, + { + "type": "item", + "name": "wizardry:poison_bomb", + "weight": 4 + }, + { + "type": "item", + "name": "wizardry:smoke_bomb", + "weight": 4 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/loot_tables/chests/wizard_tower.json b/src/main/resources/assets/wizardry/loot_tables/chests/wizard_tower.json new file mode 100644 index 00000000..f7bba6ea --- /dev/null +++ b/src/main/resources/assets/wizardry/loot_tables/chests/wizard_tower.json @@ -0,0 +1,77 @@ +{ + "pools": [ + { + "name": "wizardry", + "rolls": { + "min": 3, + "max": 7 + }, + "entries": [ + { + "type": "loot_table", + "name": "wizardry:subsets/novice_wands", + "weight": 3 + }, + { + "type": "loot_table", + "name": "wizardry:subsets/wizard_armour", + "weight": 6 + }, + { + "type": "loot_table", + "name": "wizardry:subsets/arcane_tomes", + "weight": 6 + }, + { + "type": "loot_table", + "name": "wizardry:subsets/wand_upgrades", + "weight": 2 + }, + { + "type": "item", + "name": "wizardry:magic_crystal", + "weight": 5, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ] + }, + { + "type": "item", + "name": "wizardry:spell_book", + "weight": 20, + "functions": [ + { + "function": "wizardry:random_spell" + } + ] + }, + { + "type": "item", + "name": "wizardry:scroll", + "weight": 10, + "functions": [ + { + "function": "wizardry:random_spell" + } + ] + }, + { + "type": "item", + "name": "wizardry:armour_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:identification_scroll", + "weight": 3 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/loot_tables/entities/evil_wizard.json b/src/main/resources/assets/wizardry/loot_tables/entities/evil_wizard.json new file mode 100644 index 00000000..8723be6f --- /dev/null +++ b/src/main/resources/assets/wizardry/loot_tables/entities/evil_wizard.json @@ -0,0 +1,55 @@ +{ + "pools": [ + { + "name": "common", + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "wizardry:magic_crystal", + "weight": 1, + "functions": [ + { + "function": "set_count", + "count": { + "min": 3, + "max": 5 + }, + "function": "looting_enchant", + "count": { + "min": 0, + "max": 1 + } + } + ] + } + ] + }, + { + "name": "rare", + "conditions": [ + { + "condition": "killed_by_player" + }, + { + "condition": "random_chance_with_looting", + "chance": 0.05, + "looting_multiplier": 0.01 + } + ], + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "wizardry:spell_book", + "weight": 1, + "functions": [ + { + "function": "wizardry:wizard_spell" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/loot_tables/entities/mob_additions.json b/src/main/resources/assets/wizardry/loot_tables/entities/mob_additions.json new file mode 100644 index 00000000..dc872ac7 --- /dev/null +++ b/src/main/resources/assets/wizardry/loot_tables/entities/mob_additions.json @@ -0,0 +1,29 @@ +{ + "pools": [ + { + "conditions": [ + { + "condition": "killed_by_player" + }, + { + "condition": "random_chance_with_looting", + "chance": 0.02, + "looting_multiplier": 0.01 + } + ], + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "wizardry:spell_book", + "weight": 1, + "functions": [ + { + "function": "wizardry:random_spell" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/loot_tables/subsets/arcane_tomes.json b/src/main/resources/assets/wizardry/loot_tables/subsets/arcane_tomes.json new file mode 100644 index 00000000..14ca2ad4 --- /dev/null +++ b/src/main/resources/assets/wizardry/loot_tables/subsets/arcane_tomes.json @@ -0,0 +1,46 @@ +{ + "pools": [ + { + "name": "tomes", + "rolls": 1, + "entries": [ + { + "type": "item", + "entryName": "apprentice_tome", + "name": "wizardry:arcane_tome", + "weight": 3, + "functions": [ + { + "function": "set_data", + "data": 1 + } + ] + }, + { + "type": "item", + "entryName": "advanced_tome", + "name": "wizardry:arcane_tome", + "weight": 2, + "functions": [ + { + "function": "set_data", + "data": 2 + } + ] + }, + { + "type": "item", + "entryName": "master_tome", + "name": "wizardry:arcane_tome", + "weight": 1, + "functions": [ + { + "function": "set_data", + "data": 3 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/loot_tables/subsets/novice_wands.json b/src/main/resources/assets/wizardry/loot_tables/subsets/novice_wands.json new file mode 100644 index 00000000..01f5c608 --- /dev/null +++ b/src/main/resources/assets/wizardry/loot_tables/subsets/novice_wands.json @@ -0,0 +1,50 @@ +{ + "pools": [ + { + "name": "wands", + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "wizardry:magic_wand", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:basic_fire_wand", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:basic_ice_wand", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:basic_lightning_wand", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:basic_necromancy_wand", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:basic_earth_wand", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:basic_sorcery_wand", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:basic_healing_wand", + "weight": 1 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/loot_tables/subsets/wand_upgrades.json b/src/main/resources/assets/wizardry/loot_tables/subsets/wand_upgrades.json new file mode 100644 index 00000000..4ce76637 --- /dev/null +++ b/src/main/resources/assets/wizardry/loot_tables/subsets/wand_upgrades.json @@ -0,0 +1,50 @@ +{ + "pools": [ + { + "name": "upgrades", + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "wizardry:condenser_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:siphon_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:storage_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:range_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:duration_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:cooldown_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:blast_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:attunement_upgrade", + "weight": 1 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/loot_tables/subsets/wizard_armour.json b/src/main/resources/assets/wizardry/loot_tables/subsets/wizard_armour.json new file mode 100644 index 00000000..95f8ac07 --- /dev/null +++ b/src/main/resources/assets/wizardry/loot_tables/subsets/wizard_armour.json @@ -0,0 +1,170 @@ +{ + "pools": [ + { + "name": "armour", + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "wizardry:wizard_hat", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_hat_fire", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_hat_ice", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_hat_lightning", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_hat_necromancy", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_hat_earth", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_hat_sorcery", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_hat_healing", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_robe", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_robe_fire", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_robe_ice", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_robe_lightning", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_robe_necromancy", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_robe_earth", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_robe_sorcery", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_robe_healing", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_leggings", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_leggings_fire", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_leggings_ice", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_leggings_lightning", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_leggings_necromancy", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_leggings_earth", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_leggings_sorcery", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_leggings_healing", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_boots", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_boots_fire", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_boots_ice", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_boots_lightning", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_boots_necromancy", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_boots_earth", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_boots_sorcery", + "weight": 1 + }, + { + "type": "item", + "name": "wizardry:wizard_boots_healing", + "weight": 1 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/block/arcane_workbench.json b/src/main/resources/assets/wizardry/models/block/arcane_workbench.json new file mode 100644 index 00000000..8a545d1c --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/arcane_workbench.json @@ -0,0 +1,21 @@ +{ "parent": "block/block", + "textures": { + "particle": "wizardry:blocks/arcane_workbench_bottom", + "bottom": "wizardry:blocks/arcane_workbench_bottom", + "top": "wizardry:blocks/arcane_workbench_top", + "side": "wizardry:blocks/arcane_workbench_side" + }, + "elements": [ + { "from": [ 0, 0, 0 ], + "to": [ 16, 12, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top" }, + "north": { "uv": [ 0, 4, 16, 16 ], "texture": "#side", "cullface": "north" }, + "south": { "uv": [ 0, 4, 16, 16 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 0, 4, 16, 16 ], "texture": "#side", "cullface": "west" }, + "east": { "uv": [ 0, 4, 16, 16 ], "texture": "#side", "cullface": "east" } + } + } + ] +} diff --git a/src/main/resources/assets/wizardry/models/block/crystal_block.json b/src/main/resources/assets/wizardry/models/block/crystal_block.json new file mode 100644 index 00000000..898d595a --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/crystal_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "wizardry:blocks/crystal_block" + } +} diff --git a/src/main/resources/assets/wizardry/models/block/crystal_flower.json b/src/main/resources/assets/wizardry/models/block/crystal_flower.json new file mode 100644 index 00000000..90f2f653 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/crystal_flower.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "wizardry:blocks/crystal_flower" + } +} diff --git a/src/main/resources/assets/wizardry/models/block/crystal_ore.json b/src/main/resources/assets/wizardry/models/block/crystal_ore.json new file mode 100644 index 00000000..80b71f13 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/crystal_ore.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "wizardry:blocks/crystal_ore" + } +} diff --git a/src/main/resources/assets/wizardry/models/block/ice_statue.json b/src/main/resources/assets/wizardry/models/block/ice_statue.json new file mode 100644 index 00000000..b7f5c4ad --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/ice_statue.json @@ -0,0 +1,3 @@ +{ + "parent": "block/ice" +} diff --git a/src/main/resources/assets/wizardry/models/block/magic_light.json b/src/main/resources/assets/wizardry/models/block/magic_light.json new file mode 100644 index 00000000..1f4f2185 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/magic_light.json @@ -0,0 +1,16 @@ +{ + "parent": "block/block", + "elements": [ + { "from": [ 0, 0, 0 ], + "to": [ 0, 0, 0 ], + "faces": { + "down": { "texture": "#down", "cullface": "down" }, + "up": { "texture": "#up", "cullface": "up" }, + "north": { "texture": "#north", "cullface": "north" }, + "south": { "texture": "#south", "cullface": "south" }, + "west": { "texture": "#west", "cullface": "west" }, + "east": { "texture": "#east", "cullface": "east" } + } + } + ] +} diff --git a/src/main/resources/assets/wizardry/models/block/meteor.json b/src/main/resources/assets/wizardry/models/block/meteor.json new file mode 100644 index 00000000..52676102 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/meteor.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "wizardry:blocks/meteor" + } +} diff --git a/src/main/resources/assets/wizardry/models/block/petrified_stone.json b/src/main/resources/assets/wizardry/models/block/petrified_stone.json new file mode 100644 index 00000000..9ecdfbf2 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/petrified_stone.json @@ -0,0 +1,20 @@ +{ + "parent": "block/block", + "textures": { + "all": "blocks/stone", + "particle": "blocks/stone" + }, + "elements": [ + { "from": [ 0, 0, 0 ], + "to": [ 0, 0, 0 ], + "faces": { + "down": { "texture": "#down", "cullface": "down" }, + "up": { "texture": "#up", "cullface": "up" }, + "north": { "texture": "#north", "cullface": "north" }, + "south": { "texture": "#south", "cullface": "south" }, + "west": { "texture": "#west", "cullface": "west" }, + "east": { "texture": "#east", "cullface": "east" } + } + } + ] +} diff --git a/src/main/resources/assets/wizardry/models/block/snare.json b/src/main/resources/assets/wizardry/models/block/snare.json new file mode 100644 index 00000000..52b4fbd9 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/snare.json @@ -0,0 +1,16 @@ +{ + "ambientocclusion": false, + "textures": { + "particle": "wizardry:blocks/snare", + "texture": "wizardry:blocks/snare" + }, + "elements": [ + { "from": [ 0, 0.25, 0 ], + "to": [ 16, 0.25, 16 ], + "faces": { + "down": { "uv": [ 16, 16, 0, 0 ], "texture": "#texture"}, + "up": { "uv": [ 16, 0, 0, 16 ], "texture": "#texture"} + } + } + ] +} diff --git a/src/main/resources/assets/wizardry/models/block/spectral_block.json b/src/main/resources/assets/wizardry/models/block/spectral_block.json new file mode 100644 index 00000000..fd4a9d44 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/spectral_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "wizardry:blocks/spectral_block" + } +} diff --git a/src/main/resources/assets/wizardry/models/block/transportation_stone.json b/src/main/resources/assets/wizardry/models/block/transportation_stone.json new file mode 100644 index 00000000..9e235690 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/transportation_stone.json @@ -0,0 +1,20 @@ +{ + "parent": "block/block", + "textures": { + "all": "wizardry:blocks/transportation_stone", + "particle": "wizardry:blocks/transportation_stone" + }, + "elements": [ + { "from": [ 5, 0, 5 ], + "to": [ 11, 6, 11 ], + "faces": { + "down": { "texture": "#all", "cullface": "down" }, + "up": { "texture": "#all"}, + "north": { "texture": "#all"}, + "south": { "texture": "#all"}, + "west": { "texture": "#all"}, + "east": { "texture": "#all"} + } + } + ] +} diff --git a/src/main/resources/assets/wizardry/models/block/vanishing_cobweb.json b/src/main/resources/assets/wizardry/models/block/vanishing_cobweb.json new file mode 100644 index 00000000..f8865a41 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/block/vanishing_cobweb.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "blocks/web" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/advanced_earth_wand.json b/src/main/resources/assets/wizardry/models/item/advanced_earth_wand.json new file mode 100644 index 00000000..3f23fbc6 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/advanced_earth_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_advanced_earth" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/advanced_fire_wand.json b/src/main/resources/assets/wizardry/models/item/advanced_fire_wand.json new file mode 100644 index 00000000..beb8fc84 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/advanced_fire_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_advanced_fire" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/advanced_healing_wand.json b/src/main/resources/assets/wizardry/models/item/advanced_healing_wand.json new file mode 100644 index 00000000..bba06e50 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/advanced_healing_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_advanced_healing" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/advanced_ice_wand.json b/src/main/resources/assets/wizardry/models/item/advanced_ice_wand.json new file mode 100644 index 00000000..35dadf70 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/advanced_ice_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_advanced_ice" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/advanced_lightning_wand.json b/src/main/resources/assets/wizardry/models/item/advanced_lightning_wand.json new file mode 100644 index 00000000..7c96d092 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/advanced_lightning_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_advanced_lightning" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/advanced_necromancy_wand.json b/src/main/resources/assets/wizardry/models/item/advanced_necromancy_wand.json new file mode 100644 index 00000000..db36e099 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/advanced_necromancy_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_advanced_necromancy" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/advanced_sorcery_wand.json b/src/main/resources/assets/wizardry/models/item/advanced_sorcery_wand.json new file mode 100644 index 00000000..127415e7 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/advanced_sorcery_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_advanced_sorcery" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/advanced_wand.json b/src/main/resources/assets/wizardry/models/item/advanced_wand.json new file mode 100644 index 00000000..bee14a76 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/advanced_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_advanced" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/apprentice_earth_wand.json b/src/main/resources/assets/wizardry/models/item/apprentice_earth_wand.json new file mode 100644 index 00000000..1ec46893 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/apprentice_earth_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_apprentice_earth" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/apprentice_fire_wand.json b/src/main/resources/assets/wizardry/models/item/apprentice_fire_wand.json new file mode 100644 index 00000000..0aa6cf8e --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/apprentice_fire_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_apprentice_fire" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/apprentice_healing_wand.json b/src/main/resources/assets/wizardry/models/item/apprentice_healing_wand.json new file mode 100644 index 00000000..118d72d0 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/apprentice_healing_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_apprentice_healing" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/apprentice_ice_wand.json b/src/main/resources/assets/wizardry/models/item/apprentice_ice_wand.json new file mode 100644 index 00000000..25bbce5c --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/apprentice_ice_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_apprentice_ice" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/apprentice_lightning_wand.json b/src/main/resources/assets/wizardry/models/item/apprentice_lightning_wand.json new file mode 100644 index 00000000..2f508113 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/apprentice_lightning_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_apprentice_lightning" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/apprentice_necromancy_wand.json b/src/main/resources/assets/wizardry/models/item/apprentice_necromancy_wand.json new file mode 100644 index 00000000..eb662348 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/apprentice_necromancy_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_apprentice_necromancy" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/apprentice_sorcery_wand.json b/src/main/resources/assets/wizardry/models/item/apprentice_sorcery_wand.json new file mode 100644 index 00000000..4ac8e0da --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/apprentice_sorcery_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_apprentice_sorcery" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/apprentice_wand.json b/src/main/resources/assets/wizardry/models/item/apprentice_wand.json new file mode 100644 index 00000000..57a642e0 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/apprentice_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_apprentice" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/arcane_tome.json b/src/main/resources/assets/wizardry/models/item/arcane_tome.json new file mode 100644 index 00000000..9737284c --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/arcane_tome.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/arcane_tome" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/arcane_workbench.json b/src/main/resources/assets/wizardry/models/item/arcane_workbench.json new file mode 100644 index 00000000..35acd55b --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/arcane_workbench.json @@ -0,0 +1,3 @@ +{ + "parent": "wizardry:block/arcane_workbench" +} diff --git a/src/main/resources/assets/wizardry/models/item/armour_upgrade.json b/src/main/resources/assets/wizardry/models/item/armour_upgrade.json new file mode 100644 index 00000000..08fd6606 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/armour_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/armour_upgrade" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/attunement_upgrade.json b/src/main/resources/assets/wizardry/models/item/attunement_upgrade.json new file mode 100644 index 00000000..927fd9fe --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/attunement_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/upgrade_attunement" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/basic_earth_wand.json b/src/main/resources/assets/wizardry/models/item/basic_earth_wand.json new file mode 100644 index 00000000..ddbccfee --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/basic_earth_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_basic_earth" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/basic_fire_wand.json b/src/main/resources/assets/wizardry/models/item/basic_fire_wand.json new file mode 100644 index 00000000..e323c2df --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/basic_fire_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_basic_fire" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/basic_healing_wand.json b/src/main/resources/assets/wizardry/models/item/basic_healing_wand.json new file mode 100644 index 00000000..80d6b33c --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/basic_healing_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_basic_healing" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/basic_ice_wand.json b/src/main/resources/assets/wizardry/models/item/basic_ice_wand.json new file mode 100644 index 00000000..8bd95b41 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/basic_ice_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_basic_ice" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/basic_lightning_wand.json b/src/main/resources/assets/wizardry/models/item/basic_lightning_wand.json new file mode 100644 index 00000000..2307f1a7 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/basic_lightning_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_basic_lightning" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/basic_necromancy_wand.json b/src/main/resources/assets/wizardry/models/item/basic_necromancy_wand.json new file mode 100644 index 00000000..0727fa69 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/basic_necromancy_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_basic_necromancy" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/basic_sorcery_wand.json b/src/main/resources/assets/wizardry/models/item/basic_sorcery_wand.json new file mode 100644 index 00000000..1a399976 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/basic_sorcery_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_basic_sorcery" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/blank_scroll.json b/src/main/resources/assets/wizardry/models/item/blank_scroll.json new file mode 100644 index 00000000..a6a86d05 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/blank_scroll.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/scroll" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/blast_upgrade.json b/src/main/resources/assets/wizardry/models/item/blast_upgrade.json new file mode 100644 index 00000000..3f085c0a --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/blast_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/upgrade_blast" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/condenser_upgrade.json b/src/main/resources/assets/wizardry/models/item/condenser_upgrade.json new file mode 100644 index 00000000..42a4c63f --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/condenser_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/upgrade_condenser" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/cooldown_upgrade.json b/src/main/resources/assets/wizardry/models/item/cooldown_upgrade.json new file mode 100644 index 00000000..23addd92 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/cooldown_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/upgrade_cooldown" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/crystal_block.json b/src/main/resources/assets/wizardry/models/item/crystal_block.json new file mode 100644 index 00000000..290f0923 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/crystal_block.json @@ -0,0 +1,3 @@ +{ + "parent": "wizardry:block/crystal_block" +} diff --git a/src/main/resources/assets/wizardry/models/item/crystal_flower.json b/src/main/resources/assets/wizardry/models/item/crystal_flower.json new file mode 100644 index 00000000..b71cf4d6 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/crystal_flower.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:blocks/crystal_flower" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/crystal_ore.json b/src/main/resources/assets/wizardry/models/item/crystal_ore.json new file mode 100644 index 00000000..f288786d --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/crystal_ore.json @@ -0,0 +1,3 @@ +{ + "parent": "wizardry:block/crystal_ore" +} diff --git a/src/main/resources/assets/wizardry/models/item/duration_upgrade.json b/src/main/resources/assets/wizardry/models/item/duration_upgrade.json new file mode 100644 index 00000000..5acea158 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/duration_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/upgrade_duration" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/firebomb.json b/src/main/resources/assets/wizardry/models/item/firebomb.json new file mode 100644 index 00000000..a1c8a29f --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/firebomb.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/firebomb" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/flaming_axe.json b/src/main/resources/assets/wizardry/models/item/flaming_axe.json new file mode 100644 index 00000000..104d511f --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/flaming_axe.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/flaming_axe" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/frost_axe.json b/src/main/resources/assets/wizardry/models/item/frost_axe.json new file mode 100644 index 00000000..1204aac7 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/frost_axe.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/frost_axe" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/ice_statue.json b/src/main/resources/assets/wizardry/models/item/ice_statue.json new file mode 100644 index 00000000..a3cfbe68 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/ice_statue.json @@ -0,0 +1,3 @@ +{ + "parent": "wizardry:block/ice_statue" +} diff --git a/src/main/resources/assets/wizardry/models/item/identification_scroll.json b/src/main/resources/assets/wizardry/models/item/identification_scroll.json new file mode 100644 index 00000000..4c39a408 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/identification_scroll.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/identification_scroll" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/magic_crystal.json b/src/main/resources/assets/wizardry/models/item/magic_crystal.json new file mode 100644 index 00000000..1aae8ddb --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/magic_crystal.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/magic_crystal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/magic_light.json b/src/main/resources/assets/wizardry/models/item/magic_light.json new file mode 100644 index 00000000..c5a50b1a --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/magic_light.json @@ -0,0 +1,3 @@ +{ + "parent": "wizardry:block/sea_lantern" +} diff --git a/src/main/resources/assets/wizardry/models/item/magic_silk.json b/src/main/resources/assets/wizardry/models/item/magic_silk.json new file mode 100644 index 00000000..cec4cb55 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/magic_silk.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/magic_silk" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/magic_wand.json b/src/main/resources/assets/wizardry/models/item/magic_wand.json new file mode 100644 index 00000000..1bb79f4f --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/magic_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_basic" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/mana_flask.json b/src/main/resources/assets/wizardry/models/item/mana_flask.json new file mode 100644 index 00000000..f898986f --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/mana_flask.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/mana_flask" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/master_earth_wand.json b/src/main/resources/assets/wizardry/models/item/master_earth_wand.json new file mode 100644 index 00000000..a880c440 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/master_earth_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_master_earth" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/master_fire_wand.json b/src/main/resources/assets/wizardry/models/item/master_fire_wand.json new file mode 100644 index 00000000..f2da76dc --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/master_fire_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_master_fire" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/master_healing_wand.json b/src/main/resources/assets/wizardry/models/item/master_healing_wand.json new file mode 100644 index 00000000..17c1dd41 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/master_healing_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_master_healing" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/master_ice_wand.json b/src/main/resources/assets/wizardry/models/item/master_ice_wand.json new file mode 100644 index 00000000..79f80cb6 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/master_ice_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_master_ice" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/master_lightning_wand.json b/src/main/resources/assets/wizardry/models/item/master_lightning_wand.json new file mode 100644 index 00000000..03e5f0ca --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/master_lightning_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_master_lightning" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/master_necromancy_wand.json b/src/main/resources/assets/wizardry/models/item/master_necromancy_wand.json new file mode 100644 index 00000000..5cc36467 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/master_necromancy_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_master_necromancy" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/master_sorcery_wand.json b/src/main/resources/assets/wizardry/models/item/master_sorcery_wand.json new file mode 100644 index 00000000..67cf62ec --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/master_sorcery_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_master_sorcery" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/master_wand.json b/src/main/resources/assets/wizardry/models/item/master_wand.json new file mode 100644 index 00000000..e7875627 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/master_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/wand_master" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/meteor.json b/src/main/resources/assets/wizardry/models/item/meteor.json new file mode 100644 index 00000000..14bb6068 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/meteor.json @@ -0,0 +1,3 @@ +{ + "parent": "wizardry:block/meteor" +} diff --git a/src/main/resources/assets/wizardry/models/item/petrified_stone.json b/src/main/resources/assets/wizardry/models/item/petrified_stone.json new file mode 100644 index 00000000..68982f03 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/petrified_stone.json @@ -0,0 +1,3 @@ +{ + "parent": "block/stone" +} diff --git a/src/main/resources/assets/wizardry/models/item/poison_bomb.json b/src/main/resources/assets/wizardry/models/item/poison_bomb.json new file mode 100644 index 00000000..d4c0d24a --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/poison_bomb.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/poison_bomb" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/range_upgrade.json b/src/main/resources/assets/wizardry/models/item/range_upgrade.json new file mode 100644 index 00000000..10896bb2 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/range_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/upgrade_range" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/scroll.json b/src/main/resources/assets/wizardry/models/item/scroll.json new file mode 100644 index 00000000..a6a86d05 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/scroll.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/scroll" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/siphon_upgrade.json b/src/main/resources/assets/wizardry/models/item/siphon_upgrade.json new file mode 100644 index 00000000..eec82d86 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/siphon_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/upgrade_siphon" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/smoke_bomb.json b/src/main/resources/assets/wizardry/models/item/smoke_bomb.json new file mode 100644 index 00000000..0fffc501 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/smoke_bomb.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/smoke_bomb" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/snare.json b/src/main/resources/assets/wizardry/models/item/snare.json new file mode 100644 index 00000000..ec41cce6 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/snare.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:blocks/snare" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/spawn_wizard.json b/src/main/resources/assets/wizardry/models/item/spawn_wizard.json new file mode 100644 index 00000000..908f7fa0 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spawn_wizard.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "items/spawn_egg", + "layer1": "items/spawn_egg_overlay" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/spectral_block.json b/src/main/resources/assets/wizardry/models/item/spectral_block.json new file mode 100644 index 00000000..9d577615 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_block.json @@ -0,0 +1,3 @@ +{ + "parent": "wizardry:block/spectral_block" +} diff --git a/src/main/resources/assets/wizardry/models/item/spectral_boots.json b/src/main/resources/assets/wizardry/models/item/spectral_boots.json new file mode 100644 index 00000000..e21ea294 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/spectral_boots" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/spectral_bow.json b/src/main/resources/assets/wizardry/models/item/spectral_bow.json new file mode 100644 index 00000000..649b7409 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_bow.json @@ -0,0 +1,50 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/spectral_bow_standby" + }, + "display": { + "thirdperson_righthand": { + "rotation": [ -80, 260, -40 ], + "translation": [ -1, -2, 2.5 ], + "scale": [ 0.9, 0.9, 0.9 ] + }, + "thirdperson_lefthand": { + "rotation": [ -80, -280, 40 ], + "translation": [ -1, -2, 2.5 ], + "scale": [ 0.9, 0.9, 0.9 ] + }, + "firstperson_righthand": { + "rotation": [ 0, -90, 25 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + }, + "firstperson_lefthand": { + "rotation": [ 0, 90, -25 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + } + }, + "overrides": [ + { + "predicate": { + "pulling": 1 + }, + "model": "wizardry:item/spectral_bow_pulling_0" + }, + { + "predicate": { + "pulling": 1, + "pull": 0.65 + }, + "model": "wizardry:item/spectral_bow_pulling_1" + }, + { + "predicate": { + "pulling": 1, + "pull": 0.9 + }, + "model": "wizardry:item/spectral_bow_pulling_2" + } + ] +} diff --git a/src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_0.json b/src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_0.json new file mode 100644 index 00000000..94e5d474 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_0.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "wizardry:items/spectral_bow_pulling_0" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_1.json b/src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_1.json new file mode 100644 index 00000000..1c711fa3 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_1.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "wizardry:items/spectral_bow_pulling_1" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_2.json b/src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_2.json new file mode 100644 index 00000000..b4762523 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_bow_pulling_2.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "wizardry:items/spectral_bow_pulling_2" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/spectral_chestplate.json b/src/main/resources/assets/wizardry/models/item/spectral_chestplate.json new file mode 100644 index 00000000..33de309e --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/spectral_chestplate" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/spectral_helmet.json b/src/main/resources/assets/wizardry/models/item/spectral_helmet.json new file mode 100644 index 00000000..5a8a9433 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_helmet.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/spectral_helmet" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/spectral_leggings.json b/src/main/resources/assets/wizardry/models/item/spectral_leggings.json new file mode 100644 index 00000000..e55f9c23 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/spectral_leggings" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/spectral_pickaxe.json b/src/main/resources/assets/wizardry/models/item/spectral_pickaxe.json new file mode 100644 index 00000000..45347c00 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_pickaxe.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/spectral_pickaxe" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/spectral_sword.json b/src/main/resources/assets/wizardry/models/item/spectral_sword.json new file mode 100644 index 00000000..4e88c159 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spectral_sword.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "wizardry:items/spectral_sword" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/spell_book.json b/src/main/resources/assets/wizardry/models/item/spell_book.json new file mode 100644 index 00000000..5a3d2fdb --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/spell_book.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/spell_book" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/storage_upgrade.json b/src/main/resources/assets/wizardry/models/item/storage_upgrade.json new file mode 100644 index 00000000..3673fa43 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/storage_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/upgrade_storage" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/transportation_stone.json b/src/main/resources/assets/wizardry/models/item/transportation_stone.json new file mode 100644 index 00000000..2b0a1e09 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/transportation_stone.json @@ -0,0 +1,3 @@ +{ + "parent": "wizardry:block/transportation_stone" +} diff --git a/src/main/resources/assets/wizardry/models/item/vanishing_cobweb.json b/src/main/resources/assets/wizardry/models/item/vanishing_cobweb.json new file mode 100644 index 00000000..1fe6d579 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/vanishing_cobweb.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "blocks/web" + } +} diff --git a/src/main/resources/assets/wizardry/models/item/wizard_boots.json b/src/main/resources/assets/wizardry/models/item/wizard_boots.json new file mode 100644 index 00000000..39685945 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_boots" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_boots_earth.json b/src/main/resources/assets/wizardry/models/item/wizard_boots_earth.json new file mode 100644 index 00000000..9ee903af --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_boots_earth.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_boots_earth" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_boots_fire.json b/src/main/resources/assets/wizardry/models/item/wizard_boots_fire.json new file mode 100644 index 00000000..a1e664d0 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_boots_fire.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_boots_fire" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_boots_healing.json b/src/main/resources/assets/wizardry/models/item/wizard_boots_healing.json new file mode 100644 index 00000000..57c5b635 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_boots_healing.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_boots_healing" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_boots_ice.json b/src/main/resources/assets/wizardry/models/item/wizard_boots_ice.json new file mode 100644 index 00000000..be14210e --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_boots_ice.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_boots_ice" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_boots_lightning.json b/src/main/resources/assets/wizardry/models/item/wizard_boots_lightning.json new file mode 100644 index 00000000..d6904206 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_boots_lightning.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_boots_lightning" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_boots_necromancy.json b/src/main/resources/assets/wizardry/models/item/wizard_boots_necromancy.json new file mode 100644 index 00000000..65abcd7b --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_boots_necromancy.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_boots_necromancy" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_boots_sorcery.json b/src/main/resources/assets/wizardry/models/item/wizard_boots_sorcery.json new file mode 100644 index 00000000..ffbf448b --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_boots_sorcery.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_boots_sorcery" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_handbook.json b/src/main/resources/assets/wizardry/models/item/wizard_handbook.json new file mode 100644 index 00000000..c302b6b6 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_handbook.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_handbook" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_hat.json b/src/main/resources/assets/wizardry/models/item/wizard_hat.json new file mode 100644 index 00000000..7f1dad7a --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_hat.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_hat" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_hat_earth.json b/src/main/resources/assets/wizardry/models/item/wizard_hat_earth.json new file mode 100644 index 00000000..95273a7f --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_hat_earth.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_hat_earth" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_hat_fire.json b/src/main/resources/assets/wizardry/models/item/wizard_hat_fire.json new file mode 100644 index 00000000..abecf19d --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_hat_fire.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_hat_fire" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_hat_healing.json b/src/main/resources/assets/wizardry/models/item/wizard_hat_healing.json new file mode 100644 index 00000000..0c453f01 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_hat_healing.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_hat_healing" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_hat_ice.json b/src/main/resources/assets/wizardry/models/item/wizard_hat_ice.json new file mode 100644 index 00000000..98430ed6 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_hat_ice.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_hat_ice" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_hat_lightning.json b/src/main/resources/assets/wizardry/models/item/wizard_hat_lightning.json new file mode 100644 index 00000000..408eae50 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_hat_lightning.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_hat_lightning" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_hat_necromancy.json b/src/main/resources/assets/wizardry/models/item/wizard_hat_necromancy.json new file mode 100644 index 00000000..8c62b1dd --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_hat_necromancy.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_hat_necromancy" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_hat_sorcery.json b/src/main/resources/assets/wizardry/models/item/wizard_hat_sorcery.json new file mode 100644 index 00000000..3cb674bb --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_hat_sorcery.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_hat_sorcery" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_leggings.json b/src/main/resources/assets/wizardry/models/item/wizard_leggings.json new file mode 100644 index 00000000..02aed97c --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_leggings" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_leggings_earth.json b/src/main/resources/assets/wizardry/models/item/wizard_leggings_earth.json new file mode 100644 index 00000000..8fcec98f --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_leggings_earth.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_leggings_earth" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_leggings_fire.json b/src/main/resources/assets/wizardry/models/item/wizard_leggings_fire.json new file mode 100644 index 00000000..bcb63bac --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_leggings_fire.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_leggings_fire" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_leggings_healing.json b/src/main/resources/assets/wizardry/models/item/wizard_leggings_healing.json new file mode 100644 index 00000000..16c90a84 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_leggings_healing.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_leggings_healing" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_leggings_ice.json b/src/main/resources/assets/wizardry/models/item/wizard_leggings_ice.json new file mode 100644 index 00000000..c1424913 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_leggings_ice.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_leggings_ice" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_leggings_lightning.json b/src/main/resources/assets/wizardry/models/item/wizard_leggings_lightning.json new file mode 100644 index 00000000..f8e4824c --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_leggings_lightning.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_leggings_lightning" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_leggings_necromancy.json b/src/main/resources/assets/wizardry/models/item/wizard_leggings_necromancy.json new file mode 100644 index 00000000..9c97d209 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_leggings_necromancy.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_leggings_necromancy" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_leggings_sorcery.json b/src/main/resources/assets/wizardry/models/item/wizard_leggings_sorcery.json new file mode 100644 index 00000000..3ac6dd52 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_leggings_sorcery.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_leggings_sorcery" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_robe.json b/src/main/resources/assets/wizardry/models/item/wizard_robe.json new file mode 100644 index 00000000..7f8e266e --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_robe.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_robe" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_robe_earth.json b/src/main/resources/assets/wizardry/models/item/wizard_robe_earth.json new file mode 100644 index 00000000..66ed7826 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_robe_earth.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_robe_earth" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_robe_fire.json b/src/main/resources/assets/wizardry/models/item/wizard_robe_fire.json new file mode 100644 index 00000000..6ab282f2 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_robe_fire.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_robe_fire" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_robe_healing.json b/src/main/resources/assets/wizardry/models/item/wizard_robe_healing.json new file mode 100644 index 00000000..54cba900 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_robe_healing.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_robe_healing" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_robe_ice.json b/src/main/resources/assets/wizardry/models/item/wizard_robe_ice.json new file mode 100644 index 00000000..45398f00 --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_robe_ice.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_robe_ice" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_robe_lightning.json b/src/main/resources/assets/wizardry/models/item/wizard_robe_lightning.json new file mode 100644 index 00000000..ce513b4a --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_robe_lightning.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_robe_lightning" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_robe_necromancy.json b/src/main/resources/assets/wizardry/models/item/wizard_robe_necromancy.json new file mode 100644 index 00000000..c3ff763a --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_robe_necromancy.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_robe_necromancy" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/models/item/wizard_robe_sorcery.json b/src/main/resources/assets/wizardry/models/item/wizard_robe_sorcery.json new file mode 100644 index 00000000..2b5224eb --- /dev/null +++ b/src/main/resources/assets/wizardry/models/item/wizard_robe_sorcery.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "wizardry:items/wizard_robe_sorcery" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/sounds.json b/src/main/resources/assets/wizardry/sounds.json new file mode 100644 index 00000000..857b9a40 --- /dev/null +++ b/src/main/resources/assets/wizardry/sounds.json @@ -0,0 +1,39 @@ +{ + "arc": {"category": "player","sounds": [ + {"name": "wizardry:arc1","stream": false}, + {"name": "wizardry:arc1","stream": false}, + {"name": "wizardry:arc3","stream": false} + ]}, + + "aura": {"category": "player","sounds": [{"name": "wizardry:aura","stream": false}]}, + "boom": {"category": "player","sounds": [{"name": "wizardry:boom","stream": false}]}, + "crackle": {"category": "player","sounds": [{"name": "wizardry:crackle","stream": false}]}, + + "darkaura": {"category": "player","sounds": [ + {"name": "wizardry:darkaura1","stream": false}, + {"name": "wizardry:darkaura2","stream": false} + ]}, + + "effect": {"category": "player","sounds": [ + {"name": "wizardry:effect1","stream": false}, + {"name": "wizardry:effect2","stream": false} + ]}, + + "electricitya": {"category": "player","sounds": [{"name": "wizardry:electricitya","stream": false}]}, + "electricityb": {"category": "player","sounds": [{"name": "wizardry:electricityb","stream": false}]}, + + "flameray": {"category": "player","sounds": [{"name": "wizardry:flameray2","stream": false}]}, + "force": {"category": "player","sounds": [{"name": "wizardry:force","stream": false}]}, + + "freeze": {"category": "player","sounds": [{"name": "wizardry:freeze","stream": false}]}, + "frostray": {"category": "player","sounds": [{"name": "wizardry:frostray","stream": false}]}, + "heal": {"category": "player","sounds": [{"name": "wizardry:heal","stream": false}]}, + "ice": {"category": "player","sounds": [{"name": "wizardry:ice","stream": false}]}, + "largeaura": {"category": "player","sounds": [{"name": "wizardry:largeaura","stream": false}]}, + + "magic": {"category": "player","sounds": [{"name": "wizardry:magic1","stream": false}]}, + + "sparkle": {"category": "player","sounds": [{"name": "wizardry:sparkle","stream": false}]}, + "wind": {"category": "player","sounds": [{"name": "wizardry:wind","stream": false}]}, + "rumble": {"category": "player","sounds": [{"name": "wizardry:rumble","stream": false}]} +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/sounds/arc1.ogg b/src/main/resources/assets/wizardry/sounds/arc1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..f5d3c72f6e0c10fb7737fd8e6d54f312c0124b98 GIT binary patch literal 19855 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

    kVdK?20k@1E=hmX7Ej$M{w3{?Av!pVLNU}93 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 Dr+g`U literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/ice.ogg b/src/main/resources/assets/wizardry/sounds/ice.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9879c888b742039693ea0251562f91a74f467472 GIT binary patch literal 19226 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 Oaw|3R9QQ+S20j3E6}P7V literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/largeaura.ogg b/src/main/resources/assets/wizardry/sounds/largeaura.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c9caa43f9c4bb6ec0c4fc709c325f8efdcc005c3 GIT binary patch literal 49796 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 BA-4bk literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/magic2.ogg b/src/main/resources/assets/wizardry/sounds/magic2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..cf4f5a796b085875bee97211c1fcfd536d3266a9 GIT binary patch literal 19283 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 Z{||2;KfWkmnY!cA5h?w$2VHh1%m7uO@xlNA literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/magic4.ogg b/src/main/resources/assets/wizardry/sounds/magic4.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1793567ab1a30b7c7544ee08de9e987fd9da31e4 GIT binary patch literal 23573 zcmeZIPY-5bVt|5VHweSxvnDg69AjC2QBr0xNQlX04Txf3U?_wr-oXgg2^C~u0O@38 zU|`_fCtok9`yUN3LrjuoU|@*IEXdIFFG^R)$xI3Zo3G%hU}RumZeV6)1Tv116{1+v z$vKRXfrEj8!O%zHXv2jGp$rTH3=9b>ntYSfJT;e2S*TGtV~Pieb=079#+1&Z63IP= z$6$nlNs1@~0}Dfg24~;mXP#N-EYl^_`-&D=X8KtyS77f7d|=6W=&M?C-m)#rvh&Vq zs&eo~vNA9*F*tZAwu%ISh@=k1Hi@JT#devZ6N<~{6me;-SkS~}bV8xo$LQsf$$nNZ zS1j(cdZn@Df)lsymP=kfhF8Oq*X?DCttmcd`FswP-~{_afq{X=iA^#^z=;E7e23<; z8AV)1Cm`NZU}ymO+7N1)gH|N|z%ZGD{&vo9KoxPJYc24oR zpDAoN=SJKZnd4b^x%_VZZeQsVWn*)L* z)t8nufqkyPz|bN9PQ@?+oRlG{c*&$Lty3DC&lsK70TF8spR;DFse+DoSdd1)>MhaV_|D5OkqWRnDElC~K|r!RQJ*WSP08!z65p0MCK zhrx+Mu?3tbrzG_l9-q_f=fnw#U|7y66gfUo=Hx^b?@cPcmvqj4GV%Xxa#7ed(8M=b zH1?us>1DChV6)iErm2@hQ?Hh#-rSZNy}dSa8z{Fx@(hT)UJCXiB~UBV~}bdfw5e(K#)% zbJnVzi*in_d%cSwg6ACfA{F-{P|k5JQbEc&2MlGLgH(=h(((Na@uTfUW82UYS8?PB zU|={ffyWzMjsynjUJWw68l)Qj7g|2a`~WEP-mqVppIkqd$^e4ko@1A-+)M zqts{!&@u!V85kJ(7#JAEoE9o-Gc{N+GPFN-n55wO!K5KM@`FuP^U7tM=RezA zZqevkl*trm;>*auzzPa>vkWgCzJQDqUJME<3m z4GxW+{y1XV^Ug&YvzD#erFZ(0$$4-U6Ng*~B-rH1;~{qKsL~R<2t2dY1!O;nmVu@eYvKs$J_|Gl3L^#$KPA+K{OQ!{~Do&l` zwNhb8P>?1oLxZdZLxXGtM{C;}7KTp@3>?W*lFnE@S8?((d^V?8NO7q|@j1(tBFUg8 z@{~!2&*v2Td7Ye5e9lsRY04SP=W`|pSv{Xq%;%-KwB(%S^CeS)oL#@BkED^VGYRWqM9pRyj|7*0Rj3NlP-pBC~AHLqorE9yE-L zVgo@T=Nqbe8Wcw>SFPf@Y~p)4Bs8=Y)ZSgS>h+;*pzyz5ns|HFDo{utD2=^dnku;i zRDJ7kGcfoUFfeFsNGxrcylCSAC+9FGP<`2A$f4OH5X7dqM8L^IvvmS$@@H%)U|?tv zfc8+#dJ>_mLN4T93!?u*OV*93?6q6N7$nZMGCM@J^ct^GnJe1ICN8x}h=GHXfuYB- z!|;X5lu2G*qE0=Q8md#LMRl!p>M-P3y5ve!j-l9jOZJ6JrbKmVZhK_;e94k4Q9Xvo zqGGremrjZ5*4-vCJ4bQJl%QrIABX~P3qZ#B{w|T6}Lusrz$v}^7NY9#G%Qyvb9HR>5R$KoKDXO z;z`mrEa@?Hw|pAnbX;MlWKwD^#fdo)3#PomVbjFEi1Ufs8Di|)5($HGQ+;Eh&t%l*mg&Q8b zcQoiR$6PoX%kISCB+wKgOHPC-dUO+!mZL9nzn!w&`qkD!K*j*Mp(RyKAHPA+a9UOs*SObiT+;9Amwfsum) zGzJ0cH#0DBaDW}la6kpDp8+)L0czK#_`R4TnVc9J9u)Gw?tjDog8#+;>;9Mi@BZKL zzxV%?uQT*61}86f6a2EfO3I+8?JURUwDYLZcnC8r$C4JBX{s6gbH*`8iXp``Ddct*brX zAKAzqiE`@y(V{4EjpwWCTJIw(QbVq)vgq&P4Z5Jw(en02+S2fdh&OC5Pa=LE`IzOB zGiiYc5%SZeO7qu;W66ZDm|ugnN=RX0dx4hrDDuyNzmOzH4F}#ud+ms%W+a)pkuJJEc|1hcL9{msR8L0(H zZfu)>}gg@BeR#fUX&`y@L73C%JpDV(>0MUzLpK5ENeKV4sbO!nZA1KxBS>? z=LGGtXiJeRinYI3d~J7mS}(dMed#@~+>+Yq{M+PXk4*E(c=%$+j>lO+(s4^RoVeBK zq%9VzJR|BVqtu45cEfC!)g2wY8Lxa-ZjipHaZr1!*oFr;*1mHWO8d$<>$}S#F#(Pf zWkSmuj$57he$F!}+QH$#SruPa`w)gjzh^EBx)Aa_*~{>}(WftGk|hft9oeW;q{z^) za|7p&Mmy#X?>To4I_e0=iRY~QA>z(==FFP|J--)x+g~kni0As$Z!fOf{qswVxhApP z%$QN(sEfi&$15QMtfr2hZ)JRr+_N)FZD(L(dJ_@L_f7ViiMwugO340AtY;d98iWMA zGFB@kxvWfCm63apcZ;h-$*rdi4$RXU6&B}g+mIEt)x?+k@5IgtPsA8D-Z&*?=&>?% zP15333|b5w3|~t9&4m;d7fqWTs3^F~?v!zqfaz+*FkK~;71x4T6jdEw?(T344HSHx z_E4#7Me~XX<0D)dLJ1DX$|MvPH83@;y!QM&#{!9l2xi7;?M1IlI#zWVb{t^gbC!zu z`mZZElwF7AMwkE_2cuha1Fx9hR8xuNhEXDnN6e1!d76DwG~6LA_{_}1N@7OYX*HWD z&bE^c&IkAZU0S$Kv53Rr=)pPjrz<^XW!$$z)kN_J^9lL?K66D6?%$zms;S_>Q1{2U zu!DQwVJGWH8VQUH*D9IciZ%qW)Yg5UE4s8N@ciXe!?fu$T?~)(u6%v%&1=`(H7k$a z`>=|GYf)+5w$)4wHVqv~E48FXTmz*xY0rlq-%cQNL z363qS36YWv3s!lUpI}m)CZOOlt>LKD1CuS`84RJjnfSSRHz&M~Q0C^UKfUoTLxM}l z+O@(QInoSVJ-H4g%qj~U7)AO78d^fsxOmtCSiI63MOg)ycQ^!b1cVuI1iag_J6$G$ zIbpH*L8;)vM#H2IM>QVClNP$_UzwTPllUfAZcwpINr+xLMQEGYG3{v#%)XIU!atT2 z);UCL*ow@X;Tj@(hw;tfAI1gD&yIVa5egB6a4#^1RdlZuP;`hDKcXsQ`G5aaxAiJg034@EMRz~5p>7w(`*^dTMRsx z8|2TrZD?p%6uNfS2^Nh5hJT+(&RQVBv>?lSbyvd0rZ5K)LBnI$G`JE34lpn&c}rMz zDly46MXU)8V4cXD`Y)WZR?|_`Wlg83fPjyF^m)(3I-9;!e4&caQ^tnlh!jZB*z_4ib}A!$?{5Lsxte%V3s>C9nSdZJm`?zmUVHurN((mtz%=geTch7=S7df|c9dRb*pQ~MjISZ1`9?-) zAg`3GV}|>O@4IY6LymNHWE_-;bYW|3Oy!6W$YJRfb!6#H(&1o;n!tLMtlGyS!NVkR!E((jnFv#b8yRbFyGa-Wx#ShoJf_)~Wji~&XU?24 zV}=Uj0s#*OfwNo;0uH>ahXuTEC2UN}Oh`QX;bK-M&n#C)Qy$R+sTL<9&g*+c`f<$T zTiRl1fRG?=a? z1^6m>F@&DIG-cz=X9<1Fl3lewe3c4ZpsSFe9mc+O-qQ}lV~3=?;z9)(7#*&qWK2KM z`&Zhbhw&mu($U*3)$Sb|_DDG}Fl9&|QgHFT;*YTSrgBXw13 zqo05@gQJbK+Zra02CW6AJglJ`0)0aTO%}ZfVBL^W(j|H@WTWKjMavG=o;soD7|PvJ z`pP6ic@#+B zyo`kz6dGIwL_&N58C-Y*k8Wtq%)AkqbW2F|a)5JJk&8nFgTj=e!>1JgP7-0@P-Iw| zWRfHjdQoG=TCPaL1OufGQ-Q5neP_8Mx|-^hOu7;$iwZIZ9=*bT;dX}v+q9+?t*&a? zRXeU7+ax9;o5bMg5|ACHb7hspw5-IV0*<+x99UgNL-uZaAD!%=yoiBeRR>2?CbQVG zCO!v-HBC>}$n2=8StPN+Pd8#~*DZY+iEmRlV#D|y7CT<(5Iu13dj86n>O9IX!&!0^ zT$|Z=qykGi7KNI0`0n_gW{?ml(#sLHHcFV8F*Gpr%-Vd(_0L+fTS{V!Rv&eo%yDh@ z^5y`}I!4x4RV*|7Yd*9x8uH3BD?D2vB`Dy+!k95x<~{2@Mgya-Obq*Owz@stn{rXD zCF)UL*}~vTGaZwT4M%JZd?Gv;8glm@$m#HYAi&TbvNA|;xy764cMm*zSc7KBc1XU; zP>ZOZxV2HXFl_g!@9)?d8WcLTyyo_<&6N1|ZGl{{;D%cXndTYKbgjCZSFY-8?VYu> zl$o2c~4J|=Tk}lj$B5f z8WN9g5OfiA4oqo#_1am0d-j^hSxI-7ZAyD_EyeR<+o}!;h8&j-TUfIaWuyO1$|bK(vnE@IsmrZh zL4##VU+?T*FUF%G41zqXw;3=Tal7KQCNg4HR^n9_;VS{$fjI&KR~f~k84h$TVigG0 zR%(!9kZ4+J8nWV6YS@E~zc|;nt=p4zam5M+2^NX=b8TO;zGv(9i*GFtX-p7g+0xa- zz_4v=f?!68X77U7KBk)WzZO4A5ScUWjgOc-56cBBn~Gq&NLADG<(X1_X}nuqS(R4K zdG=G!=WyVfhudcylywt&5h=#R5D^h!@mGK$z3s?FMaFxcr$h>@steV)4GcG?tEH(4 zuMzvY?Z-Zqj_u}iOO4BJT;rMBJ6kJg^XW@W3<3vC4RqJJ>aJ2fDiWR5#nG{VALS5J;2!2v37-)o5=%3RXGJtXBGyRY?fpf21jKM zk81Oe^U~CBZxp!Doy)?ol2^K^A&J*W@rTsY_8EuVJQ6mj=x!3*=*Yq?HAjCz^P+|g z@Bi$3c!Whq+u>r8<@H3NFAQ}Yp&L%sO=azS#Pxqe<53OI(0$pF55r;v<2vRxG@ES_ zcdtIc&#=MgWbwzJb5?$OS<*i9(E%pE)TE>&H8nBi&qscx)O=WaZ++KV>&$dtljNkX zm8)E0tz*{qvNXiJJ-=nk@q61stqo7R@mW@%pC}i=#Sn0%Yo;aK#UwZ^GSv|Dt`g$z;dMN+OhQ3n+kM0jg%OX$q`X7R>#t+o7vWo+-f z_dPL7y1=C+!6GQgxP>W+#lqf4NL}DTm!JIp{YBZ1TBh;59vq*Se-5cQeuVA*A%>1T zan=dGx-G4$^H=p-Rk7{cer5%uwzolB1J8t0ic{Pf%jZeWa(ThMSm~+SmyT2xP#w&$ zTwZxXWfO;t(1ae_slu{+>Jb)aZpa=9UFLlzX^Vtq=j|OvQ+$r~aySYvSyvykS;fm~ z&*PdorbRw#3?F{FF*2-LG)-#q!uxxwxWsw*4!$6qHz&-MXu|nmfVa1WQALL}aN$ zjzD#`n$%S>mkb7loMy%oA{kjxHxi_>mcF@l^;Sd&lNM9MIu=%gCdPS*4U9ajn>b$c zym;Z|ViL>!X418=oY0l4+zh~D6^sXb5MvdfF%9e00%t^K{$Kxp^Zyh7xBOrBf8YNN z|9AX9_}?Rnb(#*N%SsN;ZP$OLjzAk!dbhcr(PV%3gf=m zm5?Lk@Zu7af{3^4Dk}l*1&5Un6mcjBvT;bS5|LWWx<-Mafoa=Yt&S|g#f*#ztrxRG z*;X4g@bWS+D4IoF>vCJ3b#_s%z#g&F9X%2fP9IzvHi)-Rb6T###G@e0%_hisLE^|U z4tS(A$St|=^G za+<^yBEXewz;K93QsIzN(wEf0h6F|z?Nvbx>pBjyH8)Q1=q=VdAbT%}fk(T6hoPgu zb;ALzWFCno)1@yaotx=+p|N*E49A~6j4l6I6^<-8;Ha{bO@Sfqg^R+I{T_~0S}pc! zj`M?_GF{6!XvVQsRqteR^t8qbEETkh#Tj0T3mC)CY8l>| z-Ie)E{3LVx*Xq3syGujDiaus+zpyvr(e(@5M(^m%PIPZEkGkc$%MG!$LIMr~k&}*XFuCd^ENc8YiGy z?Neu8yCM>>^;H7X&djq~k)a~Yj0!3YtywB5Cljn(*rFFpMXzD%P+fdAO?PayT)+9k>^m$Lhfw47b=aXigiVQYepQ-XXL)&y(;Cvt*C>Iq|yDz<|+=KL`7XDqv^`nfZG zHQRrm%_rYIdH1z?8~?Wb?$_5OipXzdG?;&HF9XB9sWDBlHEKH!d5(g~J(GovRr>{o_6_Yvm=N&T=3&^5&1uy04!*#Ee8V z8bfVYsX86ts4Ubyp&)VQ0{h97&k8M11U#g!Bs&JmuD!PTa*yQ6J1Z`&WQbsJaJ_zJ zW(yMoOQP&$wbe#$J!ZjytNs67_e=_OWmxSgulreG#x*Xc4EGYzT_qbBvJ4nl9t51| zWm&<%5OCCVak0Uk3hC5JZg()a4;5``Fhw21}<2z;rxrYUED_;Qd$@sj%;CU zW=v^bED1iaeS-bLPp+?dvOF{&U@*-xRDI+<)CVYZSPcrWHiJmhkJS{m>+|ku4s8!a%sL5^B zRnz5SXBRn7WMFVQFe60z5DyE301pG7=w77-VFxu77}9zkZFm!{Y;?ewBUnvPqB)g; z;ZRvZpiBP84%XEw$HWrY85}M!Ff>kfIcQ~~so>O+B_POpBtu(u>s~D}7Dj`RqjHRC z6InB|lA@eLCWtY3B{pO-oZ+9=5*9Oc>I4mrjukzOIzF-itleD)r9@adqOJsNJ?OXo zmWI@k1suo1JubQA*tfAZGrDYfbZc8+q0+o}9upZE4{kYF#M7q4VX44iWp$n{sqqoZ ztX*MB4NZq<**QN}7AUa3w>)Iw+2Y=1ecPQ@Ecv1-dg$5CDZKSu5Ba-yPPU)?X6tj^ zpP=c5oY%bT&i!J1lF9i*G5N@X~PsL+hJ|r$6ch zwmh3!6V&l~iS4INJ8iaVIOgzNV`^Br&hyZ|%(()&$2ZiaY)EiWTv6by{aWFr!o%cc zGZtP?VA#Hmks;+s!xy#JjoVXic3zF0&EvX+v2cQfZd~|U@oCNbHhEQ_U2M25fN`Tq zL%_|5w5(I>pC#ZkjhE0T?|W9?bZUZpBlFKIRf#?BKQ8w5ER+!a<# zi4qeK@IGzk6S_4^ck{G@V3+L;3`~=>ytYnYOKM>WYvV9en8Y05$fCs6s*>!W)0*Vk z&bVNb!8*xBU2&SMOdDLgwH9=AEs~Nx`P2XEBu4jR5qr!u8GDZ@a4?;CC~(Mz<=Fct z6GM7FnqF08Sg<04VTre>@a?O@3my6vOyZbzk-_W0+q?^Ib3YU@%1!5)=({_QE1pr; zE$LR5r0SA<6$_zbtToG~dP=z)Sp1wRVC`!sd*~sk39>=9@c`=^D`xHc=^gXydhYyI z)LUMBDnTq+t+_Djw%@clt8agN9)0EZXQ$|$mT4>uum6?aVP)9hH!XmrzIH;)=THUi zJk3|XJMQ1}S*)(HTW0yIoTym$@4Kf(^__BYKUts~{>R|O;$%e&t0+_^1iWNtkeIY6R4STTfx~Ut#;}mP z0u2lst{?62op{iwSyOD^x~E#N873{^TA(G##*odhbxnfEfrbbv1MMRghc+o5s?}-t zpUl$R?p2M=U19Pn{m9>A)>8ll0U;&GfYhu37`E2evHXFiM7hDi8xGP>LmwKO_k ztau=VbAM>#dE<%3H`G;aXFtB^!)7^C-OGC3?_4#eIk9%k3>(&&U%06AfM?Fuxrvi+ zzRdmFXBDZ?db4q6XY8kchku@4QTux0yYJub-ah$FF}>~K^(nCj>zgMX|6Kp?qBg^U z=3SNz_vidGSaR;+*8Mx?G`Xx|*m>Z`(%pY|zlyDsOI^S2{LwX!ezhrgbw_s3Tlw>M zf&LWc2Pxj3XIig>{qtRS(q>+psnh}kXBq#i7PsGeuRQbZUQnzj-;(Lf7GeyhuIk6D zW_F7zEa9|i4w9_x^k8Rr5m(I6vCh>&gw?uOajmL?OTF1HRtAOxo}wDT#Yr&fRWENQj{@zt*~RqZ4QPvjt^HIy|k(Cq^qHz%#ke;sgfBP z3!H5j;?x$fiivD_B*DPA=k_HZ(WR>rc{(I`P9*9ue3;>O=rt3^+O1M&7#KK0T)VZl z9emaQ?^E;UOLlMn3r4q#9q4d$addH59>{QKsZ+lk-wErb9A`6Dgd7!=NZ^%d*u}G3 z!HD5G3)gja28IPkB?5Z23h&FM$#58LxR`W@DeB0=GZI>sx27GMFp;Z1{hxLB>Sp$tU)kQy zJD0iPxupI@#)jPj_tWCDqx=@xE}EpszO(SDLha_LlA^db(b_IY4Ol<)$Zldg+u+GK zwOQ%sFNw8x9~RAJnqJ^}tNbY=x3Ed#UcQcfL3xj_@?NVw&78WDwPW&1Pu&{kzMvax z%@20Zoh$zSMBb!_6POvZw0!S2FLdC%;rp-f%I)3NC%ba-9ip#*jmruO1187mYz0Y74p*fGqe2cC@oktAdYNek?#5H!X zX&*bS@;0H9Nn|Ap)205+kwL)`7d5qJ91-JYV_h53z0s*H{JB{DFAuqyK}Wm9cvk6l z2`E_yi9|>|NKx))W60Py&y=;Z&Yi*G;wr9$qgF>77#Moam*qIDe0VJS0V@~RJ~=(N z13_g|l^Ommk>}E4IWo34bqlo1GaQI|UnO2`Q(yZvssDNT z#q?&@N3Z|0GZeJxN9aFbNH4KER4KH>K-kBA+4rxx)-zaV%$)g#*(@PKF=XkC*{fey zc)pf5er+;k?bi9f^%)er`E+WkEe!*Dr!z9S#;7V++ue(AD0_1L)vNz$`Nsu!EK3w- z5NY7Co19b58}|FuBbPR}SDen4ziO{)U%H`kY{C8c-;J}TF-kHNs`SgwR`l@9Jj>;9 zwp`}s(`(v`dLIQzhot?om#fLpJAFu3cgc%{%8d*5PGXzOp~85;Wu{SjI>!b92E!hP z4%Z+x?OR!GOBoo8IM~_llxC>E47$aTQQG7h>3e-ugVTam35Ek(PB6SWn*I9L6{S~Kb9LDkx++AY)K1uF!$=$J@2v5gZI+BD#z6ezN|U-uv7m*rdC|k%2kjK{DTzIE}}wzZ(9=zq|cEXMPi( zNe@%pbd?Fzs7$1ddlUha60$)%g^ic zzb3w6Xz1^~&dlKTda;(k1)fIPhP3_@PHjJ9=jKYJ?KFJJy~0t?(ZS>M$909Xb|uc# zOx*JPkrqS8i`UwL7oXJVur@^Q*8R#@%-@-F^#s?1Tp!I2uL_TE^?k91VoN8M#7y5E zpPG66^Zk;yeVGg$6~R2`Z>-qwuv^CYB4ctG(gYx3=WV%+2TDewJaHvA5#1EyICbaS6KxxU?=!J`iW`<{PqF zy)2>Z$Qz@{_Fqf-WYaf)eU_p1yZzY3r0>bLw*PiczUB3JpWMqQ#?3`@p4EI+W@ixK za8SE{%hd0^2&d)s_}5?F?P}aMeUg9gy001yUJLJ}?|t(=I7PIzbQ7!2%90)D%jBQm zGo8$Nb{%U2i+#J2Q_%miugm7$)#px{+PyGw_Q_xB@6OnHb+&GIKli0Eo$LIi&2pl; zj7Ki=y?k*t`SmR+;caZk?|uKmHgQ$QUWZLRIt&bqmmfA9U`Q3o^xzR_@t(9;fX!vO z+kz0DMWWrVA*|{Q3<5lz3)Zaic36I+C4nu)k$D~iGs6lkj>6d&&UUHSo)i(8#iPpY zuuaK*reNj*FKLF2v!)pyl@jN4@JKK=5pmdb%u&IVi>FaEgLlG2bp{>@mkd{?%}pB* zOcHF6Xy}Ug;m4$Oi+xGNnrxL_JVI|af3Z25I#g#o5HHLZ5-?r;BG-$nV{uQ&az3B4d-_K>4SxT92vYvSQ@{^zZ zqT8m~#4=@~Xyr3e)>dvJ0F`9{$!KH!W!KW%c2ZniRAs($|bC3Pd%2>#8 z-%OQV(;mH$Cy(d%Dq3o3VrDKFxDz@xp?^nfBm zUC!!thtp?!FaO|?n8xU4-fVu;?fv3;Q>%YHE4Xm_*8R6Pd3*ZQ&Y3ZMxVv56hhaiD z*SuqOYQE|F&TdJ}cw;=FI4(ur>E7DBFT3{iM!#M5`%;0F-~^r~FEtaBu!i@anMzcH zyR^1SX}K?K_*;89?7gkF`Dq4*r=<)lxVwGjB+r}aG%aK=O5YbeHR52|%}L?X?6$G< z?WLO*)toe#p!JMJ#ev82aJhj27t_IOyvn)O_Qok|=4vZT{@{1uUwwbx4*sYUvsha4 z)+#w?tn6GF+ITKeGb84m=@Y&Ht`#k<4H62hi#EB*ik)1r&w5&qLQ=zHCdNhv$5+hT zc52H_@0;$t*k!Ha6@$wOyj(V%J?y!?3{N?fX1Hz>n2_Mi&dQvx!!T9Pbt^+gE8Cr0 zT*_H*k4^LHDPReWj$#ZDci5w_D!d~+j5X)vjV4wFdAsVo*$LMIBsMs#-q^sw!B%E{ zz#~g$!6Q*N28Ic#BFtO!qZ!IkxqkNC-`bHfE|-4uGECsF4K=%O^9j@~G?-?-gKtl~umD#* ze>$g(*o89Ddsc^xjfJ~+`Uo3nIWVlgTV7Q9RY@dA2{Im z>BOri&&8j|`c7Z(>-Wu7DC88w9_uw9&iA;--z`lQRA z$$w$T7N!sT{0;>!Y*BnY!)1=+0d3KjLC&YXoseZ;)W{%Fc$M*jgOOIwO+F`v15yfE zJpNPJbfU9^+L#zxE^2X0h^a1^)*2}($~3{XN6hQ!ftxCee^$P|lC*lF(1$t;xs@F{ zy9%am?mQ6Jk{E3}XWBJ3F$Ts1c0c8OMXt?JVPs$s;bv$&Rj0}jSGI-IZNDDh<7*+E zEw@dVW%WGZKG1wS__@IH+PZJ2)^5JvYs$dz0aU759JHMC;jnbW#frCkPE2-~mHsDa zpZ~=>E~`(t&zv!{c_ynT%ki79jps%?t$10(78Nm!HdK1 z*&exUVzk{T{88(&lMd5?x&NNdc7A2c>|pxo!#{<~T$>%nRz7}G7sW_v&_4-bq+R9~i@^YE$`_nghY&VkGbeX~HP<*Q7 z-o^8l2{AAPmAh8V>GYZ#DsJn0%*esr$M~Jz8C7+e&Djr*2yQ)fR-VOW(!yS+q=j)@ zEiaqg9?1nCePAXhtKxbC~vB zQ)%3>PBJN z`~T@OG`wx$zQ^!F{Z4OsB+I#ixn&*Aha0-PzkHEZmq}c+E%ng44zAE(PN8qx#VqrR zlDFQ{Du4a3)lT%=c6*0D0lF&&(~$5>A3yYAQii(zxGSKSo;Hr@F1 zPF3Al&&@fvq$V0MIJ7xmS-s5i&+O&V&mDhlYAv%bOK6k1#;|pvL9cozdB`o&C^Y7XvML7&cd(EHsoXO?+VHNG*E_m`= z)ia}?vpHw-rZF?5Ti28o*J@i$_&SweK=5-ZBa;=+e94Yx?YnN>AATRd`N8S`zUKkU z=WQ*U%xktI^Ug0OKgK@{#$5dm-swFtH*!0|&Ghu3i&A^zvhBy`ZPJ~u#H+7=cIkJY z-N)Z-o>(2fqgf+5Mj-TN!+geO$F!aQm|yYU63m%(`d|a=1pYX7&Uj9a1RjY8ti24v z>C6n9X0F}99C+&89p$VfzEd_)Q>Sn#cq`QGwDOK`D+pK{kavJ7LP(vhZd-^)VQk}` zeBR?7?|VI&%J-*D_mFxYaRRiT~d$%V_4%c_zR&sa&G6SWbWzfUH; z<-Do(0YxuHr(4-lf4e2_t}v73KhDt5eIqa9>%-f7uU{$8FzP&UZ>Eg;htEIxM07qo zFqe8g&E4Jn|HyBh{jZ-GbC;;I-mQB1^Fw_2@t>~!R$DIVU-@`CHn{%V`dyRms!TYU zrl=WlKJfjWuX+#KR{C!0IQ;MC{=Nxs9GDplPRFX>o<4DRg?gu6Y)<yf9EPvl2_c7q9=Oc^&&m)t zEuN1~iQJ3#l}i~K(%0^0J+S^91H-uwk6C#2 zHiTO&-sXNX?d=Ek9}A5?YfUxH2xn}0x7dDu|2pCG87vdFEBt9aCTY~L{>S0?8L|vN zCSG^?@$R)}Uf(fE#o!eEeb;S0I9cNpR5UldI9qA%%J%)Rj(ySBMc=QSIT8_lswMu0 z<8))!?|-dU7JU-2mwYZ-eDRAq>y+Owx7U3?!ocbG@;% z`ajF>+Zo$tEqbZfC)|+s>g>w=nMqO&=lA|R^`-T-4|9X?k>mGoeMr9fuj=19qxTPg z=W8<8W^gopnzLZJ!Fhj%|92T2zTfWbni+4mV)A@P<5aug-9PwKc5W_=yTHlNT6Erc zud!|I+{5SpdU)1cbXa$s$KmqFWerN=58CQx*`IZfvKgV$fbe@lDY zBEIjcvY-AOzwMAecVA50&YKHnCfb>m{aEuv^Xa=jdHF?EP*uryhn+VCnytd2{8ox#_K zCxc6FwW)9(t3BGT-f~PnY>UOgooVskuDf+_{P3HR;f?&8d9QQs z?9Hy;_#2cRAFxbc{Fam9t+w*+_wQ~$>_5P2Z&a)s66&jZf&IpTGmbuI_Dx%9ZpFqB z@jhN}J{yC{=M%pVy#Mhz?96hdd+bGO;)xw5<{kOroAUK`i`Vfa7HqZ3*uA=P){&gb zwdxm7XID7YWG_*@!nE2s?3c3du{*=Bo!G4a@{NJTk2_9@84g~D}P{e+>I4GW-ME=j;UOQrTcv6frkMmZ;!kG-E>)P!9%C* z^O_wK{v;h>VvrMZ@Kn~G{F5=qU;>-GN6H^2k51p!iHE2AOkitd%n~}Gv+BgdUFQW( zNMs1sPV$VM^l-YaF6XAE6|Ibn0+J?zhJP+Hto+RC5Xj&UIs$~@zzk5212X!-20C=Z zU*A&b|AqfI|DXPU;s2rkC;wmhfA#;Vf390Z4(<`+|LuRUmGR@gE*no)^@iHBKc^Nb z_jP~x&BpMfrZt%FE2!}lF@3kOhJIb{)E4 zZgI{_@9&kA^BO4(VqB;6YbT{_)_T3xzcYfxwrJi-#ms5hGh>%5{cip~)Hh+)ziaF( zuU-zlyzKVF3-@w=ne_AR{d_k*Z<<_A`T{L}W`_8x?|TJ7$eGb{9p3B%2!0q;MkroFKG?#{vXZ|a@a z@Y8!Fk1{>;l|34J=l8tN-&po~P71zoe!0*Vj{~(T#sbTC9$~Nj@!|Q#3oH3`Uz&vVaEKgS*TNA!x|Mfbb+HW?@k7peIrTA^;9#iw}pS~BYC|~wZJ(}C^|0L_@ z$wHfd)VKdlS zFJ3;&car6EwhYN!2K5Z5!+P-%+d@C6bFG-nnB~Deq2i-PFUL2{ZyIK z)^9ePzx}Af1ZLd{v+EDbUQ;c8S+$Y-{srs#_Nr5ENc8qaznrLDHMgcIE_t{1i)-RB z%Ig=MbKEAH?rR!fdARhkX9Kg$3a1{fzsDDK&Ybp(>$x58ck}7n|9#j$N4}#gN=#4V zu^fZed4mhbcUZq#m%`uucK`h6Z*Mpm7&3_enJT|aHbddTY|Y);Gl~KitbgMC{?$#+ zfZxh5Zkm~K9I8zXylHuT*}u(Sk3Tvc9eeTInYkuLmCQMHZ+jDNJvhE!uXdl?^!K;a zi0v~Q1dbq`Fn*S3E!?$;WKhHNeFEpJXt;W4-)udVHl8ir= zOq+R}EqwAvC!w?dhk`(do`bdbg`9Zl z0}2Z&lHHjE6n4D3Wa@o|bH7$iXM?-5;G78w3eG~)n*T6Kq%^N=xh@&GR+E`){qm{D zU$QZ^%wHkcXeA)9L79O;F;_Ey;h*Z0N}uy@`qnBce*EsLA}IET;pgd@LVUItL51}1 z+G{;|dwx7W{(jmuNGaVYY_g;A^ZVb`3jSq*%GnWNf~j5?vqC%;Fs(UYXS8j}!(ErX zKUE)RdGPb)ZAONU_o0g_6SvjAvzdES`TMNYj|m}(OVyU9oUr`Ta5wUO;nMrE=X`5l zq@Ims7pc=a==EiR`2C`Y)EbxX8QgOt>{lS&%7Pd}ibV-!`x__Bm z+ngtNPAj#Uf95&s@R{whuV0RAgGu|m)1Qz2<^KOi^V#=chqDfoetz11l$XVo*-!Lx z?ti77uPa0QpYON)x5&xzIb#=twT1ol%Jq5AHpMPms8}fWM(@wvyXVi8CazM5opAZ? z*UOg=crqO8E{)vuJo3u?xr`euH)qJpL zz?!?3)q^4O)3T5b3DE;_Yiy^m-m(jwuw(^e{4VByt||(ma~ghjM;~kr5WH`oEEKVU z`D|T|7O^g*I)P306aT(`YG$2ZA$y2qfc*%@>&|XLX$Co(dvO^ zbN&4t+pAOG-Fnp@&|v} z`<&sfSZP|NkLiOtMd?{BNlFUK@2lFR|GIMFaJ$bHTW;n9|JEE(ySyiIc2vTr{lzyv zasSt|FY2HEJaXseXXWqo#D54HT+Y9CJ3Xz3ZB~gPzd`V^i{dM6Tp!lu-2b!T+6J?F z`)S7Zk!*ay3SR9qSk1P5s1Ol&e*Nhn7$7UzAi97)1PeW~{-W z5VrMT2FsFz-w!yh)OhHd6LK_*HN@YufG0{Cd3J%A*mMbl4G_v^kcq0eHJyjJ; zul;%Ak5@Y@zPzsL!oe-}pkVfA%?HO0%rB{DX4v!f;@6Y=!80s7?@WGjhTkQ(G&DGP z>bfO5Gdx2MaP6>4ODHRsKNYocf8zhhNLGeD$I96m7PPE8y?CmbtZ>b~UI`JQSr%?} z(w?<@`NG)mE^?cHpmZu1m)6F+J9fYS;vN~j*pT~x)rn2EC9Cys_M84b@#%S)^9Nah znS9%pWzV{??%&)(%g=FA>-K-HW1I77m4=OF$@g!6;{Erpex1pe6!oC@`R!Kr7^YRT z#Vq$spKo{h^y16U-mt|m{HR_L-_69pwc`Io25#E}+g@wFxK-}HU;gC2^9&^h7Y>+T z6S?eaJ6p5t;Q50;pPb1uZ-4dZ&+HWD4KlO#SL7{c|2|=E<+_sZiQ*r=mv=tR-*B?- zj9UEho6C!Sow)7iGj-;Y&DkqDU*4Z@I(>D;=l6uC24$W~l@+$|jt!TUcZNZ2Qq-w>7&yRWlsOwY#6o@SyvAs6^(()~8RW%jE?* zU9k5_+qKs*%Q`7!;*L_b{fXH;r%rD8^yhJzt9w1u$|f0B26m0gKz(~7zIwaPN7wD% zdZ)cHn0rQS{dM0Gf%!N6H%~pj%ka+}#!W^KZFKc(r{8_J;YF4dUvR;ETOJq9iFaO# z^*^7!uzr?V*`A#VzoobSxTNC4(BORa>*w~^ysL>pFQ;$Q-tuy7x2Q{n(XP&MkX!&cYXuydTN! ziM_sVyDj^Pr1h~oUv~Us?9Z)xyNBoY7D@km^QUe+yKC+y**SBox0Sr9627sflk@6? z1>7^{{e1fBb&^^Bz1xM!F_y(Y%j5l-X6#=o;c))^Jys=^fE{ZM5_g5zH831#D4TxQ zQAzdWQ689yH0!N9}RdZneu!{4Dfk(I^cf=;Nf#SX3MlR3VSngZZDTN`t^0hck))IbJ9pVfpQS!tmstw0xVbEe!YU85*8h*1btSp7X~n zUp}q&FK8p;u}@6(jT_z`-hQL1sB{JWt>s1h)Bo3AnJ&lMd%a>&>ANR_MNW@X9PWKQd$ak}k9CzAi^AG+ z6pv4_+8x}t^0mbIr{5xfq<_%c)Hv(>H>>9QmD7HZ@LTH&5WVuAa2@wSVHwTOay$laI#oIjmXMw>G38vaL(2TJzq6 zFh|M%XV+e8^n5hQWaqxQ9YK%ov^6H0G@QA$&xOmhvtYql`MHY}K23=55O)yVo7Z(f zfn}D?4<@FhojZF?_DiNsV6Ag})^GXcqlpHyS4s$W;z+5Tjo%ItHpE=BiaIcH`(T5f;#*@tDV z2d}v*&VGFH-J?6UkM;btnaZzA8hBo=a6Rd3Q=j;I@0%|k;^MnbmY80ZUhT7NHcL7C zd`YWa=k=#570Io?KixL9!@2BP8Ar>EhxpZ{zc;LSpjZ2UW>eLNl$^Q0 zzg5i;w)2_Yy?S$|UE2TOkFqC;pOh#oEj`aF&MLmMblurGUN`ucpL8>rp%hvCNkv7) zzDZGY*2!+B%PIkO1qU?+EITA}3Lo@;kh*w(jad1K-tY}4nWu2f%GTY#_G9UlMXGED zHS6p*Dg08hWngH~D|jt?K!is*UgDa#K(CSRzW2BKS6p;sUXaskDAKTAWDi>pL-&z% z*TX`fI9(u+!;o3HPl!+Y;CIz0GtzP|9a_sG)b;Hz1H-4~zeWElEn2(ud;9aB`pTIM z^7k1Ta@-dj<7W7K{;rtV)83A>wQQ-Y+*V7mhAev5wJtv%WIQCVh?$VQcMZu}TN23}~+VQh46g#)7 zWp~N(pr12dDZMG5%&}|xjYglFPh;!D|H#UhzyJKd>g8Ac>A@LiUSYXAG z$er=qj(_aUU#DI4JNS?7Gx?d4NBFD-3uiw57Gy7;)wBE47j_4mw)_s~W$-kY z@jIBSu+Yk$>DODGYpb5H++32e&9KpY#Z0+XX+0lZADnp;TK)a~It9V!TV@n4JCopd z$U*Od@5=bY0SqO_4yDdkkTW`b=1Ri!1D+0hx}D=a&F7p+S^R%b^@2OSuM5OQL~QR^ z`aJX7WmH~v@0`xT!n3+DddEa2`#P;>s3?{E_U7TEO;Yndl#9O23B6>JRk2ra#TxvV_f(B|!6) zi<#G=iIx$27#J>0<=Gr410H2yd9VU8$^aT8;Q4NOo%8?E|9k&G_^sZJFy+FetB3F2 zee?8m{Yiy`Ewkj}O@B6c-C0yLS$W_7OZD5-QWz#ME?soAKWEy@{Zh8}C(f)+H&-_N zA{yIvZ1(H#+r4=AKK>W!sO>8MFRA|j8-+S-UZxfPZ$1dDXY1>LUUDoO*RE zuiM|Nh)jLp_Ti9+=7fV{Hau#TshLbuqA%?C;1*ru$S~>6alM6;?)f+xXxEmT43f;3D9qe5ASC-f{vU)f% z?o)N?Fx;ML$nVi{T~%elf?P|tYNkE%3=YM=3+#_b{M>ywXU)ewpA00Jd;W+sGzd?5 zAsM4mmw)_{QFp-7sf#pBLxp@D*nd3J*)E^_Cxh?dzAf{vf8XQ95vad^7DGea)Z52i zl*jzMyUtd3DZ>`l`H%m-oBlNIu+fFPY?th-Lod(JJ0ZFKHQ(ws9xm?J0&DG4=G_bl zd)INDzwc0f_{6K?bGBFPe!law4!hjslYTyFbt>g%d7ExrXbqEpZu8ssC;w6h^JPNv z>lU4R(N%2n>IrqznjX}rQh0J zY0Um(ZTs>UmQim*g?s zP7zh#I(?e#hS!}L^{0Pac4v{0^x_GLZ`TWD@DCO;dgds>z$2&oQfqST0yY&+9u8Jk zhI^_k0T=Wl-|z}OE8}EL`ocZ!Zl35xhMM~f4EZ6f{WZ@%A3l1+)0p`m1H*=S3y-m0 znNw(yezIIzHrM4^fGKZivKuSI+_Fs%|9^b?{lJg4Rkw4`gnqtnb;Ehe)0=EnzqK#xq`gm>5mx)bvg5{< zoM*N1&YVKe0**7x>d;N>kN-HOHTH4EWjh9qUq}BuS$I}?ruwwq|MwhRJyRrU)xKN% zX3u_~bni&Vsp6cr&ENeu3Co``wO2Oz6&7s#@_YJ>)$J$etz!u<+|Fio(sHWKrN#df z(r!%%zM%Kxq>^=Z@SK`U48b8O*Y9+kTDJIEc}-i6|G5qKnky}5F>ac?_uB-G^y|A5 zXBw*KeZG4*(@1K@lUtHaUpMc4l=-6Z-uvE4Ugi6r^Vw$X(r)+tSky3``4~gL%GHRr zpGql5Kl%SCPdTj7-*v|IeqRccR^_5A92(Cja?Efs@<^Q-K4V>VR1AxnshfyGq#-Nk zlB+d$lLSv*^J&rN^-l>F(e+g6U8VLy{?FH>$Qum`Stbe^46Of5kK9-gE|Y#=;qaXI z-5guo^uK<);=q06|I9TvJ>Lk8dw1jR_wf=R3%*pam@^#Ulv{Uzv%c53Kp6hk@t}QscL)ZUbdg^bbCl{XO#Fp;aw}+`= z!;Nio-yiz>Ae`@}`_163C#U|j?6djtz?P*UW^13h&C{hT_4dt}-tDG6m3a-b%Ue6= zga6|8`kntNU*+}utlqm-{pY6}E!+A1#wz>r{kFDKWmo$e%m24h|M8cn)G>9QtEsK|`{VB(fBxz9yLW6?c{f+L_0r#bJG)cc_e>~`FFrAOEC279qiyrl z=DNndlVM2XTyN9d^U05)JL&%#&M?)Z`+nDNDhm&bo1yuy`ue+!7mTaQZP$0z@ZUcF z=Fi{uYx}i@ef{>__`2td13yD||KXEKvog7Ug&Oi!`EPrE^Zv|z|4W;myH7Z~ve@+Y zYs+Kb#G;uU__OuirS<;2_wsn-3Z@Cy*cdbff+TqpEc1VgIZuhSdSV&BY+9x5`G%)= z*$!MRVSF+DGds_Ld!lXF+HTG5}KPP6l_)VRo^wk`AN z-^de(dKnn@rS6IKyZ@7W@sC~4`KIv4AFI#nme+oGw;-hXLEr%>%D0|P_J vYV$Aq_AwqXD&q@ijy?JACLdVp`RteTDrdZ#xz1B-^NtXpWp3r^g+TP}I|7+wuaUbmMmwx;-;YobIO6#b~Z{~d(DURPjbSfFe_+9gQ3jPLYb2nRs4f=FBh4H7u#Mh_Pt&j8x9H){J0UEURW3y6z8T* z%WB{-o{$I*7EnM-EaY(Jf!M^tz|gVqiNdT4vp%1-i_M z4Cb7Zd_1T4oaU*SM;FYzFst~SC(o><5LTtoZ1%M)FU=}GC;5C1-!aL=ImPEPFU?|K zc{5^m@wvzgv!1QkDKfkGT<4V8>RWe)K+FRhT6}J0+?;aX)m1;-%UeY=H$;AJ&$wgt;Koj3! z(b$WkrI*E0gUw^Vs#a*|r*wDitdD`(DoxpEN~SP3HMWOOZ`(Y3sz>v>0?M(4E5 z&RMH=F3LHz?)5H$2%dA?i&Wf;Ksm>?NChe9959q|4pKS3Nyqmy#E-TYjcr3qT*Z+i zfPvw_1Rig2IT9G8do{@PYLISdh%Npc6B-(N)x`I*N#lhHQyCZ}85o`{S$3t0Pbg`E zWv62XhvyNQqcK)5=PZutX`i6%=J{4J_>2I{))^N(TScxsipr8L4(aY)o8sZ9yX{zz z;?ouEPR?N*3=1V0_>MEm_%h3QGlL5i1_sZ|489_aXN5tv1p@=afr};%!nO{=u25-; zC>dX7lRy@eKu7_`0J7*}2;)T)s9g@it_O@=9ZW(gvIMFbi(P@HjQ&V=Ihgo5g!n?0 zk5Z!{K+6zdWME+AV_;wub6TjV&D3DQ$k6`SVUmL92a|^6$PYFZQa-{DBE)R?XR%*~ z2T0=iL0GzGU|{&*BfO0B zVoMg2&E=NNLneu^HWf#GD&nuU4p8srf zxkaOEQ6^KMi7z7q11l)l%`&`n_yRIccrhrbFdTSjG3{yPB8{$PnX^`%D%3gs*(FfK zH#jtQ`s0Xc&pQ`s%v!c;m)_}1Cg;IbRA^~z#w@t7iLZ$7Ws}g*&{*+V&pJUStXj2> z`@FF0WfR}f(%9>)i!x>{Te)i8>s=0Dg;z^s#XCS^t9Gq>%>+^u8hd?eYD4C#RjYQb z(_sz?1@k2rtXlPI*E;Rf4A)CzZ%$2(WP1SOZPH<2cyNG`LE!+0)yWl`IHY}dd|(if z+N8wL!NkDOljvo*lqXrpiECk^kCTUDN>GrN=29*vE!C+(jvh;w1Q~hhE}a&{syKC$ z*Gh#YK|z|V3=Ogt3=Ogo9Ib6@SQtJrFmNPKNjhWsT*b-D@Y$SVA;qN<#pf(niX?-Y z$Wta6KA%(U=XG*M@i|NNr734DpU;^bWc7SbF`t*_(vowQ&zDRIa(XeRILJ$LZt*!w zMg|8+Xm{oK83=`dgIkp0zynZp%~S7MmgzZZS>-(SS<5oBCN0SXi_Ee)4-NgwdC)K} ziVXyXoNuV=X;2)kT(yepvWf5IkkHUpPq&&N3b~MbEr|XLEm=3Bve#}6V~{x4%Ipx?(rdg%Wv*x+o4C{_AqEak28JHT z4#O8JQzm(Ni8}RIYN$?~7S*-Zsl$+C>5?l^Ifi2AE!h_?nG)5dx$TkV^Ce5JMD-XR zi;Ce^TskGHTX&np>>R}duz(p<`YCJa9`Q3?XT#(!V&vlh&a)>N z7zEfiZn+kqa}mfY}USKJ!movPq?%F}CZ6Ne_-%GMsOr86c^b2>dE zh$l(gu%yS(-STOO({Tv~28JdE24+DcVGa?8#zr0n3kQ!0OblGyJhF#f9USx&7av$q z;A5da*NlO|u>(Ai0BxZ`1`Awi<>L7jAg$ z-qE1P9CP7lEV~njlR#61i~}R5g~h`*^?M&$q~|OM4teDOt~%rx9xyT}++@$-^{?k!2xzG1A{SGKX}vw)UIvOF#oRU<>~Hk@8Du@@8bE{)YQVv!rIBj$j-!ZZY-;AN9V&gH{1aatI2E|F^v%aBk1Uioh%RPW^TIdC z`2T$Em&^BjDwcRxaOF*GyLQmN_dhLtroR63WZtaW?3nVMI{QOUX{|Eieeok0=x%StxJ7aM5w{l&@Xa!#p z47u@1CS#**;@Tf9|HNX`=M~>OKmW3AU2*;Ey}yp0i@PCWqq{}M-o8cjYy7Q*GdmVW zwMmxVzm@Q%W`XbbhRnr6Gj-PVG`x;r@!4yi7qC^#_1G#`WzoBFS7ueX2ro*Jt9tR%V|0 zKaD38|8F&uvHPs9@cb{k@!eZh%0U7?6S7zulGY@wUDYAhtNpz8qIQsD|Hh6kwzoG| zZ`yq?ur({eWrac?bJ7!a2A1j1^SdfeFpEmY%-gT|NRdC}$=a1yL_OAMFgRS5%4S{N zbu4US>5Xk^q4!s4F?C&A)UnNxGfd-&fv6$h7GLf?)2{XhrGG#4BPy(Z#b)~P+RR$ z%zw7zcar;NbQJ$(_mOv)aL0||3d54ljWTivE-Nn5Q1U9gC(_{-qJ8Q5x9z{n^4nia z-FnC+$LZ;^@Q24+oRWfdbqiYy{PzaLAU5%2Zn)`5*rtZu3e;c{q0*(t&lxajBd&5t>04`%qa9n_G|eau?OrN|N4Ge=W%~v zuGusxb!(pFmFR^5DNENZcA292S%zhakaAhU5uImCMCGS=s)5P{<*>CYBvywBtl7Fq zYt^wXhNRV59hupNt~y~pq0PC0BFU_dN4XXSZ)^$;T>2`e)?uCfeU->_zc(+KJ$r45 z=&GMiEh~OqvT6^$BqTL!!N#=_i~=cNV~=0Xnf^|+t=s4-XMa~rW%_mTg}Ep1CVJ_u z*LS)-Y4_oh?p>)f8#gdaVPbFzxuSJVDo1n;U zFDJgzJ+0rE_i6j#3IztsIf4ufQVlEHcCoqFGDHo#lops?>u{aD-g@V(-~{U_MjNcBJUYiHGX1vshU)5wEw2%Eg)!U9U`i;S%Di`*qs3MTf;gIrq#^5LuNGdeKQ-ljnEW zDe-hG)+N(^ZeF`(V*IkOm8t)7v~!XG``Te4G{qycxh{9MQjq(bHL7WT?lNf)bvG7{( zh+kVI8oE&aMsE~(Em(Wq0)*8KA@U7P^D4BC2DI|h3Pek$mHQQsA5H4nVk8xKEo#jR5n1h(p**g)5AEVo;^=S;YjE69!RX8@)xBz? zq1G{_sK%=u+a??mGwYU(aOB{VS@lunm7>Q_Pd@242bvDdQm}VmXi%L%)Rj)%sg=r^ zo44PZwax9)hOJxk56oJ&O>DKY*qgUrDeaEBqPk(GQmz{noHV!e9Ok;!#mUevu!3Pv z8=Gesb6G>l@vymFNg0B+j{-M#bxl%QuyLh?f=S1O4O4$-J6+tK;wQj*(L?Qw=H^Fh ze+E3})LgiES8IR%ZuLzu7tY_{*sy@(_Es4?6An%$g)I&WObkLTmn=kB-ISeM3M$`d zeecu=TR&~Pl8xqCk4*{(mM|CTgl2ZLFs+@E>wdHJO4qrI?P|PE+6-oHf406p(#*&( z@6X&D;kSJZwf-$>OL>1}->tN+nIET0z2ED!`)c1riRdtPcEduM4p~memC{prK%;eA z4z5xCyk&0f-Imzq8){dNoZG?@&g<>DVd~YybX{dh6K)@GX`!u?vb9z%3t)6jzSYrj zQDfB=vnI1Gve!8U6&>5SPQ^L3Fg81%^r+lpa`94mVDo-!busZ>+qNEdnf7tD(XG$F zGn&0JbZ;g;7fNo9i_2Q5`n>-3uM=E%cc!sUVCqo|6^ZG{x|JTHqPcEY+M>PNEhg(c z>6A+`-zIFKAoV)KVFs(W#9WojvWqV0^6-l`ersx-7?z+CZNR%Ce2Kej_QaYke~&hq z)v7SedlUOI{I<{Lhx{J@&V5-vbJ-5he>w%H%@(cI=bbJ7eu?stL!A|(_g9@(VPIfL zU{RmeQn5T#n*UArQAfi`W;df+uYCCSQSjQ`t!8OkvM=v)TxOU$Gx5U8m06{06hq20 z1FW|MUJ%;5jypSZb3pEOrf1oEJEzHpu6DkCWaEabMT;(!G>R=bs&C=4P0HzH97FWN z4QX3-J)E-znIBC!Ak-Kpb^FF7rX_*_+omo2vEi!xBB!s{D*_T&BrFxpPaM%=-Xs#` zQKvXrPB7~cd%D&FmF9p?kM?Ss91Qc$#2zWPPHlX2p5^2n*ShVoVjBO>6r6wK zGyAIg%{?nj&4r!jc9^d$oe9ba2lnL}Oj>$Q>gTKr0`_t}<5buIL4ySQrpp%*KzaB!`d)+*ECU{sh`*m`BfqFHNl!{4|~@e1^cjb6sO(nLyY z!vQt{kH{GcYB?9B6kMD$TD!GbSd=}(BpA}n*ElVAJfy)QZOJ8l((S;bv+KB+B(m=` zpO_P(YSf#ny4a>k+a}|rMv(u$O$S>TZwR!kaqi;(JdK%ojbxC)N>x4~fysOf z`X1Ve`mTvKmC_r%ER~g51)CF6cmz&!Mue@opkc&j#G-Sh`dmayuqYeDJsG<%?@c5d z%s^=4?wXd&2^Ww_@1QGNxXrEH<9iHBBg<+-N1MnY2cjSzR#^B0SH!W>p-?NTUM==x%% zplZw{rRhe8wV1418bvl4eS2ki);iImjD^j!tVMxGbD7VB(l);}3Cd!ts|3}>)LIJ! zSa!&!yb$6Ll}=q6t2jlN5Mbm>#$gHGrMP~y0oYA%4Hl{C5|^HweE{w!sE-D zygh+y*@V*ul8dhF_~LogGiuhf`A&TIWbU1sKZW;zbOu}gQU7JW2c&mAnf3YDy|OKS zXQZ-L>47SU1G9_6C!fpOq?h=+#`%y#M6Kn8Y3pTy1A8sGpSXAF=*l;Zw@ADuFy8d2B%6+M&?DF3_LqT6pVoLcZ=`4m+*;qI?(c0r4GA z!#-HwRe8YvL&WsyV$;wo_2z|NPrY2cOvtbL&b;ki1rrpv8%Eu4GhMYz%LCMwu-)PK z-~n{dXJfmo2Q^Rr6x*naQ6vcn9Qr^)0$~ zqU4^`8l9h#jyjA@oV~geiW$Q~{aPd?6y5|aEZL*6F*RY+p_qWB5z3e3E;)s9a=%gV zbAPE+&~rdV(;<^_v8Zyh;fw%7ku8izH$5_F643E(WmQma3GhkKY2#ARZCJjP>GjsT zm#1$KXdh!>P}g^OGQoS2(=St#A2oeuVXO}yaRhIQI51J1J+R*^=IrR;7m_955&^D6c3 z@8sUr-*U1xIX~0d)Y`mUJ|ZfmF*5u0>qX00@8sQXpL8kfe7{m!{*M1i&VEr6_71IE zIU2UI{HU9Jvt(wDZ2yVt@`V@UUE@TTu5)v{xJZFR#Dz;m)b+|%k>v@TVy1ULANsTB zvdrhY75~4pewp>#_*ls#`8r#*`N!EGsN_#veVTv6R3?Twsf^d8_f1^HdU8wAr3%rd zL918wIq8ZTa(iV57O93xyKKq0(6vOBRrp3%n81u8rdzjT&&+RNzIR}K`Ni4GA1

    fi2+F`DDlM3qD;>KE8SIT_JJJOlE&)y@VeHM&j40?Xh%$9l5EER>*e$~1@Rf;Ag&}|A(du7>eG@jiv-JU;lRC#)) zR6JGco_5%~dwKcg9~K^Wm%Vpx<;=ZhH%=Os-gbgvJL$3OO+yX?i;b;10fLRqYc}1~zmmZx%b=mv?WQnUDTakvXNBkAIIS3l z#1;di6B`BE7|!}#nqU^aEPz2>;seusC#{OWJ$b8KF1*owaQUvrmi=q|-Zm}se|v9D z%lEEWZMiS040V5OkIdJR`M@@Bue5RfrKQb}c=s5mp0~+db2!m1{jox3e)`_ls?4la zlR&xdLR3w;bjYEZen#=qx4%y9{=PDEkJRGDR>?ZIJAWDcJ5(SWxohf=uXYxfCg~kM zC!?0!a^%!XfvSro)^XvJls?Wn$z{^gx1o7i&X$tKOrEQJn+l!eigX%9eI;hH2%lJZ zr8H_%d~;BTOj3IC5iYmJ$dskq9<^>evSx|iRS{RG;2n(&(L7#N8z){o)b+S!ZP3wa zzmBzw?AN-I>3WpQ>=45?Yn9_$!WUmTG9mQVhielzt1j*9o9K1Yh%t`!vT2BjHA8>V zq&FTFH(g#bGR%^EBUvHA9ue->m{YoMr+ht2BeUkqKM4%;c=kP-Una@Cr!oD*vDxoi zI1dO{oeSY1RwSme`p-Vvla$tqeGUw*Ej>ehBo8sr!WOn>ymH)hc zSGB=>AHI9(iLc&~8HcZ;$F*WAc%o7}z%_{AMUz=9>h^*ne+7~36U3J!#VcU@%6K^F(oNUU- z6f(%pX!7#V-=xd=&|vF~L(5pToOqZfu#_mUwXd+A`5=nbOL3|5gnirpe*a$>BoWqS zqFtJ)5a?^w;>W@?L21Lpmg@xxJ#7MHTU-v-Rxu>;axK}( zDz>EfiE6`nW*de8hPpdW+S$ea_D6wQtmqtQne<85kHE zT+ipa+glbrxSz}W-&ijClga;|*W@ zP3hB#zAI<04P5YGlgG3*OV2;sbuHB-Hg~O-lR0CvRD?3a`apHPlZO~KHHj?_3qNGS z9FbAD*f3ACMTJ4aQNw+kw8u`_2Ej{QZVqo2`6zbF=tfLfEWyz;HAF$z{I%dZeKn_e zNoEHtgNPswrs-T8TpujXW!}Of(#;si{9wW)zXhgxQi+oKdK?NqipdUAl2-!^FD!ME zNEBks<^C2BE+%#@G1z*8rr3#tMqx>;l_pJ7^ST5toXc^)c}rmhGjpQ=bKM);BlBNQ zjrt5OrOj=k~$Pw6j>D7rT+8Nw4v(#Q6 zYQ8YH7Yu&rQ;}l0riPa%^HQdy<90vO6p-~Bkh#qa>{nJnwS z`mt6S^E!S`2`*Ll+hb+?b&dGr-^;`0db@w5{nPsuIBl=_VY@#$YaeDWTczd+>UgR> z{w?$W?SAc#u1|j1#(n!Q`mXNv?-LO(t<$f~Za=wd{gl{Qf4@EYx_9Hso$)SW9ETLj zOqA8P&sw5*(RYz!cJj=aR_OwUCBo(>7BNMuCjLDjkTUr!gArGAVM5ha0m(dvr}^iu z?wVN<`Eo^6Sl^kbvaScuS`%H|+`@d_*D#h{{lEQdVp`5@$vYAoc$tsQOxDk;@V9+( zYl*|W&W)4IB@_#oR2cq*axgKl%wH}q{6)7#^T(ZfpC^@#26hZbB^el|oMC=B-Qtz^ ze#fb=)w{B*ojz^&yS~L=M*PR7_Xb|)C*6N5QO_JLGX4Afg8dyWhLtsS%o`25b88sI zx)>Q^loU+fzxb8h$yB!U^ujwoc2xZP{mVagTJoyrtt+kt38=<}-%9ceQ(x-%_ z-(3sLHDS0?cUzzNSKrc-sfQnaWPi~q>U}wMf04~3O9_Sp9_6bt`$G$39$&sR` zX}yoQFI`}tlJ>J+ROI7H`F0*Y|NmVw(pQ{qYZ;9F7#S+3HKmAu<@a~l&*WnenY_F{ z!*unk!&_d<{y%VY#|POz6-7y_-c)atWMx?MT0YtD-yfytw+o-+i>Br;;b_X08{&X#`-|*{N>|(q8!>{$%Za%AY{S|A5 z87o6d_(AQ*eLcOacV+H;e>(g3>Fh^mi~nwzxz<0`yTtwf!=1mY?w$X9X|vc|&%*Ny zqaACWu=7kmE?VxL1k%vr+Tmv$dg#)-3o5|j0{WI&jzslybkxs1V=DqfhJEF^VnSF&O6GMWc z`Hv+1uk)=s_%E#T-yLv6w05g|==>m2zZF-)TQw7wW;sq=q`DzFeHrsdLxx?q=YCx8 z!{idr{iZ1V&s@Kz2fYUN3=KA=+deN0aZ{{*VwcWyf1B89S9TM_>yAn%r}eB2XL^#V>bF`bUB*FpqeFhxDh=Ov zY+8{VMpD|TvSLp(w8MR;3z>K*NG#`MHePVGe4$v;pl&Mim%S*#JO@582 z7d(&abM(C4Zh7CT_NpHgZi4447{4JJGrb()OBHfHN)r4 zB!x>t>#wD-&y-_sHWK~y=#jx(_iha}(HN#I&8rSmWUj7in7&1op?S*DRU0qGK4Nf7 z%JE?h>M87FXn3ab$1O#xP_bRCezoI9G1v4weRtMn|~qw`7Y$VQv0 zwk=8y!5gi7)z+MvQ*ivzi;Kqn7c>JcSigld@*G>hqP6U{<&N4mH#Igj;SZWe760A2 z>+)Isu7+^lf}7RT>y4KhK437P{c?6{$GyB{9($>+W+9=Vx`@Fq+iBCoq-S>+|Gxgc zS94Q!@w)Zd`3d>A{`~lVcfQn|{L1sMe6lZ1oxSVT+2`%ou1t^rS7>7sUp3n`{a5ki z?3bTjBrgdFxc($=(wX^*_KD|p4leUQRaNv#;cBq+WWi-&X`608);aA_8+#`<_GYU= z!Y#2_|9d<0l&b=>3Oh}dc1-W8=3KdV%iXn6VvL5`t8cHiUZ=Lqm3{J(r3wz)4ldF> z^wN>>%E~7j?php?3OrU`c%Zj8yL4;Y zO_no%pXB{d{7}OeeSPJ{z`tE-lU3t+c{=2RIyJg!|zMibG+?eZDweM2U+3e>b z@kKi3Q#GC_zq_Fnll@W3k4;rSI+%H#b$FKN&KE}4E}!FDabt?J*M*BG*$nztU28oM zaVT-_f;QEThJ`XoUIG`D(z=x0u9~w7F1#zCFUfHrbcYQ`#>0S_Q(8|oa4x*-;*!F= z$cBT<)Qo8{hr@;>o=icNhz(UP$9x?mg_>1_dUM+?7gDS1*z2{=d$DjsH^r zrT#1a7yhqQd|h;o!28m!at6B?o%Ym7j!nF6?OWOB#(7OF)qTXNs3^z7Fz?RZ%l2m{ z9cz&G_;&B;{cj%0Dt8VnT+gdFIbm+@?F~^YR;7R}ZvHBM_4fw<&;5R#{)?|1d*{0A z;+cu&^0U89dzQOO(tY;tO$w`f&2ByFF^F0Wg()gWX+hoR}| zq~(V>7ld0WakTlUT|N4;FhMC(guVBqz{%K!(dRZ!eD_mM{hAF5o+0Z4@ z96ryTb;FHo%Oo2GxUK!T&E?K7@h*6zv%~y=+<&`+RXfU0Fu!0~z;5?u@1wKnyG7J) zGPdn4|CV02X2Bzd?`*ebrmlXt_4gZrpJq|Pp;JLq7Yx4-?lL*vb1rrb-{Z$JANK$K z=5PM>JO8|>=k`L!yZ=>PU4JLG`nPY<_YeNh&CMU1Oa5v9Hetr?>vJm9?h0$kTM>StoQdsK1sIaxul!=3*%}pSAm5pi$>swWoGg+%AR=G4drlnp9 znfItmX?|g^@he`5!lDiLey6Q8em_H$*~4~6na$RA=F^9mbTs5xf*Iz$xy$lvckHnn z1>9{Z@6|5ce>-nZ^Cy;fzLr*J-wCA6UiY-w!vEGq>HZ-!+x}?(x;X_T;^m5d3Z= zHSb-XP;l_Mjs9{1oD)q?U%7Qo)S5B-Vxvds;x8KO=EMlNB)`dK+ZDdmxFk9H=1tj> za~B?qGAIjipS{)1-4Yp?7BE#{Lz<9!PR`!wgp{@`f>O6PN`-b`(3w!s)P3OcN)5+Z zZthEZ@@{4`x@o5hdY$lQkmX8d?pj)+oa`_wbjo6jz(B5zQ4*0e&+#8-(?2BN&|N#} z_tN*Qa!>ZQSvKBS&CM3ECRKJ$aPo6Ov@jhf!(20JWI?yz_g@NLCx>!NgP@A@AvL+3}PM6CHAEIN4KmAH(XmiHb%E7JAI%W9fRLlD(H9ih z!=#?*G_fuSNeVE?}WajPMWTIy*yj|jG>{G7PCka!hCn^>_ zVAz==8d&^v@hU!%Q(On5w(6~BSoG2->cD}$eQUnzK0Uj$Bk|ZhMv+Sn$Ije1-Yl^o zJ3&$uKclOTSe{(G(--SDSPoCYJykJKo_wBl6wO6+DX8VSQf=0_4j#J^>Tj`K!qX_W`0;1the4XZY+CXekjEeyA5H%pM$(*>i2?vI&L38)k4F@D!Nkq39@9=wckZ zFCg<9UxDl=?~9k}w#rC=SG!4_RX z=beYjKA+gyt;YT5*Mp4(Qor}yU_RZ{{Xu>Cy2BC-dc1GHmm7S0wXyB6FvGk*wHwaf zj^22WMv+2lvPCGrv~FH)H;d&GoU`H~-9aRg1rW@&8%5 z(}%TxPg+x(^2@L;MpCEg$-|9bX03}Bd3M}yWu*2&!*s5-pDqhoKI#*^D*1Xs(eqg* zMS6v^7EKgy?&>*Oa_rQ}M5De-r?sZ=b5CmvmqvM|wbjl%P+%#Dvb zf~Fmo3ba+&u3ez)qQTwDXebe2ntLlyqhTA*v88kNo@5Qr%Xo4^M4@}4@X%s}yjJJJp(*xx*&TJ+#e?8@Ww^x{nY9Q=|5FJ)P~1w!?A-*GTUy%mwkWy!Da*Vg9HcJh=dId zDZQ<%U2UxM?%YlJn7*sGA%pqk?e=>$zm_&VW4L}nUU0gyYj)o@-nA=NLRvp|2k&k5 zxn4i_`lQt_YnwN8A6rxZy>?&yXHW6v z9{q0fZu=g88}@Qm)2pT8Vy3(HU8_nhFuHWIW%fPQRLlM@jaPpDM;}M++WbmUxW?GS z`^$r`+ct0Yn9}~zt2F7Uli$&7QCS_q5SeusG?<*je7|x#rU^(Kj|-M$>Gk#5Boewd zB;-?z-q%YB(;fe+ylHs6M04F1yOP+6P3{usCroOQm9m!#Q%o(nj_Gn^e7 z?Bd_cmag&QOkMrxN_|g@A=^_|-q0TJ-3%M|$#vZj{d~iD!#vhy7ZT!a_sW#*DK*g9 zyh4XnBZ0B*&Rvo3*4_pkY6WL%PujmtX7QMP+FEgq|2(<)ch390Uxw(OFK$k&dcW5d zwC!yIsD~%8_vN>1Z$H-=|1piz5wBlgc=C2VyVljKZ!?mAUJrMgb5B*OZc%-VeZ9xt zch&D@zaB0Bcqn!9t4rsv@3sGyyR%^D`|E!u++-_qx&LMVtE8pV3-iPG-{CWlQR`vj z<$YdrR7TAx$^Py{MY+pUC!h1XHt#XRG~vs|g*qpAdiRK(PFa{AxZ?Fb3-6ta^JjM2 z=NSd+2`^Yt{Vn3$gl#^)m$IvG-`F0fs#OqmVY}8!?oA1kx5Umi5-r~9m8`zlJW+R< zjm`77?u!4eMHg?sd)WVGZu?i)K8JbFCm;R5ZnvXpZB=oC!|aC#`BG0A=rC|I6cn6i zusOgukEgEl{mbH~Cbym`-~3&)Kh1q=)0WB@>BXtHrZe@sjm>{|H*>GwH}>WC)YsPi=UM&r)W-9V5~Ke-oB92J$$z=W&u3SCoPKlT zfg|o;)?O%k|72V3zl`4>@;26Q`%$Cv?BtA+hth}kch41x`}gLNmUPiR)9aR!R?Abq z_AChdCwj)Fct`UVxlPk9_f(`LP2imQ_w?Dq_e%@A6#G_b@!B>A?>u@YSvOIj=~|1N zByZHx=_}NZ&U>`dW4E%Dl9yg%!MxcwC%(BA(K6R>cKC@YcY8wg*6OO?WfwT0BDRmA zr?pk@jZ{M5v5E#p?j4NnY#TN(7%(t1FdSf%VP=q+$9RB|%?4BurF^uOcXFP6ps0NE z*ZZGZ8KrmJ{Fi2tCX|z%y{OGCG&FP)r~pz~mh|V3yxrZ{y_P5T)_+VlPks4Ty>Im^ zgTih9p1l41S%12_wf*C1kK>p9tgU;Ic|U8X{da`}-#|_ngj@KCxpm4yC{cg2o0N9?n_Js$i;Xj*bDev) zEaRE0edYVUBP(7AYVYManxeOCW{z5Q)F!b*aT2<61-fgtK8U(yb7Jb;(1&8Pi{`%IWX$mQ?0RJ)&@?!OlF`ZT|jwtPj>~OzS$IewU${ouNSZ z+MxzphBF(!J!F{1%EQoY?!d&uVE5*3%E#4}v6ihHD_P3pe}#WmIA9ZVFHk^6PdzGf zUa*yBd#%|kcaxA%&Xo$F#UC7#pQd#_<2^6?`&Zr1+Mi+D-*54m7Ww+^!P9#m%iEux ze`)s<<@Ea6;_TxyKF=@7>V9+jSHqp6_~lIZtHZgqg|Jvi!0v z6Hg?q)eM+y!pnB~=&RS4dRzVZ3fRi8^;D%_V`67xcwlh$9MkKB#-|eJW-vDB>jW2^ zZ(?SMImp0p&jFNhME+KnakKd-?A)#S>wL))gG8q9GhS@IEvA^eZ}GlWt5&Vj0`C~G z3fR1QcCr7yNnbagj@mA_H2!pNd-IOAEmy98x7N@3-+6prb>?QRYYC~=PwVYot+0=; zTlw?L+uwfo=Ea*u|FrpeIb3PZ?$hp1E`9mp{YHAnf6?RXw*L}%a_H*aszpma*!XT% z+1&iZkKxJ5#)k$bTz7PqEL(ntQ`TzEN*9;44wjt<%6M$sa@J~Sc;`m$ma&?9b&`sq z%7GrmlBLy!Kipa*`53adu8LCOVdkIrC@q_jbD2Q-%tp`h!r#2FCvVI?vunQO2g?tK z-`z-cS7NW|Hh*KlCezQ{%-F0g)}DBS?E@PR-!+kc1$y&X=bfqDz5lXq3p2CFv%FRR zFPAAcaNf!3lWqUUfDaze-HP5-&))y`0saqdr;)QtJhzf-nP-}-J-#NS#)Q8*|WRtvt;&( z%$3}~|Hq3?%bnSO=Bnpi?^95HwCjYdq<(t-q#s7PGn1Cpq))z*!l%!WS@`qA8O6-0 zS)Iz+V&#VEoT>MYPI$HEK^)uERXa*_mu`9#lj^HJqjY1K@|i1MsT{t{U#4uAYu~BR z_w;e{<`2srCK)B$W`A_FEqEvABmZ7MY1s|kZ1YsX^2tXcmDD%uiRD*8heK|F{0CW} z!N$PAa3Li`Pgdu@(tq*)Cja&Ri~pDVFa2NZKlgvd|BC;0|C|4}Nv}x1acquj(YuGr zZgY$ee|$4FI{(Rsybafw<=9_KKKS5Yzz~!0ZJH+s4};LYJGH;#-}Y_VXfA*9&h{T0 z8}&raC|jH^Tz|u^icj)p+1;bc8Mkj5fQoVzP`i7BK=QV&>;795yg2sibkyB63yC}C z@`sLGyka%-bJIEiZm6tort2#^1`MdHbs0u*E+qGPu56=IPI$Kj)Tzs$O@` z`oTo|t!kH-b~W#9EtYCqvVU@Uti|TSO?5u!Os`HT_fL|V>wWpi^@YnnPQCj2u+4=S zi@72@6l*xdmAy`ArO(OUt}4g$U}MLeZ5}!o<_ zhM|t}S`uT0#d(8o4dsV(nQU}UAF?lCkO1Y%l<&Luur_BzC*1sPQa?MMD zElFODwOb5tUy@q23N#JLz{8nYT2%Ts=S{+?NB2K3-uuyTdhMe7YfY{_lKFm2{+z+) z1Af0hVfkjLq!h{(L^f`DnY9mo0i_m}xei>+F93Bj zTu}E^FUj20VWUB`Z~gwomwopX{rBlS(R1S6ob2;1-@+WeseCb4zjptb#gsca*z#H4svn{MmdaeRcw&$zeRJn&1*N`B z|FqY$Ggquy)+3tKP}rX z&R*5}+sp5Kr%%-{{rvjnH2MFZ^IlJ}`*eR|ZINAVejU4{fyC`9?wejaax|D`-H&E3 z`P*@4dYXNz%x&+}-#)Lgcy6-$*^}BI)#>{G?QCs+7a#sDUl^|DTjw9VyWT6<(rVdp z?k^kkA{U2=Z58)CFt5d-=(@^-IbBw(wb!k9Sz)2K?nL?t!$d2d-wjt^|F3ymusBA2 z-3OyDJ?3|rC(kS8sbRf%-0n5w<5#&%GC!o>P5vx*OmaqKnQit)iw_O)QWT7c|7`ynZ0j;J4+b2#W-0U@heTRU2OojdrEOpu+$6%zFW9m!3V2%YQHTc#+@6 z-iyB`My^=3iVHkeaw{}xo{#muda>CuKG)|N-)jH=!*;KYZBa(-nZ-Y&%iL<~`G5M? z7naoYuM4D)ybkp6M^MCrn-4!8kMT!h)FxU%pwzuyS7DYCUJo zml_Km=q!1}!sMaM&3^M;=8{Nl1)sTB-1h7bf5Da@b7R3wBiYICwp`-hT(DZli-+BS z&Ah5>(azS*rR5JUFf^ZKx8hQFOme{Z;vcfO+k#HSfGiHQ>Po<0@1vM0w~{OPJYr~KF_ zXGZYw?|SlkpUj5)eltGZIriAD@cp7)SG%W8S+v~ZWa0Knf(EbWjLC|UAujnU@s zQpd9^theQch5euThHYDw__p5I$lSA^ZYl)5xG193lH%^kysg_vV2jJdzy+;kFHH4r z8ykPiJ>0q0nD2AV$IC97u@jp#f+no&IJdIv{!aDmYm2&=MFRF5KNpp7uqV?aLabuL z0fqwp8@fCR8y{Y{gRi@dfZ4~-tMQ*!C5@<`QzwEKX&d8 z+U!4f=Be<=Br!{`M~APuu$&3fy zpFbe+!R^37%jW`O2O4~t4H$$O=AF4~^0B&XdXte^-)S83X4viEW?P><*p6TKvuW;LK~MPVngM-|DY7m4D`$s$YGHm(F#sTE}3t zl@Kc%xbciz99Jp1J; z+nXiRIx5cBp4j}Jk3Cz4&meB&!?s)tizbQVi91q%9C~~srcVCw<}#M_70(%Rq$9rf zdmlJ@-~s<*#)8A~2?rKFkYuiVbGPKXp>1qK*@=}Z<>q(m&)o}RJ2h>Nv*nAb_ATd^ zd}Ug=swE^;71SV$c%_%V>fp(zHP(^)PTgCTnQ8cGlkVl_JO3{fe7nEl)q#ym*>CUr z={RZ6XOr!#|CZj1tg}_O*Das4_Q=NUn$5L;)_DK)tcx@2JoI;NfW}1I+p@A>a#qyV z8s%rb=xXKrRTXSoUg|G%c9Afj>~vGsmHuHX+qT;mo^0LonYGl|y|VnAD=pOU-WB1 zyQP5+0|O6R!%+sY1jYn|1JVtx76%w24lpq=6fi`HHM6f_VvsxY*J%D*Ij$|feyTfv zi`u8xhcC!^<4}28_SeIYR+pdq8&BH$b^r6PhcC|rbxRZ&L95hF%6q3iE}Z{T&Ck~7 zHsj;3k0Q#St^GHnrDp5Lx8^5*q~3YA@#@}hIsc1iP4d0owa4H@&(E75zog%tA1u>7 zw2_w5M@Lmz?O z#)r$(CHc;{`_&)XTd4g(&hG8YNW*)Uc6G;=sloZHz1o^X~jzHUF~h)Xt3`T@1hP-m^UT&@qdY z$h?(b1H%2!+5CUC;&r+FHs0AYSFKvG$_vywY`AQxKYR9J`S0`oSE+Gye|3KDpIi9XAnSLx{gp@0-EYt4*joL8zc}}S^2+$j)93X+ zE)JRYZ?12IgWPW2>oLXF^9^O6$o{vkTKsv{`Y5U5m@;$Q+~(^$mp>PfGMk zbKd>cv+rpwoTjtXAN*Jl-F~z@V%dg2kzzMer$6PrCgFJCzHtL%KWj1rx7plchKd`<@}67w zF~__=$Y67)o%Mk1hK6VfewpJ8c6;vf{ItBg&}52k$u#B4-7i0$7Teum!e=>k_SLOn z?J`j-uia{2vH6}!NNA`ksIRZ__2d!Z(_O#+oX;-3^8KU1=8u2OFPnest;(-IcJqDL znU9aRmHq!aTYu7Lb-w*y-_4%?u5MR-hjaJkjlSFJn=30{|E)WCdj8t~h4(7&ziQ+Wv#>q?wU*La!(vR{mbjm*`8E69#OWf<3|!-v0|rz(3Gfz z2?`gOSb{cKB*m&VUd>`y5P7F*frF@vwq$WpP0fyOm3GFgs#nI}ESvIzm+x4wUl!_j zZAFE&&-udZ#(Hax&iH9rcglF#mwYW-*?x1=jqiJF z?;SEQUR}Mv>tD*Q3l-L#t3B@@=9)C|)7~53?KaI@vTG5y=+|!tRxVq$Z1s&f_+J>T^KWiv(x&`T{;g6*VJ;${QsiJaG&>p<&PWb zb6Oki+2r3sbJ)7TTe zD%F#Y{@F4^(obu1v1_Dz`m&gr_1#NFu6ykcpUj|noRy&=c$R{s`I?0rW|-Z(yKSdV zlIXrm5#PFxKjYe6CT==8#i+9~>%feeZGDcf7^m-AwR81qHTH}JRSXjME2hkT{_w+@ z!sxFv8p`YU$(+vLxw1G*rt$l6{WCxRtzzU3@A#O&z3Ev`^4V#|>Ce_|w%A`UTX)@} z;fe(VZvbrL2L~gl9s{2=!OpxP?lKZIvy?r0Oa6P=AvFgJ5t-u)?{ZAPXJ_?#cI1jxGrhVP85kPQ?wTCw z{n+hO;rp-0rmkG5x%)e&w-6KL3xoi@x74Z_|`$li*sFxQqLLVLXZ}9EGeze#Brq_=&H1}D{_^dqzI?N}j!j(iw{QNo z4cY;Gmc7|B#+$lpEv;{D;0O(ctcLo*Ci;55@7+jl3n^zspJwLAElj`1^#`D)XZTH*EAFLm{_@2&X?{ly3|Jlp- z=kz_}qsjjTj(;gCtewN6`07M{t@ZPyXG^SCdU4Giw>zE(h;M%4 z9xreIDu`#&@#{fc*Lt>c7;Q*SNoHtpQgjq9pRm(Vw&kM9%0*Ti88;Q2HCVY_?OX1F zFSnnZ4SKDzGX2Dv>4i?acDY|LWs&-_@uGHPYXz)TbFs_mD z-s-zsekK1ZOPqXZVbj7lS^J;5e=c>LbnN1;Vl(sa)#pXNzDrsw!7e&syP4E7(4YgT zJ<`w;w)XnGQ^lK4TEBMLcjwvD)0W|Nb`_bsJ!Vi3zRiWjOcnFr2aq=idBtS<(lI1<&uz`IfHrQn8?N^}An-b{q4(w&6csclWOB zyyqLPPSftMHQ2z=_xQ}FfG^XwKR9!=WI{5B96Nu*zTby8y%FpCYVhycZTs1$?JL6N z?=!Nz@yu6w#}GH?Z(sb`{Zqm^k7tTMUL3JI^YL9M}?ZNt2}OaBW$rp%Y|{nu@?z3BUC{TGWD z&#Sckxm?uO?Ph3g?e}$C=GZSi{kCY|x!OI~nCi1HE_zeWKkrig&S!EF7Vp2mo$F$n ze|geg)^`i!-?Vq}h}Zl3g1{6o-b|9#h=ulu#Lt?%-x zlP?QjA6%*szHGCMy9RsH$%Tb&j}kPvmDpb|IMkrWc1DFGL6YU>!`IsPf9k#ecHxVI zQ|YyN^LeEho}M(T`L?prf6smW2N8GPM!V0Lmw12w_OQQc6HYf=e)iKrFV~s*{rpp! zMF&%!-TE>6Cxcz&j)V_$PagDfx+cGA`T9FozAY^`JlH+=bmZL9G)p~EuF#HRB?gT) zZtsl@42_I(HFwWETl{ynQR3v_pIh^y{@>lRR6$~z&hgwYcUR38&U1WIw=UN>`*4=v zloTNbh69!f>t_5vFB7F}*8hKdv7h?6t>5dX{P?ebvi*1Ojo#nK+>^im{`u45i_W~g z`)1yMl6AJIYsN|Yv(S;@kIB?zf`LfmIX%zBEr0jH4LaNEYt}q|?!DgXkNNw@-?#3u&p&(oXR6-LP`^K+kM7xS_A|1<_};wknHe{O@5m#yZM)|Ol^&eRT3d9&T>j~qxqH7fQYDTazel^(dKy~q8~0ixly=(#%^w-nc|ZQxz_i7zjyne z-g&o%!tS=KYh|n^KT1CO@q2^lVT)%@GZZcEJ>vSz@W0sNRA|A^$FFbN)v+^If4cT# z!9D(?QQbceZmNjrR(Qre|NtAyGpxZi@k_R;)2jwtoyR>`aC+#_U@EV$z-l3 zp_sd8-fgb&cI@!gTwZt~ep%nzuX7hAZZ+82u|R@>f#GZY*^>0)w>i4$zo(yTzP82l z+ulzL>RudpZ~x@ma^rXUpZM!5zZ_Z7>JmHu?8*53yph#c;`EF+7KcBcao=A})^_gq zx0XxKRSDI_n?{CgdQg+?b?ayB?gg*U*TkoXA6;e1FBTiDm!xu9M{Tpf57Tv9(|`T- z_gyu&_~QN<=cF$R9QJTxEb4vPUZWtsF0zY4LbGc%o0UDW% zcsfc{;PKL`kg0F(%SxawY@ZZA@AIY0`Mf-`u_dAYn{U{fSv%&CRvn^x8}I z`ZmkvrkMu!P7ne09+MV(?oTTI6aJ`S@8zWE>DTY)`R%c<`8-{^us(kC{mbn88&}-E zohuV^w(#G{IJ<8%zNFQeKYQ-I+(!OybRggE6E>5jcmMH}vo4Eo;wa}Wwh`T_wX)}@ zy=g`KstOSv$4xIz3jLgX!@+jxyO-t4k4*Ips&DQ!6rL5i>V?~koeR6!l0v(-$y%C( zbr{b%%EZvd!|`P4R=sA%Ee{S_=9Fw=uR0u~f7kT)_kHW_p6s~To*1;dxV|eaG&ksq z;q3B;X*aCz+-RS;uYBY31&R3wHA%9HckAYHh{(M3Rr!Or@w&X>cM zZvZ&BdHAaR5Zzj*;{rdWI zwSLYsqea?Ty@kE$zux`PmA2QuJdW z-r>jp9ACPO?O8zV{a@2#{)YMXhTd?s3-6t~QB>pfL8YzI>?(I>a54F?TE61CsZq>z zVBhEDdR@Kb>sF3ud?NmtSNwA?E`7iF=H(-IR=jna`@-1upX9^k!kbK%StlxAee*@< z$=7K&!!O>PY+3#OUyb<=jt}COYghi>X`LNjYLe`3^LiU)+2(CH$gq;F}(a>QtfGla^+%n*{`&nqwfka>kU{9~vuPDOECN ztUDCldPSkc;?E&Q_J7@Xb^e*w`eqjBuoh{a%X{`E>wm0c!G`8%avQf;{rVfeq5s## zwoKiS#X+DMi-uj2%O-#0i`kvS;qE_w-s`_VZ+18yo@4#)R#92%$HI^O*N@BF#r!n6 z(GnR&F}Uf zHBA=K`EfbFEj(sN=J)U6_2qrpYzq?Z{H~UJc3;x??Tk~5cb1E%Fzj-;bHmDH$;G-R zRuzYZ1q=-LqW`|N&v_6y;qn&VQ(xlDyQ@wA2eB3AbQ=~eo@>AF+V_O@-@nG`-kQ}G zYQ(_6ux4MTe17t0gYut+X6t_bzOmKfx!cVhclXaO^V7K(@$aEK-@eoevpdtirhUA& z`MCUj%l~)V1#Nz}o~`-x_Ks{}>VY%-`-LQu?Q37mmT}TA-&SKl9U&vRctdHhOC*=RvjNS8x*2j{}Q z94@E}SsJ&ZOiV(0nHU&2=KF23G&SD;GjILTcaL^;FR_{XvwKI~ z>!W|J9uBN}z<=iX<%g$#%GXzzdIpL^z#cM~pu!+hrF0H7;d#mJ^CV;5Po{Bj5z|7(xXgDI9CtE#Mio7i&hciMPr)epJYBkr$VXRXrGH#Ob( z+*aquJe7H;*3X;deQo2-mJ71Qncqbef(pM1txYUro_d63R%S-qxamO+qGX!Pki9~OwIQ?`?cum?;F>c#@~zQZYsKY+T`ko z#k0I7EqXaqndi7%oQ%U2&7~QN96@{KdmgCeFhoceFx<=jJ6q0dgSJQEq~f1@^R9i_ z(sCE1vZ!_PC`OL+{v$rx#oTh^2eU7BLWgo4&wx_DLbb*?43pV?jb!}xWD#jQORm5KX38^%OH_#csLk^!FMCeg>AQ-E{<|-Z#+I0D zc(!5l!jBJMet&xE!LO4$%47d*-S>KNzHsHAeewGw+BZMu|F4r@>)*b&-?K>T*U!%q z-vY#SUH9$WZDarQa%J75Tc=rPN%F}q&WRIe7T{&Ao&U+nagx8+Vf)qVZthw+xm@+* z;>jo5mumFwKDG66YFovNHyw|TeJfbEMD1J3?TKnUPS3yaXgPdia#DzM)%Fb!@lGxh zS}<>8-`0&gdb#(9KFNCV`Ry*F{u9Rix%YPn$lmt&^4;E8bpA=-vU#)ra`T>(+p%=c z|NnEs(k4Z2wYOfkZr}e|C%bkYx%tMAZL)!h>oMu1r?-B2XB+u`V!9k~c7n)Nli!X$ zcO!1@-o1NO#Ih4hr1BPD+xdBG#p+dcTYY-Be!-u}L)ci+#m@0TC{{`3FdC&6|5{;gGC@#b~%^z-{JzJ9pU z)c^bBTe+{@&n@5a?Dow&uYY9Gih~tM^^2-j#t{}UcNG#Q)7HD_Q!{keSw#< zHtXSid!t(fBIE!bKJzLjGqfFFe@7 zIPv--h6S1%6RzHTxX8(^FKdcPL$T!cYqw{W-M;Q8sWIozXPMv&m;J-fM^DLG_CZ|Z zdaC1G#nX4T81ZukTXJN~i>=|a3n^B;#VV4u!(+|Nq_)uip<6zhr7tr#U!R_v`Z{*u z_MZKjY1gi$8XC{MKl7gU+3(jsUM^c``$W^i=(@)0-NlFbnVGNn@6M^MIreN4E60YO z03H*C4GU+i%kUJ4Dw_Q83XcIpocG^sxoumfw5`jyV|hJR`)~F;vn@PR_Dx8hn}3VX z-1lov@tH0C+v27~N(Wvw;N@gsNO-w+d|jYq)8=;|YJu60%SuATi-3V?oEtl*HZ(VvHFK{P}Z^KjZ$iFYEK6-0-v0 z@8*A9Q#g6^@0APJ&s?_f+q!qtS2n$OHnp7`a{iwDwwF(wgMCfUG0(QH`ljBxWu8>I z;S=W2l5@wu*q`~fjbC4%^^I-9tnH_+Fs}M_CpP=|x#tq;v(CPLtZne)?(&c4Ipgh_ zmhEyY=VOp8*ZLT%^MT2M%dbFz;lb->j{n#4x3EsVukd;&Z^DL#7N1-9oT~Xfnd-dn z-m#svpW8p_{)v_E?z~ES-OgK@C_L@ZXT7**lYig+lCgAN?bCg(uWQw^qH|Ydf$n~Y zdFJ`?p?Az`RGQs@1&b2_S^nD|LxdJ(_cUP%|1VVrhoX+S@+-VZzY$D8_Gqy zowQ#5QcPar!s7+kFUx$Lc$(+BO0v+V;NHU3cVsWB^w^rdW#VRDzKZA7#Of8M|#K)KPE7m6AS#>iwe3!Y z^TU_dw`$sbdcS9VMpsX^{E0uETGBG%yRPoMS6_GMw)0?mY=16e?J@| zrgn0A+rxi>lTK{=Yw|fShpZ`6rtA2a!-)A|- zN2V^CA^$9eQGWaO&(~5N7rLz6$q?ee`lp=Z{{qvKZeLG7dvS3onIs zb4X}7GYT-oY2SVGrJ&9IW=qtGnK9YRXTO!-X2HtCd*{2?^ZIGm&wbQ*yX~jj^Nbn2 zZCSoESr`}$XFC?xUS8|_XAASkzE9S1_xBh6dhj9R(eGy`=BvKupIM#%`)<;Y{G!@7 zQS6mv|Gs|u{dLCkzxTb5E9#&0y!ma~&v&y;Zk}T<`E$%Rvvbj%nOn6#o6L+Y+R4i+ zP_2Ab^TzcD=09KET>g69&hqoOl2eag^%0ZVRmdtL_+a1StB+mvtX?ZU4%+laxV79* z#652QoLlTX0x8>Tdy-lfTwlqS%fxh&A!YKC1w|p^4AO1$!cVUKDLJuN^=A94){yg( zA-QMn&xmZz`@08*Natj*HT7GA2x_0ed@^`bp=93eDmcO4rcl%z$4bAV( z_AOs=YqzC<-N8K#tOl$S2R3S`{LAtFc2bb(pVK-~Wlg`yOdn?$T)Nh(62QVB$9*^F zufYdSwvCHDdm8V)v|qLT+1yhK*BjKoC%f)nkPvStr5Ts9`R(u8ef?%uMq96~Ug_zj zs>#9NU^Vr`o#x`&U)yK>_+4uH?u+E-OOi`0)4#2h-)z5Ib#uP?={IlAR`N_btbd#P zWQ~Q{+r2U-|7~if9Cdu=JfH8xwW-UWr(6tW-g(W!d++;axA-T&Njzt_HkftS!3`mM z%B151R_}W9GO?@ZlKh{N-Rk@2GyFUK!(fHy3WWYOLVOlgc;|DQ1)9Fs=FG z^o=eKJRAiZbN9sV@$c%r$Ctn9-my0YXIek!XZeIbXPbBT@WLCu@0)HeXx~}w$l?F* zOL2kv%quE;zT8fk#OiynVA(z1>(2RBW=uxj-|qdGx_M`|uJyGmTaTYD+yAw8{(C*W zN7n;P?`JJIck<-^-*4aRpFLV~@nfAueRxS~mPjN+p&^Hkq{m71vnRrH_O4++vA!iS zQIo~Q<`|PZ2OooA0Ruyw_h0tN2k39Ga~M>;N#onzWt-+Oy|?(-s<{QKYD{Cj@XDEGhdlp5Q+*2YVlYPxm;RvPXO_UiJHbv*CN^}vY2)Nz;A0IjD7Rf3=9kI*nK)P+xPmh`qM{z)>dtojr6|ISK&yYf>xe7k0DiTCy`jtRc-u2yE- z)$DyfKBrT5T5!UzQ?=d;HmSLD4m)4^|K|AjxHI8rrp!2W z_g}=TH;11_t%zDFI(6x~4((q?yp}&CPNy#^(0OX$7M?z%(zkG;bD7lP9SN_jQ_{LC zE*zd&^XkA%#rETuu<_m{V4L{i`>~`+BtLI&CU7w z*XjH8;-VjGlXpg5b>Ovs^)Wrm?sAH;bLv^Sz>`rPV3$$^{;QfEGIk z*iwoV#NYvF;#sZTp;_#I_WzXsjsFY&Xa4W{U-y6F|CawP|J(j?{dND9<$cytr6Kgi zvv+Bn(=SW3F1xP${)|ZYx_3WkbpM<6z2UW0TJc<_E87>@+=|i-@d`_0V@NPfmrq~# z{E_(1Z`1he*S=Suen0s4SM~RkgD3a0fBStmWmWRGV=M1$`t5&NQ>C(~ORlfGbLYj+ za`%e&7pIk_?$1$K*Oys3|3;honptU+PS|bH>?>LtR$2P}v_YlBqdgwKC*R!Cxw=^V z%d$x}N&+X(_`Z|e?_7EBoVwAX_tifuKFz&8?O)U??@C67ge7^?O&rCZ=)Mq;3B1X+ z?q2Nl=Uw}g-aiYtqM7w>_vg27bY7&f-TiFHdp!8clVdyu87HPL`hWA^l@2Rj-lT`+ z*XQ|6dMWvR^NsrL>*i);@!vH$zw!}#->l64K4Et9RV&&hmrYjszwh4BW!Ai&nzL`6 zOSS6Uuf~01?qQp1!_dcTs*fAn-+R{^WFhe{nc>B21?gs{?C@F!6LX=4Yb*!kD+1ga zk1TL%W~h_;8y=UNz@5ji#_GRe@wR+Pf2K6P{Lqe}jNwSP)H=H>s;Q+s`G)xM7Ux>Brpb(``F<{h6`EE%e>|G}Cggz^exX(hMWd_PugeTB_v5e^c1! z-R)W8K8owkurWYY|z z+0Sk9aCsMdX8GOOODs0$?V9VHKkFR(e6@eud0y_z&ZzqJ>QBz5hd0VI`S%-5{$=_5 zI`4Ad??weHSXRjA*FUto*7p44_jNlh4fo3@e$=sum{-ls#KG`|gC(I&e1ky8E-40~ z3knmS=w@89mtbJfaB$#cnD^?>@gv**RvVmPSbDbp=Fza(%n}E!-NZI;y!JEK#COZO zn8vk_wf3mac>BTb^0u^P%hrXcF*3{upIq!GG56=a{@iB|KRdoW_x?WL^?S0v=I#44 zYya;IiL>vguH(ur{+Q&y-J|B-4mZ0Kjo3{--e2xe@bPJiS^+RQMr)?@LogpPvS@!T(fLmZyWY$jay`uXTXU-Hb?|GYOkvC%p=bz}W!Sap2 z&)Eqtc@YwN=#TJqlj4H>{j>B#o;|ZZJAdUuE~{NXzO7vNt$vm9%$d7ZzP!04$iFOo z;m+=vJM)hH)tFQ3@jpjuQ%3yn+4;YUTuL_yA7Ait_aF|4_xE9E=ejjsX@TeTjBHZm-b{OH^KOT$cZLDvQq zhEu*;57-?iGv534$3H&j0au<=yUdwapXa}ubFV;+^?}@D$@3khD(`CFuK1oUEjlwx z!j)5tlcB+SPHNGoKaVp?-Wu)unN@#N{9m2ClpNpocSlnWy?S{6Ykkest%vL5c}~mc z7&zPAJipwP$NAjZniJJ=75)3|&VE*VceMX|>FnY^DbDfxj;-Fbt4&V%=+(;YjlO&C z>!}B86sc^4zrS-o$SX-z!bs)6$-J2JI+4uTgx$KDH}uy3qHD zN_@*EF>T`TJ|?0Z$+I@GGEAkhWIHqC%$ZXbq;>2Ro@CS8l{j=`)scZF&>*ErsdIoVuOY;})!2=+r#x>E8AG#I5gFIu_2^@kyqy}J+S1YPM@M+dZ$hr@7BlyG1beGy~{Qm6mDec^SWfh!!!A-G0zIa z-$`jX@r=7o-fRB*Eb`;_lfdv=4ZE+)t!G~0o?trjr?EljtoL(np0yPTWhiO#dv!2N zZb8@o&RKUamY!1YU77S)J$7oA;j$kOIe*0bX0em|x@+fGetXUxH)9!M&Kx@axV-pV ziEZ8;_V;Da-zK!&D%RSUQ2;y*v`Y&#}V=awyK8oD%8 zQ=FmU#d?#rf0H-M&h~$I`+M^5?O(J1=FRxIeXakN^Ar9(+WYTO!Ohbex9ejqL+raw z-M*8))~NdD=NYufwF&>`u1TJv^MCQV zmzsC1zR%yY>vpJW-jSrYYo26Y)N(X5w12&8=jv6`G4=N+wq@QouQXQQz2n4}{D%Ec zYM5LP^18#mc6EQ8-tKW5hLv&2z@7=rKZQoe^u3+Wb zRWAK5wigyOxL@;R(@Rut>@#SPX>o{CUNhD3>0y=$Dih@kWnJegvPv+_w$E^4ym#x5 z{Qlbo#SXgbDf!YJT1K6ZrguZ-fL(7wz?jU?6th%p)(m749ujYzwe7% zW_$bJ_ZLd`z4NVqs_dP%VPef}IrHr6lJzw|e)zBbSN17(Z|%#|srJ8~n=99@dEVaE zUu)-A`?+V9;B?!23o~BjuAiG)xhuQm>H@y@$~3h*7bj1>bC>_H@6#>Lrw%t52mYSE zb%XG?5Z?)3m-2a*H}1Y;y?grOI|0_a`;VP0E_2`C^J{xm;oj-BPec~w+$_2;w{qv2 zFIzWP-8pGJ^D5KsnI*@+xL$>)pvJF2I%cm`P^sOlC zJI}tfRi|Iq+x`A_$2fh{l+!7-%kJL&`M&l=?BghQD{IsFHyL(wx7>L$dw1k(Rmp_; ze`X!H70K<_I9ct#GjGZJytH5S2M^qH4G zPHu);ywm~PU6()n$g2qaQ2MEw0BodZ{8p0D)wvPq1%)x?gUwmXoWZzni8#G?t?t(=I2lR&HUHBS%kxwE5OOa@%D-X4gV*E zugklq$dLVa>fKN4J2>JqG?AbY^>|e%{AG_a9 zyP$b*$qBZZNxST3X(?@Y-S#`_9Y;)E`&HAO+2yM&oz;cT6k5lsWn`KNg_?NpYFPBz zzw7j!{kH>Nt-7=0#$Erp?-p33%-fs#CcpUpgSTHNxK7OOQeJ)byHAK**`|(jQAKVi z_8t9N-@R$olEvyX+s^UNlx)vzaQ6HA+Qc)=w|t`d<$Yh~uJL=dEc-{OPay9B-VaG! zAMUTarzh%}mcG|FEzZ)|Ho*QfU&gnBZ|yD`t5>f|+BD<)k|WQ*EbE?|@m$1SuPE8f z?N-&kcjAcE!9&(7len1nt@g&#Z z{fEC7|2~@=?DZq=jJesmb0ynK|89=oSM-Lj?&t2y!QbtF$NzU%l#l;={NeNcpAO$v z{`da-wC^_YpHi;yURZw3bltjBCX-)(ke*ig^79jsJcSvbwybYO+Cd9L(axo%=`bjyOwvVFFy zqQw_W%8jjmKW~#byk+HcrV}mgcPwjv|DF;zW2?bV^R#){=F9!l`O2>r=YFm@mUJ4Z9n&w(Z~FJXgff)YQ1H$>rOR?Suo1Y`m=ndZlRhq!@^VlCw2?x zoMbt$_t(#Bx2&%2S--kPdGW<_+j>{5at%Ez!7!m@PRH6?XMK2&x*p5D{BGIQ$v^Ku zpSAv6v+JU_dB3zb-L3uqXKv2zHT(Z(%&C;GpU*XAqMqEA)E^5r*T+3t@kRdkQu}$6 zms_(>+WYXWx%9i41xpq3B#O2$elv-jI-?>>B5e0Bp18H8>w>?Z_GxlepLpS1+TAt{O-;9_wBWO$!W7& z(|P>2f4y|{zwQmuoO>JNC#uRF5aVDtAb3b+#)g^Aj5{3J7#KKpCd44qOZj3|o$~trq>?^S}Fl z-~XQfGyl)}KmY&2{}cbu|3B~4pZl4)`^EOGZeVV@^z6UcYGJnzOBn7H-6}meZN7Hb z>fnd3V#E%bEvoBl+qN~pt9PjaCquzC{{CBWvN2Y6EuD@1-yXbq@TPP_<^P8n*1vBa z3@`fhV8z}XGryk0KNg9X)jr!9ethC{?^3&SmlyiBB=3vUORe0crn@WEtE~J<;=R81 zH+%f_|6VmVp8N6qLjPr2Q{NtP=l(8oer{xNI`{Ybn|FSmp0Bn$(<^cx+mxFRVltM5 zhn|_&Cgu?I=3RA{@Vaj@QTEfh%TrQ{uNN<$z1XE_zxU(T}n8SudQ zY~VtF-$N$+OOyizjsF{M-E4cbI@Le^z?CoWOpWU|+P|~+-D_zbp7-q5OV_!xY9~*K zt?*R4zw&Hj)h%l~E88E93%?h<`<&kV$!Ga;f8+SxjAxgdmwB8km~;Q``v2ROpTCmR z^|H}+PW^L{yPqfX-?e1O&$=DIxxsMHv91r3&)PH3&}L%hte^Tpy>rXTUkBb^cMw!eoZHRe$2|JZcflVRK0RH2p^IPF9JCB{eaL+pgEuKDqnz z$*r5};cqUOuDyAyT0Zx+^fk9DS*sG)DKI$P{n~$X@82bRQ*W&Nv~T;>{oimrF^^m>XGy7nw@@=G%vEZDcw7JI`#S7&U2F@H-r}*TIc34uUPzM zux$Uyb8%|+p0mF#U-WBxny22KC!Q;&pLu##+ADs2`;vVoKCY<==h%BsEY$n8jMsU~ zuGRO&yj`?ncm9Qp_{pk`nRcRsZI7ZV%S+W>1kW(g!`vIU+#(gmOXR( zSMfj7AFEY%Et~84^o`r|cbT=80qvD9?ar}S6^X_r1f=JQPW`()ee%uPXPI6(cUsfx zem>uL{$CznrLXa3&s90+f_{I#U2nczYjxM;WuF;hzgsMP_`A^Z>-Tl<{>`3h<-l~< z*Z9wzRrA7R4YnT?nUs0ZiX~xAf`F5tLdL<>+6(&@v#sjtnB?>z!>eaPB6noG0;_>1 z=RVD@r*{;Z1rFr0IdeK_n3=E%fZA7ig-xP1jS3c_|N7%|RLxMXjjJSKWPk!p&1r(y=8wvV)wj zarA{Z)wq1CRr8#c@iQb(?eX5-GX+#9s=d@(G$;1*^!1b5&n&ADSipX(Uir?Qt4C(d zIy37@XndK4cmA~1+voQ0T2}Zz)o}0Q4_B2G7|Z-~Yt{w&UNkn|es7;6SIFrySN;2T z;ctx}*S*v_XA)wl?tk&l({0SJ?uG7sIg{;r@Mi1nAA{`*W~{!l*?#`fcQv;Hr{?>n z`Mp|vWZ&7px8vvh-MvC^zu-Gd*2(sZjvm~6(l}hb{L3jJLOc>!I*MV)r*6l_ds)(npKu23!|W8;;MYkToVUH z!3D8Lj9E3Eq>EPzNHn!GBm_7x{G0h_zR~%ATxN{iB})Ihi$8yTaDm~S?($Vq?XLpw zJ?E?6^N(A`y>>5ucJ{Rk0apt=85r(5S3kM1L3sP)pP4f&EV^!QG1cEaW8aVJ`78gb z)ciMBGkL&#@}mB`w~q>M6-NhNt}yzjm_DOw{#!?3@1N(~^}?l%GrP`67hPN0opkQx zT=ndzIdwKE|2AJ!oZ;0qE%Khh?DN2{zD%~)JHkGzT|Mc~m!Yw2p?`AMZywW_ zvzxvj{&&RH{6MD0tn+tn3hPwGm&q-d@oLs@A4c9U`-Psg>^-7Yde)Tnvi{D`Z8ED2 z`Nd1l-#_BBq%xD_K!Nzsp z?PP36uJql6$s(K~9tQ#o8y`+}NMP7E^N;+^+>J}$`5xk#e*FK$vuvDZ4DSm56wOua zlRtG@acXVu?QOZ)w=Q&OxH2&a^_=!S{rLI$!o`2@W&SVu^X%b~6=Jnt;(C_z*{_zn z{XJ*?o$_n*^~=lueCa+d(|&xvMa68LcXiqMn__>M_$)t}`r-1ahwTqbeZo(~YX{HU z^{fAx)c38$t9CzsH{;0h?j=(b>)NiqmDx5;^1?nYiJ+f$zn3oUsOxFCb>U0*jBV0W zCqGJmZm{>mmkU4F*}gTkEY$Ux*ZxsPfBmxZt4{uh=RE!UbKjZI2R^S~9W8$NcK#*J zH5=oqR+OcwzPgq%YqjRQwuRMuKa})otDih`a^au#Yc|`z-Dy_7D>OLtazTZsM_y14 zgOIw&Nv056-@8#KS1GN|xN7QoT~S+D>ihXwyS{x45}sMR>%qPJc%NfZRfT2C>VG7j z7jam1ovGw}N^W|($=ibtriU-sbIxxL*&&i6f5?N&dC{w#N2D9NpClZ4v+>s7x6CF^ z^930Kt}aN>_~_WSZNkg-U!0T@XZoh!bx_(N+}v_y%f9=+^H{TZ{>}K~nx1~C=_Jby zpMRHo&t9M8d%)w&@#SZ_el9gU_P6VIt^K`eZ@WL=yZP?%E^&$6v;Ese`&rnNGpVt0->Y9+l(rL3^-{+6cf3)L&dVbyHPx=48U7siG8?)ruhdZA{F0K^b`EuS{t+|$S_X_Jz z3`x`O{FOZWr$y4MGj{p%t5)oJzwTq;{CRTzyVHvMU!RpzC_K9O-Yh}e3p+!;^Rnuu z@7kn!zI?gFEI+&E{|nChe7KkY@1Oqs^tQjZ*P1uB3hXVTkl`_^V^&sFXG=JSDPz;zjp80y&tnKU%2zDcdGLLx`G1TzngECmiH^x z&dLvWyS=w6guk|XUuVt@2leT1d-jN}oxA6qjl=dCfB*O1ynJBJZfVEZ$oDDP58|v| zE?ZzfH>I}X{o$pL{%kkX%n(;vzWLR^IjelnU8#Gq$lU$xlgUSaTsU0zL;6&kRPXxG zf3nvm?M_QODK~A+)b0L%Y$kHc@`gIxyVBb**>zQ!R(bEg@MYDfquTy0)S0v^`$f{K zoGE+m@hm$x$2wVJR<%X(Mc4NW7hJw7dc8{3{J@oSPBC9Ld^l|BJnxQ4P5IaJS90p= zMRY!HPhPfv{xtc(wl!a3K9#Ne$uVQ!=iqNkb~+S)I&;9_^wAQdIWcB?SDw7L+fX+D zMal`Qo$u|>sIpAnlkk9nsc_0OcE&qhjEx<D{HslWU+g<7g1`*H(R> zPxqJvcqR&MP}wVeS%R@ax9k6pAE!R8zRAL^$ROwS$G$G-pTJk{gc~~lo~NtloLk6v zXZNE6XGG_o7po{PUmxj)*@+w{FMQ-S+=?$8N9M zdpTjg_3Kn?>aSe>|L*b3&wm$J*KhV*{%if!?wfaY(#kGBb=g?@$4_|izl-y^nJaFo z7CydvIeqD>9e#&q+ukivU%D#8fH_1^ec!!3=~F^OOU%0!U)_1r()By-^JJ+iER%>@okP!0-D-XQL&=qo=@ye>%fGb#I{0G#&CiWXUcIHik1M z;lH21UG~j={(j5toxf*&Cg`!MgEdnH}9T{{=M zT$P(Y`;<=Bv_(b>J)&QD&C1ft3SZWE`B_r$++VM!zxG-X&HioX(z#DWLaG)8=gbq{ zseYm{$jnpA^Ml&P=bul1y=}c;_y625r+IdPxp{c? zyzubZn*+W)oK^c-KmMFJ@ABU&kLNGiv|cAX>|Ej5b1UrAHY~Ge-d=Ts>C)f&RsQ$y z9Nq1odVKj=x0z3j=W8!Gugc8(WzNkjpVn;u^E@xoL!*oLGEcfVpdAN=B05n zC~@X6o-h~OlA5@N?Q_$a%G^LEfeUR96Zal;XkRst>9?6*Q83r9YDdox*ZEv`Cz(5G zpS9h1R;|?})SC5I0mHt`Klk_DUc_$Btnm4Vzxk~o)(nR4GghrL>CbyE_Uy~~+AX=( zI%gL3UIU#)nbD(NTA8uz|E^mf)aU-Ldi!kq&iTLQE?ylk_wPU7_j~`&XI}sDqv?%J z%<+`|>yPeUeXjd#Rq%e#>1U7i*6DtFz4Kehl>6SB{GY`xeiMCV&hpQR*ZR6XTqwBy zsH~K;?puxZJlprSx~iOC=bo{wUQqe^i{G)iYu3fQHb47LcA0 z9a+YI>!x3kShet+Y4^zvSMNhf6I5*PNc1rt-C`p!nfKd*%L>X2lAfh=!-6kgV07T> z+3|tR#U`W1Kxw;U{RCUqr6H-if;1#z3?|m>cdB0~w1TCn+V0jQaoI zHjh@3VA!GV@@e9fnV+9qdMET$ea(HnI5Fz#v`GvNukJjIvF^S+(|DQ8+^^Sd)wZaA zy)LzX{i@6VfByTv_dEOVe_wMq<)j+V_xu9@H1Q#;|}%NJ?M%aad(t4*TqJ=zrLI|Z{A(Y`*Ev!r=L`xY$B=k)qgjx|6d+{ zg?+)&yjA!A@*ra&1WhUE#OCDXj`}C&m;C(x3l?K=5 z{SAII#Scg~Gd!La@cXEO})&Apiy~MM_wn=vJe|Cm1?LYVb$F!qLRfQY!*L^effAsF(q8XLHX3jr2uYCW^ z`d1qkpWC!%=c(|YwjVCfVcfCh<5JIO=l+zhUw&`S$$LfCpFF>b%N7(YtGC$@^yA#h zwzO@(UP@ZMZwoX&W4KMVa_^LHF2&nx^0}%Ug8r#@5%JoVa#@JvZ;B=V5-{)@1FkX_rp3x``8lw*{jmj(`Dw)Tr#Wn#;&3^`Rhk{rpJ{2*FWK#cF8|& zV*cf;mStu?^RDN|ze}>XyZ4F#bNr-L&w`gdJTswS(vq3~ceYvGY<{V?LhWSL@~U04 z#GlH|lgs#}qdRNwzn_0*&RaKg;mpg9Pp{8p_+7nO-)HiScY5w;j@urrzv6lL-EXE{ zMb`~t-+P`jHuCzWt;bfPe3(s6Wx@WhHbNod4{CUfYA)Xu4OLvaOlVH{`cF5tZsksq zU9|MNtnk#_`TkdE0{XL(_5sCpP?@E&+_+vH=3LoPuTpszwxHhL6!q+ zeYakFxLoP}>G;N(S8Hx>OWV3(R;B^Nfr>4wU;aAt#cW~t{&?v>-o>92{@x1z?7Zle z`p4%{UpMc}>fAQ@Zy3%_3Xp7&U2@xDKL-bOcHro3~E zYj^u$C*rhea^jl(e*|~^V*R?N);#T#mstS+pHuIi7;6QGACA3e%j0}a+LKOK zm%aA#0efBb)m?dvbs_Ux54-eDwnXldHKiwj!LU-Z9beb{f;x$`Se z9agE`Hg9WV+eyi)J<_WucdxP4d}jM)`NCxdU(e6h-@U5Xs(w<+-ZcMfo-@uYytRQz zbneNtS0V2nE=>J&jn)3|z21%Hk-=f_ex1FU_GfkN$9yx^$&*uewLf}U`1ahMzbSFmjB>P21)%3i+An$*{6HAC~``ryoEr@DF)nI|`F4SvDIutDdQ zQO(mu9e;95-ZQyP`q-bktbW;2zLc1Idl)39Fy5{S+~eNU=)FNuML_)3943|ytEvTd zm4EKMAN`T49Qvk3bJOqH6?GPKxvQ70Y7ez}ylS?*&GL%LtH1AYK7RKV zQ$hQSv$+)uZ=VEXZxV^Ps;J|X_t&o3qI z-fTY8RWLC1cf=&Gn^8YOUd>R}Qc<2hP{L zF;igo^3@7fC0|v}80{>otqpkYablgO#uk-1udiHqCzEEi!&-0S9Yd!JHQ#$UKL;JX za^dQRYX$dj&N`bttvEr;y*`LNZQ-dBwVH32U0=@eJMl98QmC?)>*~@}j*YB0j_Vf~ zdR*bs4L_xEsBNK$(N%A!E51_q@9sIk$jIYZ@4;B@#DOe5~W& zr?82`N{4Zu=b!qek6I+8IgV(2`jM}5IsPQunLCS~9z1sQx2~aHc|+jlhlg*Og{*a) zy-I;W!EC3Rv-Iq5)7gyE4!x;;tiJ8=-(8god-wk46wO?F_h#*!+|x(4OGg_n{%L#o zw$+hmS90=Kn4i~s^RZG-|4+rg?=k1o-Ohi_y5zaHebKwvzrm(?*;c=8Z8ltJ|CiRW zvn&3{_qmpLF7JHJ`s&fW;Qfccg{%zSm{5P>b;FZ$`IB!R-s5xa%GFgFtNz3;o@Z@2 zS^bx1>~4MAH!q*te2IBp`f0DUnavf;>Nd&reR_2{zfJYF@7H|u?D>TsOV?O_sfv%e zb-8v%to8IW{!F$8E20-mr#^pHds63x)+Wyzx4q(LwY5Ae>76`3Y1aZ18;A3f3WjgK z{hMiPJv&lz!LrT2&fnc!zB&KV{oL8P=hFTDe=mGH_5F9-y4Uy3H@^E<^Y3iV&IkSn zKi3*wusy-{#@)C_6T@B9ruQ}66KaUIoL@7LXM`)ZwN`lrXjPwArV zDtWnk$6}Y;?|znf>z0+Tda%Lu7}wt2OV>^l*b;xU{vEsc{@0(Igcf~DyOD1e+BwDb z?OL_%wzhw|I6XI(r&(V5{CwRVQ<-&gUri-0)cQnn`#Ba&5b{$rDCtY$#NdIxsUOcEyTY&R6Hoc~u=)=CX0?=d-I`sdszLxYlTNVBH$)$u*PMEnfeA zIV9=vwZ&?edcm6wm0*^oQzp^IrlcNKkQNZOfcZ*M`ftU}9Kc1ugPndjaaiSPw| zWZL#7>`Am13x|Q5X0YA+J@4G?TOVxhDsv2S)rhP7lb(5QE0ajWvB`pBPL$a-My zt(EfcD&6LEPdfi~`&QqY=x(ztu|zRPCI*?w#q)g5>^NWhM<(XR9{KM-FW)LX+w$i^ z?%}%M<)QoQ!pi=5*zCHOW5>68-p4=j|JPl=^ZC!e=g0lOJ^s75{M44(eLGD)_two) z^)?T$|D?FPw*0Nlk!JI|Uo-s6P3L^$t-s#0zUEJg*!h=*XJz}nufBfvu5MG+;h9Z! z-ZQ*acP*b$ys}l^|N6{y>)q1zS4-ypPVN7vuv7os-aQ-kNUfS@d*>y3OeXOGt` zo_TEY&oAq~Bz`(2-WGFod6w1BpJArDUkl=vE!$@KY|)S7`Cnq1UNxoqO`qdy{(J43 ze_QvaEwkV3Uvy<|=7I_~y-ofPJts*8+%qt#$!<`w`Q5sg zjWUx~rug~z@d`PY^RWNfkQUmx`NYh9e0OC(JWSfR^V1`H28W)H%w}au`x|Do1kSl9 zU7o{Ga(dA>6%X$=hbNW?^7e0QHBfM2&S74|V8@m+!O`QRx6rmHGP?ynOiEa?aT1Fb zgIwkx`S|7hj~P-kZ1Uu0>xLC*FnlkOzh-#ufMK$HuJqc-)uzVWpbG$2&95xaU6x<` zC;0xpJ9F-8r$z4Xm)`uVcuTza_aBSz{aU>Hc>Cp-f6{MS>A&8x(d|_7eWyt$w=hNEQsh+`RuZkBvN?9~{0&mRDjkf$2_r)#u zON&oV@TzWGb864BXUkq*S~mUW;TX$Xdr$H|@so;Ryqxc(E3lx=hd;mjW`T9|@_Dby z(tR^3Uc9=Oz;@^GzFk#6uRjc!@VP|Rukd~Cl&a8x7q{Q6e5q*_adi3nGrkADeOcqS z{-*mGweD=I#%14_Kc^LKTK~>GeYd&mc3=G!t6!gfVk^04&u-RQhLR0A$yVP_g|~4X zSn(q6e@&+^kGw{C8`w(VMgv>*?|jH}$& z-)(qU`0`G(d1{DG|BuT{G%7SIx}c-amcrlvk!xpXO%$ zoxSY9y`y*b7aMlF9=0(EkC^;a^7`}H#{yLL#-4n~Tl;X^{5jLxey0RlUfujTdP2&f zfOmI9<7Q91U;9IFrA%=6+sQoAD;UF%`mM-3yZm*8_~+Gg_f3AYGdg%?O4vn_yJ|0e zQ+BIP@DzNm+RZvqj3F}b$*DJeCo3iSnFM!VW=ROXYI3$!U%38( zcYNjdtrs)4+)B&6s$n{vkzwLf*TZ|}-a2~Mx}?(L$H#{?fA?#L-(UYczdpV?-}%4) zPk#3Lsdv5hM&|U+&HZ=x)8$fAtD5Kh={((@ZO_H4cAfLQzN)Tz*QkhkDj^h6>B@w%WKuc2|i`ozil3`nf2<{ zQU1==9O=<{)6Dc|>wG%t=X#fO`^hC*ntMHsIsg1rzg>Fyj!yAhU7=}K#%*igookz1 zx9oL-)a1&`zJ82T<)iL7ao>|>z1x3$f^GG2_hVxH{BK{rnEl4mqB_g%ztP>pFS90n z^!@uL_N0lYZRKU_7G>MNH3b&?epNl+cD-}|_M3-;_WEz+>tArgR^(*O4}s97=jS!w zd~<55)Gn==^L{eutlPw}^v$s*X~o5n&wsw%EaaG@J!{3}DJpS{MXI6iMeP*tOkJSZ zY2|#nR;@iKb^Al^r?L)Aif48^ia$4Fo&ELxH(?G|*aD3Qh;a(gwXJa+*;hsXPygTl zf8qZ*|EK<+1s<$e_i5*>>!#l3taz%pv{yTY(K} zo400d&CSSO$L7t@aMa3z>;A^-&)+hA&GQZZY;`?)`^}e|p5j&RH|@>N-Cz5^yfS!t zXZmB;yLFGxKDz8@_37-v=`SCDtDC&t;&S1$9k#VMayHznPu-%meCHcJE8{cACfVty zeXlAm{CoS}q^X=m))Godij{LMjpgswp2^GjC9-0A{hNEgEZ20bId^k&=-fcLr*fy+_u{)PX-(cl^{B-ut8#kr@ z6c_fIO`bbv?we)Wrbk2f96mYs;RWx-jn!etLmG4VUFW@dsx-UlhB=$;ss(NT!VWPw zr#sF+$M!zlG(G(Lt79TcFQs>B6iu1?uOQ)iokrcdSFsPje6tVEfBo1y{O>WI8{z2i6cL$U|&M%&ISA(IT zw`5hp_U{)HWfRxBuFZ96;bLMqQl^?|Y-v29#$wh7`}2HzUwyy+|9||ie^vR*PSn-B ziTL?x%g?*tlM7#eOEaI#|E^qnU(QnTv|OoUsdkF(x%1hlo&Pztgu$oEzLwpXt!pSSiiKiS9s;mJCs_BXxrSI;g^-TTw~Q^0h!zOH>{KbB{| zxMk)aZyGcE(KVm#w|N=OA4~pIGuF7cZ_{0=v{nC74f6nC$PyhCMy(K?PzMK#F zv{2xB+nKw0Z7P~>p|fgV9kNZyw|USMwM?w-*(+{O{NA+w@Yvv?x=`~xFJEOIAl_$f21D~Jo4|o4~UG3j@Gb!0S-f?|lb<^*j z?!S0^{mtJN9QGUZ*3WwQ>&*r4?fU!d^?Q!5&t8^Oe!9luSH!7l@|VgVZto8|Y5DBA z3BRk=#rvD=zkhzwe>>%w&2`tKQ=e3ppFg$E*jRjS{`_0Nf1P~w>fg)RGmN*s+5PU` z>B`7uCv2a*nO}a^KbTjfbo#6nmcs9}r2em)**()-ah77*GJSE=@BoX~Q}W-<6rW)? z;q(0Ft2SO`W-=OIo-dLWukD!;?8z7Z_Ke~8jGgIL-~ZIM#MeK&zvSVrlMB7dZtl+h z|8>6nf5XGJzJ{E!ks_R(SFOq~zG1m?_k4Ps)n>`1H7Cyax$s-QKYe@W=5IVtX3E4p zpUiuzvh>8gU21Jj>Ff6!MXOuPUj5(0IXYP9s9*f&@P@tWjtr^{xAi#^Q&_~~69cTI zcSYMCYW#9PEH{6Ne)HbOjo+uJhy6eGt~bD2{I z1`0Av3@mjSckYO)ADqb$A@gsuO0_%XQC=R9=*LHG!dF zy3CL7nT!5E&v~;}Uhb^rxu@qOBcI>f6ZOBh?P~3L{kodhXYafHcYX3_ro8^iHT`PO z-#txR<^89EW4ibIiyxntPmZ+-K5}p4tj%Q_n{I40bvB!-bbsBsxvE~xs|w=;?wYK; zGbew3tnu#6#y4l$n%i1VX|LmY5N>$g%ir*B@%jDc&u7o|DSf)_*M#mp4?__&N}hRV&=WukzY0l zFOvHH_kHX|22KC8w|7G~OWGazb0;qHn}^zFwokW1MQ@9n)Xcc85-(nM=G)Q#OLs}? z6{UNnS7qowm|U5%%iuiE^ZO@#;#vNL@3C9^BU7HMYI4sN_Sa|6nD5H=yPRTcJIVTt z{tp-47iJUotz4Yzz!Wt7!Rq5PCaYK!OcOKVX__GUKzGN6%q@)h8`y8_{$P;$HiPY_ znvnC3A6wU~O1R(EBB8`3z;^rLLR)nXP_J|Q(wFL%3=$^)3Qvl0<}uj3OLP7e{kQ%5 z%ObV%^DnCBuiX|Xz4gL|4PnhHj0fg^&e?mtVoSN!{H@IUZD%jZtj>IHvo%*x=x5^p zvfZ;wf8M{m-BMCc_srh?(UCoOYHObRzItZy)9kym<-RE!|IYpNS>flYeOqGqjFk?>19$`G{ZV`R~+w!DRIX}UF(-TPmL%Wvj?e{53Dx$9rzg*aTe9A;fNoS5R-c;SVAbAht74&yc+eH#ykY4aNO z*KJA>GDwI~-?&52GRH)X1ohN{Mdc% z<>v>>81HPkb?}$T{iefm?~}I_o7`IE=4-l|jgz53O-|C;ecG|Ig+2s!h}XEeZbic7}sGv3ZS*I>oJzwGDD?{i+9w0N`ke%7+pCr%We zyLt4^UG>9nPKw=6iC^klT3A$c_D}u!IyuJs$*=WhYJ8r3D&NFE=&aAItsi6Gcd|98 zU7x@3d*Zf4v->&U1$`d=T3GndXA^hEiF~7K=h?p5=C2>e?r(a%_w!r7lh6Llz3WiC z?9i|C`X_wNf0iuu^Oe8%XrJ6WrR96)YOD-iIqxFx9Lumr_T}f?+6?2Fl~#reES#kE zOXEjEwDOjOP0ghWbMGfL`W;}1_fp?o`0+&YZ8wGuJ6SlHI)AkX2`L40u_dpNU^F!uEuW_?EsimX@>U zwai(Qz2(b=CrovlChYc`rhm}$&ikqt-(`4q7eBujytATf-P!jKZ`j{2pO#(w_0Qb9 z-zKEg3GX_wy8PVi*z#KL-xpNkHE!(gewV(qOTM9HPT$S?RlBZK-Uc1ibmS zDpqY4nq@wDjepss$STicN4|&1GizMmCE%HYI`O&u*PedVT0syg`!2gF`A! z#TPGouJntW$~m9k*i~)HgGEwZvra{xKRZp_I%t2X&)J+jCo$g36Fx67ymSAa=#oWi zCI5DQFWIchCd6>#k=@Y=i!Q~?e0QyPhLZ3qHCLnQ|Bfk?aISBe5YU*>5%^lnV3+B{ z`xX6p(+&yL1!eRx#8vz$@A*8Nf#F}z{dG5m&ha)xe^Ijkzje+1;84Ne8Mn=%vJW3x zly!=sVaNZ)tIE>s_uu5z{U_9~qd)t7`AL@N_qLjN)l`;U{oeOC|J~2qlb(i!*ZS)} z{;dDE;P(D!e`ZhowPA{Ht#p?UM`Q-N5YVU9TPCb_){%+pA`M&S&l=wWiQWWEYUyd`@@9qx0~3-AOF(cZE9_I^}TnY=v>e8bvgb{ za~ZYjdNx?LI!)(YAU>n?VEuy#i6u*({BrqGwZyC9p!4OtiRX46F!SV*b=r+;dQ*?Y|pTRg~86_&w0z}O~-s$-CB>?Z?zIUr^s+;*DSw# z*?p_@j>PndY}l5oZPXhky*6|z3q#6pcJJ)pmkWOVE{$2a?E0H`%Txbv`~URKiLw{p zuh?ImyGBm!+0>_JD)v{3nb#Sns0$vS|3zze_lEPIFS%cCf0!3E`}n-~n=Y3Ba=iZK z{Gb1&Y+KG3blkb~dfmCNbKl(z4_|oN`26ikpPBW>&SK&6X*V+$ByG~oaCm&?)mf(x zK_7Dh_RV$vd*{vG?|Ux%{`T`^yYD_{G5@E_81mM6P0`wX_xw@QwO4OOMmm(Q-Tlcw zcim3&XWQT2dS0fQe0uK54sGkrZ}Q@cm%Z=vOZ#YZwkGkI>Gd-{!TFCF>(AJ~ovz9J zx^eTt;KwJQeKo)HU#F`|X8JQFZLd|Ip7?nL-?Tl_$)Db}On*jLpyi$U`)fb%Txsq4 z`R#nifcZ?v-iKb@TAj5jiZkYJvc|c)t>-1z6zG>bKH;9?a7jDSVbX`{l%na3xAhfT zR25Tdmx@jG6XoGm;8$?`oz1f1NV1oSyWg@sUQhG0D^Io9dk6@weP!}h`TC=L;S9duHDnn}Axb>-*Q{-p(+ITHUiEQ>sRxSz1{p(KJDrXpNMnw{)KDl-;1r>IXk%U;@XO zS9CW={`QJ<&v|}d4f}sbzvOCg$hWA|AGyCIw*9`Dy1)GD$uh0tk{zl3%dvsI!)o-osQ+0pp zx^*wl9JUB%Y>ciiKXOv$Tg~a%s~P;kb7r4;Ik_aw+xKjZ{qNoJFRH@kYiaqv^*O)( z&v({f9$VX!B~OFDaM{hYJpE_;*Jj(y7q_+e*cEoaW=+*zKg&_IC~MP;KPRm&d;0sm zZ)Y+5uy-T>n?Cl*>1Cf1Coh*+RpS@#d#$as>*Pt@`iJXsR|m#vW;i&_u;6Td)U@sh zL&b)`f0Oj4Y*IbvcB065{YSAfWu5;Do{fwr<+TG}#IE2+e-vrZh^ zl9i>%$e{Y}<%>&mQhu9St@yn%?EdWgX3xL>wt7Ej?|z9r_V0hseY5_4x}oE~0>8Fy z|C2R$P8s~I5nfjvRJpf*`x%*M_Y1AJJb(NA#n<%z?={=fqnr<$7G3;Yvi#ez-Mp2S zeLUCK+F#uv@vNlYX7bs$yNh0K_jzBNx9_uV$&AXI&wW0}@}0F5KCd&U=K1sMpW`32 z?cKFpW4~_D{MA1;u6tHr`ZziL>e+WI-iogm|0i)MbH&0xC7Ca*+fJ$cGP?TwcYtN= z{#bMF@Z~Ez)nBT-uu+#jn!ZNuJ9GgD59n-c$d#tN3=9koE$Q;2Gyc!{KkNVO|1OaHT}Q$xcs}ZM_cuI*@wPu z_wWARbL85Lo9q<_Ld4nsO+E9)A^8VKpQ-V`Yxk4g%{KkqJv;4<%sIsuW;uGZbb=-x zP72yZ-MZceoiEkJ+1U)j!DF&|dV<>EQg@e}5z2SC{Ce z?fka!SH^9(wY}G*cpVuUO5ax~Kiu*5wa@4G>h;HOhW^@^di+V@yPCAs)9+XRd;0HL z(hIqnXD@%>e!IFhtoXg%?*rX-{>QEB_nitnrE@Ny)wXBf`j_(0C(K)?D!TsSYB%Tn z)XwLY?XR3`_j#6_m@|8&uhaCv{C{(mx9eM8H@7}$t$mVz8E>hpf4bBu<)TaGo}Zpv z3@B#`F822c;tctgX07eD%2ed{zPsn^7;n6;9jg zONB(ARGH2Bweqic&B{|3{pQK6%v?|`uu9J3Zmqo0!xd`U>Fy=nHJ*-LFSnh)*MFbC z?bWPRfqdc2N7!T<4HIUcVBhIBMb)Fu;Hbil)AP<`=Img2GXGnHK&ML_L-&D0H#YFv zFl{hg#Jh4XZ)n6LvEXUkHr%SpEaFUZi3PK57;YvuaWmRg{E0sOM);ub5e}x_`s|$g zCf3o&9gi%Z(e#;>&;M-0m~WN(=?JtuLH?7Shyw?pMjZxBYh0ZvS?F{!EkwtDb)U|2die{JGu2-O**g6V@AtSk&0QUivwIdzfY2IkEZezE1-3zR!NdF;Dli zxxx(J)Yx#>>8^TlCBZT`&aRs{srBr_EQ!0Xiqg~n&6)i7%gMdw>!O|oWs-F4IPHWOV_DY-cDaZJ}p7d0+EdSQo zp54DbQC!mZ-vL+Go&E>sCCM1JufAi#aD3&voOy?>+HR(+HGWO}G$+OC&t2W`zeOJZ z@F{i7oyR;mXV;ypIn!#(4}P9)Z1J4&m8GlSe0$re`^sNm`&(@JYRA#{JMU*lhg@l1 z{b+Z1Aam56bu;cwzRBCOa&@ETJN>ukejLwyw~td$`cP!x*ZgqSPjBNn3co2SZdiG6 zKPzjo56djpm4;$%{i!$Kt89vBI1+GR*@rZpyj&}WjTv4VHQLFKMC2OM8ZLP;>`VXi zwC1z04daCJnyv3xTsK%UY(KQc%5HA`t@QpKM=m~fo4B>k<@kn-jKhbTE-5fFO#4i>t1tZWmg9Gv4`EhE#pd zznqPC{NlIgeEE5$?!=cPTOX^ezE(A5O|5XL+1AbLuNEJyyMM1Ta_MEs6UN1FSJhvP zaW?;G^Y^>M>*&zSw!<(C34<5Zc&T4z1dYSR7 zJ>Ideug<)hKk2AwX42%fmwiw7SNmU9Rk-(_zwPgJ^}Pbe#iFfM<7S-fJZJOGs{QY; zIdXMfwPtyI8sYM*&d*D%{`GFw)~{t^BGSC#Q*W{+Jzo7X!&&}$<$^iYMe%?B{r>i; z#{SH`zkPd?Z)#8yuXQRc{4jUw)z+7{TNQ z5eKqam{ku%O_kBS(ej7ONqJ#zk3~;tYb8&7LL`@@^@2OuKec~e-uy=V(j(?Pv6PuB zSNKlacAt$g;RaXe)fwE3aTRxJv@T~i&6Zp8MRtGo*3_ooj0bG5e&x}+|M%(UJ#uyP zWxwtV%XTrjvPw;o;X$%z_s`iCKTn?irNi0J^TpnLf0p@8gMC%A=3DIeHgCP{@#_WqY?w|-|nxwx43zfHW~#sWV1=RAUT#ZP_H&M(?NQ-9`(Ik9oGR|#F- z|NHV)lNkS)m2296YAuqs_|u(yi6u5h+OKN4mV0~RqMC@4vsTW^-1Y6{WAR0{chr}E zVwyGY{=}y;H~NH4k3LULYuKsqb8dA}W3Sy?n)yuhe7aZjz+vl~*8h*bKeH{Fsb+#T7 zu*%V=GjA?m@prXS>E?Upvu|el?wzi_++Ls6dNuolfLFHf5B`tczBBb7>+bB&W$ESr zcXM+EJde3ka@96;cis!90M<2rPeiBe=KHrx{r;r3WkwGSqNll;3GQQK_@f+TeUst5 zLPpA_OUZ(&USUEjcQ)qBc^kg% zfoDFyt6gSQH1E#C|MvGkAMU>X?fLxo8*6{O^ZWGS@zlA;+h4XGUUD?%pyJZ1mpaqs zC5vxpRbDdqIqOw={xgA}yQ*)`b3AdzOsDqM^VG70_R~*ww_Ch9^5vX^Pl|opodu0+ z_SH+5THM|J^6}G>e@{MNn|$2n^4Xk^GjG4XqHys|O7Xp{RBityOBFUVw6)88dQ-o- zZujSRk3Jh8V43mxb+^{>-*2A2Ysq}SeOF1DK>`i_t@2j+Zx_RuFa_G)pKUr>pqqwV}>T_Kefd?sI11VfA#eVV7YO;;lwXVdLz4tpMj zo&D~vy0-LJy}*hFg_qt|E+t*e|H}W^F2Cu$fpJ6lpRClX!mqpy)n~7q|9<7;&!<+q z?sqe}r@hv_WtMeuR^Y;QpanPo3yKOYA3nHs>;2SYLh{e{pSs#&G0WrslP`W*^XDlR+5ITws=vm}{(qjO-R|PLO{}hyV%1Nst6VgFuICk9`-Z6*sD!>(sr{PymcMva z_o_8!R}^z?LiQx?`n2|5=g(QGK_-8kzNX1-p8Lhe_+O@TxY@SY-P&{ZHYD&@U;nPU z@Z`n0?=SFv`vTEP zQUzR=`X$?a+U_Rp&Q#^iDF1ww(>(3S@eiqTX(t>Q80ymhPtm?k@_9Ko^G_C{oQcy^DWihRd?_0Z@anu*P~PMRfhAcpUz$SW5$b> z-L~dweIJ58|DCHnKf`X#^dDD0=TESWy8CU)lxVA`&wNXdWd{X+-p%**?W6tQE~O{mRLApVE}NmVegr_{JJtyEgJBvq$xf^S5nhPM&-B%k5XeJ61l~ zqB$$C>2c2eiNCMsoW8%>*r8nX%axtW&)t|a|M<5#w~RC7X8Eb{pUj+Mu*=M~{Bp{@ zo0gWUTBnOUbN=n!?)WY#{gQ#O@5iOzuas}R-naefUGvB94*fZ&&!Xd|qkqEg#0v$s zB*E>uj2GJ2k0@FvHEZVlQIoKdu!!JJ?GcXD##Ym^AEuobLa5`XkPU>Mz@*?yi$RTKw(ew%)E=23rF>SFdhjVEDc%sQ6gT zp8mD6SN7&u>|7P+63!o;c|Fcw?cX7zzgr(KcNex5xNrX_DSem!yVY)D$JftYm9F(k z^RvxyOPNo1uFqASE&j^j;+$!1zqY(e-%n_auH?1t!e}3SSzhPwX)%NeN82moPY58WZ+Prgq&vLEFNoT7+ys`MI zK6^?3y_uhLW)usQ_9p%ReEavux-!w?U+2!v+p3_Lz3;=9;Mue6{%`d2;Gb(g{qEoB zn6qELrUhSqKjq{0>>{>_7fhwYUihAWcdz_e!KAwq-zxIfUj8eVZk^m#`u=jlhl3I2 zCzdS#-nKpMnaJBY58@9VtX=l;om6E#+rB*8A9I6u&zisL-IC&UEpv2l%xTcdN>cXm zau6@gx9z%8!y>4(VB^0#=57hi`CN)tA|)^R?^gyf3y2-_u;~@g$*!AqYJRg@a<{SNl3^jcY&pw)I}i>g8Lt%8`j-(dpCw zcI?%7x9lh9^`hv+-L--L_$FVC%8tBawXb$Zzw_Of^WWe5d?6$J^XL56X%+vzem-mc z@5x=~msiWLm6t~^KmB{tiKoeu=WXl1Kb||E+xq?2&Drd8nCC2AHlu%4vDysY#8Y>a zobAr-Oqmq&ce?Rfvya_o8D5d5cll@i(N2GMdUNqxyZdER<_6c-1Rma5`EHHntL%1% zXQ#K{Ketk3Z@a2_(-q@$?IC4fzD-b{ZtL}GL3R1nFAU#bI=Wid6)$^HdtD&)z1$43 z0*QB8Vk(Y`@@mB|wrjq-{J6GM?$XuU_2R}XCyu`~D=aI&e(IU2^Sp(h6d2^rXRt{a zf8G36eh#;>>ESCAs?TkH_P{e{xn%g>^ZeHw$|pY63RJmSpSI(v-klJcisdJh#$Uo0ir16x6KZ^Iq_9Z`#*`D!c z#$6>VHkUKqf;aEno494qvI7?uPEqpnF4)81@?)JTd#@AUF^;{#OP*@;6w6H7ysUqn z)dHU)8@>my6&xmrfeJnb28O@U!BL|BC;#vH-}!&`|JMKI|7-tO{_ptT`oAvy&x(_r zlkPCgFuwQPu6CY})PdUfThq;!_emAp2(937ZJ)h1|MgbW+?Li=UP259c(?WURwuiE zudn<6_u#kRM<2*E+fNraTl_t*I;-%{-<`W>y?pEYZ%6m)3$u6pxwqAJ(c|p1`()no z`C3oSyBw)w9r0@^{^wmg}LH@A%8hTCD$kR&Uzey}ZBw?>tiZ zLM>aZc*Xmh?l)Ok=h(h5`!-j9^51X%+lm&L&0X2ObIP+Tdj8)`oWl+peSWj*R99D* zS%~V%Yj@t~oloBg`^ z`@y#he=DhJ+T30>M?7Oy#ff!FyH_lmyq#;$?<+6AKT2Y|u6~?3$Xn>1%2tDEa-p9Z zY<_Uh-QiHjnaNS$AAvv2do8?SCN4bh#!!XWWI z|9!9iGX7_BrFU;1zp?P^_K#by?)(1Xm(|TXvtO-V`)6zU=lZyLMfTOZ(!U*E{VuNV z;HR+pVlzHo-sCMb|Bd~fuXfj1c8C8-xpXnDH{tt==MO!L`fpC1zxq>{yK#KnuSZW> zVjkZy&EK@MhAVCI_w)N-&({v)^-N6<&8+#zGlA#u1C`JA=jX&|_O@5=##2j8KeRp)J5_wO%(S~cul}%q{r{hT#G97Qm*NY)e0DBBr^IKT+j;E0 zx@RAYKX}e~)1lrml%+XAZsErGpX;5B^f$a=@etknvaG{xE&B#W2BE~bWP!Gvv-ORO zkKMf&Abb*Fr|s-fY^RcWXRm?p`_PuUy$)>oc`! z;d9#+%b!Kx{dMx}l=_=58ooVGvH2GKhx=H~q?6}XEuQ`P+&mR+{yPCzcklVPxlQ(S zNZtz@&Na1@e#ML2{C`eqdpqlmlZyUtb7maeX>%oD?whMJOP)P{T5Nav#Jt$OcYCJ% zEZaYK_qLghS{a9*wW;Kv-6a^3ZlCtTcA|lUta1JC&BwO~t=0~I;d{}?>2OJ!Z|sG4 zP6rRmeJ1UHYFHk8_sKWSC)Gx8(&-s!_P4@{ak(mbbqCFsHiznB;rG%l*H$<=*B9 zH8$mBX!shnC%Rhgo<-V=)jHLezs`PLdUfXAA6u+#Dl5y@=A~^eY`cEp*70xRHw%AW z{o#FcUdWSwp=JB@r_bLn_A+&`op5_?{FBd5Kkf<4^O8I5asJIBi7zwG8tk3?cb3dI zMSkH(^Z9>`AOAMWi8na^;PRaByXvlaK8t5Pyua$3#`i1pR-S+T%Ghz!rT6o!-=90l z-GAbUzU0{h@8(!Obotv`D-`N<&h+Zcb~V$dFYE60K3Z_(@$7SR+gJU389Ckjp7rEA zr)Ml()hIeb{ zoRqwKcKdv-o7ZoamE^8yH8s&VrNYS&QFtu>*?;lkckkGQ?>{SeQ-3kfM%8Rx?w)_Q z&Ag_p`Fr|%S)A%l`!7FI3lIJXd%oZL%e7AyZz7(A`}+Hq&VN>^eL2ZeSL|cjo}EQm zC-wZcra#V~^JGT*+_m2yw;XAi`=2km>GaLRvwi$~^_M+P>#j9>b?HLS@pDp7>uRd( zd`l;7-}JTP$(9*wuP>_p{^X`ov48ye?=_qG#noNXdpDi6S+{I{KL74VQmU6D*KGX| ze!XPga{bs>$vIN@gVvtSu|K&%vLT;&!NW7DRmQe^S4+?6Jb!2RRiRsdb{Ba@TzkIe zzt8dIdrsEd{eGMDX6CFqv3B;D7}K3Ir7ccxIRB-@>1n9n9n0%`x7R1zpNTMao#kRv z+IGl=VVPgCQTyu5yi+Nfm6IFQY?Z$6;1vp!ad8Y)o@zB~pQA+HnQ6PESTeW`G737b zJFqNh){=2mVrDqOk(3(0VDs1WJJ}iTrS17{WG!OO@Tl+nN}u+p3=h<7X2>1rKCai7 zuy+0Thtj;kq0_@=sWLFUJnwetVaC6|Pp>?lVih;%?%X@q*Im_Htg)-QUiy{k^xQ4a zrSF`5a`RTjpY5~l)hhpNTXwiR_1mA1$5L+RpAV6F`X? zH|KZ66t-2avDNmwJ5JUWb-g_Ke3sGuUCqAF)P3@bzRX*6Ri%)sF5d~5sX#5SgFG_!D&SThdT(maoTd(v5$ASJwZpzcpijUg@K)@8<41`1$*{y#MnH>VL&+@EyLFeNIKaTX=5q%w_*xeU~@ZKYMxN zjc{Jqi?u)hPyM*<=E?nUF1ky-IqUxvbU}Q4xc|J!SJ46Gak2Kv79}yO4uzM6 z8|Uwvd(|X#@u_1W{%8HKtzYQ_y*{99*^_Wb|%_xX#P%m1ZbyXAj&%e=d1+Dlu5 z_iytp_})D0@Xj)$x#C}a;uTDn8MEe&V&;*~|7kp7DR%lQmmo9!}f7=hG#F$8WAbm(MXUo$}yr;iZ%rTtd@= zW@xnL)N0BZ>~^@f!fl_jaF}lER*uV3v(DY#*f9Iegze!M&n)@GwQ{9uLr`7Xoo!aK zQQHqP%#l2Acb1Qn!DiF!XQei0{}oPKd-b=6|OBoqf$oHP#$Ch_$ z`SbX`&iMY~*W0Y?=IiuZw3QTOwfy~G_x<Dg(XJ3!+*>OMNlf-_HCGRb| z=1(q=FWUA+R-^8%{#^r|@Vmd4FMsyR`%b~Nhi8t6Py4%FGGnc?X!dG(#?QOtXRP^M z_Wbj=9mwhlFR1Xup4mt`-jz8v$C&yx8&2W&rHl^@3=hLzKMMPcIHxjS8Vn46-$==Qo9*$ zoz1eHSVY~Av2e1_;wsSf+IE3mr$T~#4l;FAIkCUpIhXMR0|SFx`X1lfsx1|l8Lstwk6S){Q7prqXpa7K zJ7t$VU|Dy5)+>&;8LyS2g0He|Zk@!?5b?<8{^=k8e_ro@(z(%a!tcwL?zQ}HZs<1pJ*GF0+dXglE4=4sorz@WdrOtiHFXou%+1x9@_yyZb9U`3^Z$LCKB3cI{@0zG z+>1&&9=C>}_1% z#s7QtW8&`^HOVJ7A7cW}&0M+e?8mL8dh714i<6!;?<~9ge(^sujBHOm+3?UkP~2K^ zhu@sv6=myF^5@q4ztT~}wRrkXgTL=~%IB^%ew~!H?23u;Vaa^=J9n+FN4?Yg&b&^~ ze))~^8U^n1hJ#uSX4ebs)6PscIyuQGS&K2+#)N}K^#L0LXVl_n{%>dP*OJ&M__kRo zfTtm`^$^qNB<=|}7(AEg@`WjDu=^}N!1yn1kKW@Fo1K{q*~g;Sznyeih3U>V`TT>w zjs!QJuGdT|+xB&{X{c%F$}L(93`TdO_wJHEw`a$nUAbzXpPefIy>h;11^4s+=iZ;( z+x+8QdacsK7hh^0y;N4Y{IPwL^?#1c^VaK^zl+-)u+02x;SP^83oG>OC*O$YubA-W z#%mK(-(yjE`CfC>Z{FqY*vk{QV%L(Qzr zUs?rgCFTE}_gi&Bj-j6QU~xZh#k*U{5#e=VydTaPWr_IR-g2My`t##_MfKum7>=pG z{=Zss#=3cO^A_HyY3^=V)$k)OBrCCe+Wm~1pH6?1aOvt#TIYFTYxwsQnTOc?w>8zV zF)%Ry>Q?kUM2ZSvEU_AujFCZIe>3I_3puD$ZQi@i1e!*LB;}&C1&Pa{Kwu z*BAZR)75U(z5M1ir`s7TGCjPmN-!`4aX(&gZEoDJ>g~K|C+A21o_;2z; z|9`P@{}(awy_XmMUh(|f+YM^IW!p;Qt%LWym>hpRKlOb^pYEIKza`azm}=)N{vsmI zcK5Or!RW4WzTPW)9@?uZ!7nW zqO~`lM1Jy~d->0mE!&DVT)%t!|BVOS+;v~ww{z`CEB>}U?9Jzx=w+|Zd}%H6^L?** zFXhUgzV-}_U!Tvld{f(e@bRa=n>QD02pK+?nj^jM8+bhgYfA`Xn1P>xfnon5U3-Cw z|K>VL6X`aA9$kJPWvdiQGDCS!f)@_u1GqxUl_)mJZ1e5Ss+cHf_^ z(_4>;)=V?M&iC$&^*ny#J4?Sa$*yBvv8cOyvR`wwL|@^IGndWhh8UjU<=80Rvi9UP z;XOHT-h|#z5DZ*0>6S*IQ?1f!Ru9LGaSJvt3}ED8Xowe*b6~SeuaVL9D`vQmR?}mf zI+?d&w&mx-#+}|*&iPg@%=mH9EOYI`g<6`a!3+#Z)7BRrx@1{heE<8mec@;8&Rae{c!dEv}EdF}S^71j`-%C_4UH6UK!2jm(=PkO1cJrJk+NTJ(Kc->wCeGCb-@wGR;YOOlQciB3f z1$#l_ZXq``a*|dA*@8?!mGyJ}udtKzn{a8_P>oAdi!oPoO-ssqigw@7h4~3f_g_&Vq+8)2!SIc%Ven{K1rg)clbBo}eoE7qMDZzm^j8(a| zyH@aXGSsoF1(c5nIP^W*UDtLyWB7W2LNmh*es z&s!&--1XnL!&LhRIg4f^Le@8+}Q)A zN}K2XeQH>ne*bIDi7S(g8-6YSJv;LMZ9A9Ritdh|Pg?h$ocDj~>9oSMpNHREi$9xm zE$DsX$vL~E4Clm_JgeKjVo7y<^-}HS`z-_JFP`PR|4Hrk`fp5W`#(GE4@tYWHjt5@`mbp2VKll#CEUNx40D`e)x9rMU^+p z3VuI+*DHJcL2ln_(@x|5ay?UP{#m=rk{$?rJb#?M{%iV-_12~_SAIyy>jYmue)Mdg z{Ir{QkE;qNeB>88(|Inq;mrODhR)lEj;wB2W^jFvEgxgY`?l3FCFSn$|~o8-Bk#^xJyNt|yf@-P3Pp++MXRbAy*B6T_kFq4|Hc_jdHl zt~nO>PyX*rKHIuapGxbEWcRE7yI*#C{kA**9-Q2NM|I`DllL-qN9#{c)$5o2b^F}C zsdn~zkFDF6Dy=Mb-v8UVdtROYyE{*eY>#Trdvne{^A#h*ubV07O@3QG)_Zw2 zo$tZPH}})46bvtOD!+0G&1?T@f17{DCXYD>N>)lIl~rE$o@iC(yUx{AJu}>G!p_f6 zE^i5y*i@oargmocz0Jie#=kd|`M$LOVtUf~B74l;g0qc2H!9`Y4ljGDAAD9b>9zj4 zcawW>CLM|S^)@$o=Zua2_dJxg-)-Hq;kEnU&28!LmrKO|=3#AS6o~IRc}CxNiKfqz zL#@2ic+Ed`Ffc8?`r^<3RXP&{;GcaN`_ zb@4VtPu{##`0;NcuIqsd4J3TsZeKLJ5)wL9m6f3(zW)98%sT#=+rNE}4gd6i&&QlM zi_X`~n(#R;+WzL%+xzy!|GvDH<@p5TIfq~V{8O{}^7pNOPV2tB9-ZqE^!(e_@4vhy z7gx%;vZcPiS=*n@QRIIvuT1jVp~}h`GuP>boR56`+jVP4*Q%GL20E6zex#*wo_z9Q zn|$gK%lpCB?a$IrJDvWQVDvln()-ZE^WV%kV|Vw#&HV5!XU<$rU+_JOKT_rKn;^a? z)A_fndzxO3wW<8LdgcsS(_co;+wQBeU%x$}_MD=X<<0X2yB1zG{d<0$q*lNG=A!Rs zw)C6s^)LOl*7iD2?Xz1qH&in?ZW7t4XzKnlGw`ph#qI9X@ylu+-e>1Cp7ZlK^X%WZ zttO-j-H42{jP%LnO+LHzdVjIrndgOT`nwOReOS|YY@6AZt}ja%KMOD%P%Qbh>E%1M z7bgGLrd{rP&lR$p;jYuC0}KptX)(XA_;pD$WF9My4_4u2`2OOof)z_ncJ1wqXk*jR zG%rbphFeenUi&xWSo700#dBtr_tri>=&!GLy5?Tb{U5f$uOA=RfAe4QU(3%U8~;~t z)ViJ&IDP-m+8;0NSL+;KWBKy;>m`L8c3UrSPX2hmx9roEJu`3a?w&C#(SPcuOBcdl z?>W_D@%(hC@wq9^lMjoZevmV3(Tc<8e;=t_^}1f&=lh*Xi{M#p_e0{P0~}pv&OKhz zofv*@`{cj!pVrOY;CW)r-o~WK|E(sk{a*bw`r`3-C9(^41YQhItyoxCSIugaAH&UC zVK;S|__&mw-x8Un%2aT7V)0e;YeusJY{gMuq=WR)9vS*%O-@JEItdF8a zRrAp$(VEQ+yfVC8A1D5Bj9aO4aNz~sJ*~@{mRYhe>`SwmzVoGuG(+OC(s}BhFY_2| zf--j(&6_!2PpRn4p?8m}wEh@aMc+5b)^%DsMdT?H!v?#1duruRR;MWv$fBy7xC{pBEG7ysNib=Jng;vZlRt_qK~a zU-4Q}W7YGU<%g%ue)E$*du{cb!yK? z2R(k%xjm=PgqbPNTbUnfo}1-z?{H61-7lUe8oqu{t{2WY&#B^{8hCErs|>Msnbj_F z2cC%BF`X+C@;34^3(Gz6=s(8NcX#Dq+zyChB>TU_)dU?TZ(xN}{nro#F*?WcEYG86@XSHx< zW#gCg30>Z+BEejBfT5K^F73|pr8<*tGG0iH`F+X9H;wgbf%U6ev(T5DpPj5ccYHD1 zwW@sC-c_NYv0g!33=C3_w5PYrEPnMekbjEdvh}q(?9Zm> znmu%RIq$&I##1ZT%$Xc~vv65rdFeU-Z~wnYO>KVPcGBa7f~5%Og!E6lSIT{=F5LF$ z%%H2Ef{d1@}5vQVRP#uN__>!?BJj47Q*C6ap# zkHH89lN3<~1{Q_}4bHyB&pflvS*A;<_Z2O$%=EKZuE5?E_`s6$&{wtOyk%RKW#^sK zROR4}WMyDrVsP+KY!wLt5lJ12Z4yZxitRE*Clr^@DdN&vv7m{|=!8PEkI~B|ll`n- zu2|e>^-5#Q1t)IZEtkA}46lYIuiMKOTT^__^7$Mn!3p+<0s{k!6Psj;fD;GE_zulw zGm5y3PC&e+z|a8lx%)&B&y6CdH_Dv7sN(-gCs5e*qOogmh;L|UXlQ9{cvX~lGLI{mW!BM+SV{J zq=14%fpe0Q=A^}*%hIyeWzOD~v3gtX=}kJPH}Qa#FfcN(fLz0{Aam9-43ri*EtN2G z$T*?J;K0P-aJ*3Fc%h1Gkjn8Q9d>XCpI~6%U~mZ1Ia*}mUTku_*yeb#jeCj9$tgZ( zzxeQjl`t@Yqn&}l!BFOCq0GsPD*i#bmy1lpi*2tL`(7`N4F`n?e%uI7FDwiUigVMZ zWi@aZPe=p@3n-u^7IHZAKx|@RVCY!*L}Av2S)b2Z^38g>V5P|H%Lh9{W~=X9Ib$|B z26N6yKAuy2PV>~vqYGwUm{okvlV{da2&+q3=AxZHzbbDZBnT1V@ncIT&6f#uB4xD@&dyXnoHz*``o-%HU|Vr zsxK{R0{dKnfuThJoQh!tI4MI?@sdehTBkHNpD{YE10vQOK4Xn{ymU;j zh9&oIeKxOnouxFf z4ucbiVhcD=PD$!9JU*w{&xsQf!LXcDC~|zF%*lx=-kVf>FX^29Wa9tXx>JYts++*MPx`987#2LVTgh zN2$>epk)X!GB7amF)%QSIW1JwW@@ltWN3fvFiFAlgGobj!eLo z#n?4WQdAiPSQ#D^h@8G;68OYo+S1HLCkl1EFS|@k&78HYQ^~~pvWwun=atJi&wsYL z+@jI7D3dAB#FvqQffW?&W*J^Od;u9JyciTz7!EwNnD(@Ckw(|D%vq~W73!S+>=G#A z8yp%t{c*&!=bei*W-VK_OYih0lk?yzDzr2ajXvONItHt8@hJUGC}pm2c0>g0+|9MZl!J}`(# zZBk|XM~|gTf{eU$mre^}Rh&A> zYo)@Hpdd|Fh6Y&+h6dRPj@Gs{EDWC*7&wxrB%QH*uHxin_-szGkm6E_;&YZOMUp{H zeT zBZC7Zw7YWr41_|!!7a*g-~lMQ=Balr%k-SIta6_EtYw*5la^$HMP}KYhlYOTJZKmf z#Rh^x&No!`G$@W%u3E))*~Is9NN8v)sJ**t)$2psK;eJAH1YPTRiKbQP#Sx^G*xm3 zsQT97W?=9yU|`VNkXYI>dC|rLPR?OWp!%}KkVCUYAc#$IiGY)bX6pphepz`)QT z0PUfe^&~=Bgc=`~)XGFP;ZONY$kk*(vkb4pP5#-kG1y{;Owqd~IS zYfUwu7JF~J8kM|etJ>n8NruOwve#_ArZgqU=$J_GnyuGnwHO@xE|I*(@Oji^p+i69 zf^|1ujmi%4(o|0AU3o03*w2eIwWnA2>XhPhtPBpe77Pxm5{~MUp<;=PImP7~z!9^P zk%7a>%kUT|g@Mvl&=QH_GnUU4T0lLqB^+Q0M-Ign0Vfa1WSGRlmPtXUW)z5?fyT#79M zU@Tp){kQd0JAg`4mA&5mw zrv!m@Xo4*A(p(Bv2kILKc|pwsTQns|3&Le!SilS_{gkzIkN6p{vte=@uIi9?fZWowVt(ixMdIh~#n z#FM0LSkhzYZuvCC>9_;~149!71GAu!Fo%dkVOHPC-dUO+!mZL9nzn!w&`qkD!K*j*Mp(RyKAHPA+a9UOs*SObiT+;9Amwfsum) zGzJ0cH#0DBaDW}lZ~$6Yfkr(*?b@qMm$-x@qW@p|f9L=0{}29O`hWHRjsI8v$JoX% z?ws~>a;ah4o5`QQS`~%-Jh@Bq@V9@*PHu7+kX|Fk{B`~L1Q(Isq|l2jlSEcrnX*bL zD2r8J_?qtylO$a$kqupXy-H6GnRRGLMe-~P44L|Vzx{7fhBdb30Su3BPVQb<;m}k4 z%T>|+*Pof}dh-(YF=(G ziniM(>nL#BemUlCbzMDaO_oTjPg3KB_=h44v)t}3PIj+vn+Q}#{O=Q&Tj=5kJ5GI7J&?FF zQWqNwgNen_iyzcdOaqU;;wfB~rGMG&-kRzyy?L{~N=lZTzO`olRgW`5rxn7tvT_~^ zabWk6&~UlE#)P9ciH%if(h3hTQP&AN>?>4zccgr{WHx0=FV}*k^r%T@7kdtMg(hm; z+B88qJ?6O5t+d;oPa>b z8(EXitzh5?RSgYw&2C~)P|`Asx|k%yz|g?7Ay1Kkq2X4Bqb3&v!-5qFxjM6tI59AU z9u06j62+6i8X%Aq7I`8l#Kd~?%Fd`Rt_H>gLk5O~)lnN~%=zsiq?7z8Lo~DTOtB=5@fle1UXCuLirRJ=CyCtVw@u# z=X6xay}F%Oi0Pa3yX0eB?$yg<*?y(u{nTX?JHz${N)U8%M9gqwl0@8+$5gNvsA!yW18c|HLp5ca}9m`w%Y_6e6m|H)1p{u_rV2n zjT20oR$(pME#bgU7%LON44e<@(Pgs{E8LtQpEb!hck;^5PHhURE&&}j6 zSq?LeZCk9Q1gy1FqGu>vihLEZj7h~Ilr=__F;Mh`5UYTT30Fe%B9Vm9!$FK2mQ7ow z#lX;!Vd$mEz!0Iuo9o!QbfMXDvj}5W(<_Hgaa=Q6&(Ls{tJ#}@!DMOJgsDtToJ%wW z92gmxlVlrs8CG0XU|={$h7LAX2EoOr^z9ky)X$2t*l@4gnABdecQT&{!y{{r=Mfv7ZSQBM<@PN&Yc_fB zq2FZ^9C-!|jxpvh9PJ-)o|-jb=7R=18Hcuq`L-L_ERq%P-#z=1NmC`k)%UlR`N8uk zzu#C){K6c3a%1ry4XORBx1OFAwMK-|utSk)SuZ1lp`!)^L)YF}%T_QkMd*Ax8lV)c z^R4Yxl&+tt(Si=cthG_i42u@HW%XZOwTg?2q3h@hrPZMu-9;G!Hg1$yp*4|d#iFjH zsErFW3O4Lr>X!CcYUS67#?fAmx4j;AO$iX2!n){IN8w^;W+SV0D{dtUvOM-lV6{1s z?4YuprJsStxnXLL!lDQs2PLyzOO?LeoYddNBk-tUlc&N4UyntKhK&wsZaK4;C8Zgy zNjG6QEf&mZD13PqQ`?G&t(*ed*WS3US+yu>me^umMiB;A)-}NlJdA6i1sj3_879tM z#=yWJ=_qoMmqUSJ!s&+IFdoK25eGLH_2?TZnTg)78AFdUFfj1WU`S+O5MfegVc=L` zxGj${U`v!EsPYoyWmxd-n}nHX8XK2F!it5F9TKY))Fg!iTp0xw7z{RUI3RHQnkp*; z!-Z}xh9u^M2#tmnrpyi2%74xUIw*Fnl9twKdckl(LZgBG@NUL?>1WS~{3zS8jn&#E zIBLG>Wy6kg_g%;CrL)OY9Vd>(z=fav) zYVTS^vgJz6nmSi{b@-7v(~g9QXuHMwTwTF#nzMS5$taH-oC5?cQtQs+7jf|Cvu}i zQ=~NHL`FmG8b{4g13gCO*Gz{V`1H-WEY-jyv9$F;NLS<5D^45FWK3)7+PIq~fGvSR z@kD`Pb5XAiS3`dZSGK^4uaj99h&5y$b$e|#i$RfLk<^!Ns|8(6t)&d7JeVXH4lL|h z#K^$l63Uv)!gA!yqNS@YNli0|ke?mOYH%oO)hdMsMuFrvo7P6pYD-jH)wRHBTTkHD zkZe^3h8sG~iZTfe%^VJM8C)J;Ug+4)7n;r0!_lCnmAs)>i6QBz8aE?13&Vl5BdeBb zaxrLhBzk+BvIq*UO~^U2fWx7h&088Yq!eSyuz;1pmBB$w_gd=p0Kch>T1jUQ8Sox3 zaS&vXl@erSmg`~a$YEw+h$}x^$x`^fVC(dUb8elD{mkchyWHY&x6JLmtBs5|xbie^ z`D>|ed1G?qA|-=w3aSse*!Y+a>lHMM=~!$QGv9sSi|*8`iI9)bw(N*YRT9jm{CKy`w=lj%728M>XgNuW6OCnZ_8j6Xygl;mr zp%JE&%eaU`MmuOm0fVEo;hM3va zQ*_h{h6cyLk}f~)giG^(GCGtbl}Ix%vV`(9Ya*k%@s}&H*C{R_26k z28#s;RWCL-Xtmu?;F=-UmD#MgqIH!-Sm1-1BGHTtb?s+Wc;-mId*sT>yu76H=7xj^ zHU+)nqKtDc-OatoCcR92<5Oevhs_7RByVrM3;vLiWUv9N#kC#li)}6?H;Xy|G z!fk9E9a>5bMscF1A-PQ}85kL4E{FKI7WgtOJ$Q_b?3=V6TNiAYvxY2b~ zM1nAR>{ z;C5ra?k;x+2hocg9T*oVFSw?b_BKl3szQhWOKg+lmsIT&8KxqObUb{da(zxK$gB#N znbEA#BtP}yE4fA?=kJS+#FVZv_C#Hm5j5~UupuwhSCmnZ;Wf)N5r$rljI|6Mj0_B+ z8XGtm7&^6+npaMXjM{kOwg^MOR?A|hFcF48ZL?O5GZ!|jVwkh^O1Qvf zHc%=3TEK)MjKN{Cl!1m;#|Q4ua@+?NL}kyFV$NWQR!Go@*vMj_A;rMGqDh9CAx`|P zE02wETw80GgK6{kMUG4s>4#2lNMOIoQ#XGKpPNgUkHOoCzwdnJie=&Zbzs_kA?67( zu?wbun;j=@uz~X^i&&qXOhz-i5rfiIP45RKg*#UUS>Ezku=Ucybz7?Z`!qc#-dyzc z+qukFLdWl$S#F)t6p?dvnVf;?QMKC%OhMx71*7y8vP4U7Xgy$L@LgjXVaPp$OF?RV zA6G+f=B#habQu^F3OmIF85mf1pNL~+U@+a>+t|2hhLYIfYkmw2452x`(X0#%Yq;Wg z8!}(!877o&*q&u-EkAkhJV8%h=h6ThS6@*L1=bCHXBF>og-8WDx}~mtkjA)EK}<3r zHrJV3i>Ygs+LlnBYupPaw!WUAm2fLnKqEzoOUSi>rLADmLsKl8Vj%CaSt5yYHT*;RH9E-~CQ8kAJ-kSD1a|^~ClFW*K`i{3>W;oya{WvS2ZL#`lfOc@?HT@`#b< z4EeT5wdn1}`S0%T_LOnHoaN_ZX7Xd-k2asw<_Ly`pI8|K7(8;{@H&T1WSMX@$}l5k zYsOly5}hyx2A9V^napx{Og28IreZ(+fV3=ES! ze7kuWl4hteXf=F`D|@?nxnpmH^&PXfsikYhIb}mPPTi{XWW}n*OBXJ--pe!FsZjkI zv%{koZ&s`mlgQ=&c5SUyhsFvc2CE2Rkgn_}pYOUcSCqBjtG7%+83=9na)-AWqbx~AO>T+WY zaP9EE(=2+>z3`jP z2DuX_HA!)r?zyGdb@kdYmLu0#3>`#FkGQ=$!O)PDoh2mD!?5bpu1Snn8#TJv8MbbY z$o0L<#=yXGd6m{IM@EK#!?#zjJ+ z)-@~klv(*FQ|!w&_8m2Nc4zUY;@bt2pWZliY1c$;f3AbKZfOZ+g2yBn4>*CxG{7q{ zKw}q0yC38Tz5M_B|Be6G|3CQu%%HxPVDxX1x4uwjGVK*@m8(A}b{tT@)^CZeV(up?D-s z(0#+KgKQfQ#x=4m_d;>V2!rIG6n`F1F2Bv z18#@8nieoINFC6*bSSEK1p~tYd8T7dBCJ=~91m^?VOX8TE8_iQF0-SFn>JU&iUv~# zRu_gZwh|Ts4Exe~xtVMEPW@fBSczllk?LzPlOEh(xb=0!N)9H?k5ijcy!m);gfCoh zbl+W$1OvVW;?JZTyk;sKJj!hZ6Mf^ex^Y5AK2z69N7lv5nzpZq>||i* zkUTnDOu&`FWpOC$#%r0|B6xgV85j=7z0r1IV7PK@WtcSsg9ER$=n4jh%`2D1wumz@ zta&v-Vj??3;E_uqA`A?H(b4(Bk&Fxi2PN-|um&)Svakk-I=H$xx~x21t+X1_qA^<29MaEo>_^XP-<^XJAOs@Jzdr#l^9JA*>|ZQACu1VdF){ z6$O2-lx3I}n9UGd#lWDl+-l8A-UJbs2}|_2t{piL#CS!-CHVkH2FrmA5eCDEAFK@X zwx2C$dsI8&UGg%ej(_#H&zuOjcl?1}iq@nL_1m9bVsy+lHn%Sp=DKxfLnG@o>0E|u zj2wFp6l`X=&8N3a{DzBW<-Vm#euYmm%C!uhm+0PI^R!O3pzR`!Tg=lkiNOtip^icu+HVq1EIV~bHzY_391&dilu4p(4 z@SIt|!yCZnz`+r0VCsEr*^EUR8eET3G}#ucXjpP>lfvywCl;+@U|`T#*eo?iBSpDk zfwO6Y;W4WaR&Iqgdp(<%u`n=nPm0(mqJ1sIHIP-naXnW8k3tfMnPgVuf-b3T2dp|e zI2sN{te(ciz_2KaS!{s@tFf@q2j&hXtD|fT2{V3(+9>igEDGjUIN&P5vL?f1)+*i= zY&?u6?pLK6R!yAQ%cY>ev}h|M14Es;>?)^@!<}U^Ryv;7cfSk}6!?F{Vtbro@}_%^ z`s_-H=O@>4ND2k5Xf0<_$`&!0@N62JlO6wsV~lGLOv`u4n>=IgyAv1Rg)kg8D77&V z&JX5QoE&;JJUULeICn~cfNa~`&aJ8rOK&am5HaNPiZ)x>G|P|YH^&t->t9_u3=4MN zb64t$%n$U$_*S6ECV-J!uD%*|3UQS{=A7lFwcY|Jb?3cGW{qE@J|9(7x-^kCDwS6kVc6NK(I zZV_id~W=SQ(c4&E@1_ zXjmJPbwGf@!Bsc)P00p^29JddVLZ1)7O}82Z!3J`E+QPv>ezEfEqigUTON7GGhw%y5B0J7$d|LyM$NLo09Cnh2AnOk4~d&w4gxm97Cbk9)-IbsTvQvvtQX zvM@+W7#|a2U~o{DI+`6Sec(k%X~%*n28N9h8~GRy7rQ4+KD$?0Z?E-&i0}Xg1`C!G zH5yti91ROtb3QOLY!GF2Wx2o4rLr+9cPD1pi-W5j!gaeiyoXw=bba2botw~*)3<`@Dna$8*(8%Jl zcpS1J{K$sWK`Px!Th%NpzVK>QHBXFuJ7tD*RNBgp-EAurIe)9X&@oHVTDaBaxgOfI%Vau3C22BZCv=+jX0n7@DG1_1g0| z7_RMJ8W9mH!Vs`QuWe~!W+$kll=L^Bsi0x1t9FvWMn^_&=QX!7G`Sd7&D-S#3tP+Bp~10>ONGHMUG@XVqsj+z)o%j!TfA;iZ+zb<{(8lN#ozgCmCDv!?XNwz z*Qwm_j)EbxU+0lt27xy&?|!?cDVz^pTe)v}P9Mv%;6@A6o|kpmFHV2^muUO2rDfrl zx(`Mczu9L6FP3`MP`f81z;w+-j?P69jAxES#i}-J_3PNoxPc{FG+fkxM|$-&?FKES zWogb6W-&5uWm?gt>h0!{yUImIjB!fh@mUk+Dlh)VSGmn~+tILWjhpM6yC-uWGFn%d zax*TtK{QvBwNpZ(SnhL`>fQ^BTL)vGBz>y$chNEuXj4mvU7Y;ttxn*{w;AgFqqbS3Li5q*(0z-9A zoV&CoYmwF>WwGSVZ7aDLk`j9i1sJ$YzHfZ$F>U8U28I=_y1F`RS2B4qH=Nt#7`=Mg z$^{LpT(^~O+$JRLV9>zP*4nYEl#zkqN`Q;wMXojmi%l20W^geuxMf)LurhQrmPEv8 zFfcHPU0b^ih6D$mO@|m580M9q zHDlPrelE;VE%u&ixZ;oU2STe2wJ*Gjo9vMH1O=R znqlc>DZQa@8MAef$_7EV1NZ!Tc4^(a7q$9)+SPUBA+du5&UlY%3MyNYJ>M^lOnBuhxQ~bWax%h7du~ z!%JEcmLKuaDQsg{u;AE)w`JO9b5n2Yom6?;Zg4*BhG1u6SAZgqtHRDjO6;y-f?Jss zcd$w7oG~}cW;?8(Ez z;Gnaa<=`2n)hkS$9T_(C&1lQ?Wn{RrC2eN(WqLg1cq#6I4Q3bB6{%#L(-z>yUjTi7DWq&CNnr}Nh%O!W?-;N?PWO7 ztv`EtaPlY4{WBWw-(q+m%8(#<;--fNPs1ufhXz%q8`oBLNo?SAU@^!syK2HJu*Hg} z!LfDoOx}6vvKl)p9o-V#agKWsXAV_}r<+ui;}`Wu#?;$I*;hw-m8 z2gi-=v43uSuU)pJs9=h)8-oagPFd9ECM5=ju9Zw&OpyY?t_MU`&s~|dfGfo=I4$!= z%;Rg9bWXI}ncO;-X!$;J{!0bhy!6w1a<(L8=iHc+Y_b?*5E2J-|2moKvGa^i8(nzq$LqwxfT@}}cVr$%&?U&A<9(8 zh9&0(Th8)aUZx5G!GjL%i&(3cibm@stx!}tvEq!6sYu8gNwH~c7g7R@dBg&@Mws5% z)05QPD;nN-;e`;lw4s5+6}L4?4G{_r5#~9}iVPeDDGR%99CG6p4-q`PVZ$WX*=uel zBraH%#k^qg8(ri4QU*bW4O_F_7#J7=E~c!Bxgx^Au;yk*f&nXou#gAa1V)B~N};P6 z7}z45B3cZSN=+CTj!8JDtjRg+%fKMeaPeBGBdbfmrcY^(9o zJJ!VvWiEN_I%k-3Jtn^3>sY{^e49U^fNje+c43EWnyZ(vq?L87 zSA>?kG^dQD@gm)lJyJl*5?p~)CnWHCj{fyn_na8Y^bBY(}uFzQ3@XTekLzwZE zq5v&%f#}uS%>{I_Sf@BSdn{m^z_=naN^^z=1JjM`Ix8+DgbSF8=!BVOsVeyPXe?4# zwl*{36%Q+eLyq9;y&X*&LY9UB8-=?&7b<9Vgo=n7Oxl||b8X>;;%jSjjnaJE+g44L zGKuO{We}a>5LwQ!rKv~EkzIgQq?>Q6V5)8d&jROVYq&ZrIbNDb>gKX&$4PfAJmS=} zDp3{H8=-ZkeN6 z3Y-kR94s@M7&MYkC%7^m-j#4tp^JebA(ESc;Q<3f!@;bT!ps|P2Z+e7;&T;Y%u!cW zYT|3|ZCjeTsy#SVS&4&z!9s)~qC`P~!R3gR!&Zd`hDBGIBp3{u#4j;7Z2Y)jBkM+1 zhLr^y8|pYz7_TlcZ4lH6Wnh>sav&;HosDP3JcfDdXT=%6id?E(5yGNs{KIdSKhv+^ z0$FWQ$D2I+E**+T25?ZCDV ztQM>c4_FthxYp$0wd!Sta^nf7m?y%U*G@Ex2$Hu~P(4y~(JjS%oy@^iN|CV)`7M*K za5S`C+ud}^V3`*~P3X);41UbPIgcOR6>|)5n95M*#~3OdUA?)1$!i4zgUIWvT^$@V z+SX=kupSg}ISCq6W?)rlh%%JW6_t3uZTpEJBlYC^ZeKA==V{Y)zjby6-?ZZC3<-C5 z(Dv%q@-p(+y%FC$pf#8fl1O4ORvQh6L$fn}x3b zzx4mg|8M`V|G)PC!T-nqPyhFJjxlsMEE5xGUChMLol(LN<>N1(811d z05lHEpm1#QK^+DL7M3-Uo4FYFnm4Usa9}9OV&!3IV3IzV0h%kaU_aJjnjp%^z;J z@>!Wx3alL+r~RT=AI-VEV`YkNuQ$iWJ(F(tDsj&3y|LJh@k`yTPyxp)i~1a08AG#k zOu`rsY%%l|WC$=6W!P|bh6aPuir%Rw+= z)R=Zg2&x(^J+>)|fz6=JL!w1M;}GvAMiGYO%*9dxH(GqJxdkZPPP>}Ja4vv{=ZaKr zh+Cw?a*iEY3B6&f4+L0pMCLG-Fh~W59I?>YTG+#y5yrL#)C6K!%p+}hv~7*nq7w}> zG_w*DGo=_7ELzrkjmcAjf!D)Wl!5!T8Uw>0h7G+84N6T>TbC})WL|V}VW2h}14F}> zRT(7<5?ns+?l>4Y%wya6$(iZl3$uv{#Z1SW zvUnMk7#c*ju5{fR#_)k{LY5L^&ko^AMOK@mK^HAKSvJlJ?(6NFn#>{WH(RqOC23J^ zZccf@*_XGD=FH|(xw_Igo70(h^2VrrXRaLRDGy-T5+`zDqIu|5lWzaqT-~ULf|CmQ ztPb{M8tSlWDPQ#2B5ok%4JG@k3Xi zQ{ZHwXh|irOqGeg7Cll|PNb#y@UdxZV4oW3wL5gyR)^miqDQuHIcYfXbZa;W7%Hr? zFm2_SqT#;$;DW`ao}6oR7+hU8o-w+;sDtrBE^mXBf)%5qAr}KfLq=G!PM~(A39EzS zni(r>R0ZV3LS(x*qPY1IE;FrUiqMI;*i?ELG(IiF&@gM;7EeKk09MiLtjsQr*RgyJ z-?S7M8ZI&<9bsz7n0boff{V+VKv3Q7-SFS~F53xhMJAO1-iD2SybTfCH?TN3K453K zSAJH6?W^pLe(^HC>p$-7PLpE2$GraIp>q$V=9f!Jvw1|@<+BKQemSCAqpnirP}h*# z|5w0aS>gwtQdb5}h6kKeN*Opf8w3I;U%S=HoN#2W2FD%+?a&b84Se^W@rns8nZS|e zvQ~TJj)N@~)!PdXWajg|2(U6Xy<+hoz%=B5%aTo|2ejK54RS>0PYubw@&5M8TTDx@ zxVH6H6lIArF`S%fv4&}dzf)4y{RD+?+ZY%YbYzQUyUaEBVP<4FeRvg9f`UpG!;O@$ zr7R2#A)zNbCavvC%D;8vCWiuOky6tQE(VWObtbL`(@Pr@7&n;nFo;}caLLKJ62@pK zdixgF&E0kz>=*A1EPg9J^`&}g^bw;~NinRfj0)a+b#+44OehSHVsez(5#q3gnQhNE z!3R^>1UASdy127kFkG}nGfY_IVDxrJ9s%y?(j#esXEw2giRP~1XWhVI@7F zZfh=f_6CXy2y!z>n5A#YlZ{qLIt%KFF|dg+n69~zWz5B}f>&wL0xbq6hQ>}U1_lPP zW@P~eiz)FBvqZ8bG$fc57#d2s6dE+Tu0@D2YcME91%_U2Qd$+bWg7T?gjnRCn$XzRh>bVIJGYZ`zFi99aUUZA}Se z>~jqgY+$}{e`mf+9^Xotpl5y(jM;bJUahe?L6g#oqXHs=*{a`GF|AmXbs^>GmK@OoNjYYdSgt6sF|ANoCM?*k zt9wQ+*ZcOydYxq3-M`oLa9(o`JH7OWM)c8h0;U_yygub9wav}DAhgkGtL>BkZ_`|E zNktc%K$~XUHH-qn`prvY7;05F7;1=02Xbg`j9Ss7yI7HNq1&_1MkknBd>Tw9xb6@V z=3qUUGUHLonS{*j+mF9VF&gS3^_8c_(idQ4g29eoTxG zIic=nH?%4!C~!muCo?)6J)j__yyDiOZJLuqL%9}kgsn|C&}Cuf<>Tg(U~V~g#p5+E z14F}(uBhz+4vZ`eM|NdqdP|2e1c-W=QChnY&eE zi-4VL>+O*r-LT=vZD&^v9Ji3DIy4YGr5f-uCkFrcu1XgL8 zU0W)VEO<0E!iQBspr}nLM_MW5z$LAY*38+TF0wx1n#3hywoLx}g}6F`G+6V^xGwn9dsQ1&bCjENVNOw9?_z9|i^%TQN}ME_=&0oj?W#QBfD; zU>-*X2Zk%VqN0Qy7>*d7T++6*_3SkfhYhZRuHp=u6L}aI8pLihF)>{8csrM)ih-Fy zidkzBs{upCL4Hl0>LtgbSPpcECnUaI#m3+wA{x!j#K7>+?Cyocj{M^S_3u{-l+2sW z*FR%by}NZ%zwC<==lOROTWx3VR?pcW!?Q-0*GP9#!=}6myNwz5F*4}n${Z+glwV}C zc6&lROG@D6122=fvl~PDf+jjlT~TSQ=ksNL^z4%*YOA(dUUT2D{qWk=(iy&&uN_P3 zSRtN%nIoy{W0p!_sPDQP0qg;L76k3|a~C|=!PL>k!6tf%ZMpecHiikT44bSH*t61a zFfk~kExKmF%gVswo)cVMZGAax&9cz9Il=}m3=9lcqF5Ya16>&cTykzpRX#ILiI{uq zYR6Qwl|D<_o*AAxT(7RBPU zX&PDjTnY18m6={mGi76Bn88rZ;-%B2=<1YjYN*4w;bfFv*Nsa7R}M@Op@lIi2Fg(5~1{9ZBeJK~! zx)}o)85oWj=pI?daxp!NAavdG;LJ zY6gZCw^CvSx^+Yt4s37{k#=a*PT=chXur4bv9bi8K**K`1_n0X1|~)Z(Qa0UEpFNj z3X2#WL>l-R{-w$GuoT!U{NI<<{^nd{yExCI`VIXXqTW2X-z|G&+H-a>pM{$b9OODS z?>;kg#>S;5TgAI(=?Ev-CznS$EZOl*TIE91<)dXuk9t{FrJQ|L^X1vKeQ)pkorz+c zd#9@@L#s2brg?8;(v`^9YRwC@+IR!A7B4y&z0^Zy+k!4h(_9xpQAP*Zj4jMAS2x^{ z=3q+VkjN3saR_w{a5)mUdF|Y}Hx<+x5;d}RH7rnKlGw&KD~xs1<}EkRR2d}kB+rYs zEPs}g?oqbZGtclAo3`5OZ|kqVd?fPrQ-iC&OW-Sh#t9D`u1qlW+P3rb0@rVP+AS9Y zopwZTI(Uz5cdIjBLg-QjwP;=Lse;}-4zs(m40xJ4gqn_UtzcQ0&ceeYn*3&?;M9v@ zEN6~fSu=6%0$v5NhA8t44~9SihiFcjMIjsSZF_r;Q;dO0B8%5FpoEKoA;46^z(A_e zO*i)(Q@2d_Hg*QjwYR1iZub;rV01W{;=MI5ae)Mb!;)EC5yFgH779Gj-Y&B?dI19i z(}HX5;fxkn1+vX<9lA72)RECacdf^>HJ}KNh*&nwjF~|xA#G)ntLOtp0X~J;kC_)) zwpzI{Is`hb)mBL8IOP14N$!A^%?9zAnOn287F-L}WngtRVMs7oBDk-eSBv4EY}}*P z*7Z~J_-AVhJlg-zE-vDS$IEvvTNrQceqJ5-khy7I>28&2rn$<>l@kM{858FBi3#X( z>**{>+|W>Ar4;ADBqqFZd(_!ouXeE=pJlZ=NvgAUVgAgX&2#6J=sfa?I%AT??a^`k zK+K8;);;7s|W+56l3&^39JDZrwR4mIdRBTGVsb;sY*50 z!?QY=It-_6)Js^c%8{g=ypuD7NrOS##G!M=jS0C;T}!zK~9T{0fwQuBTur=@|$Xb zV)4Qpow0_lp<5J=G8o7zx-a6$NJ(d9VLaeH=c)^jp@5^{nzp@M2@!93x)(4stmw^* ze&iy`pwfJ0b+0U_5DS>HON3!{HuJL320`a<>*{lEeoNl)^yXXR`HB43-t0YUk$<&l z{nnn@S9*lr=xk|ih*LZ}LExC)7Y(Iri{e;ji!Bg~Sk>T`(7SNT){P6BL{^+inpE!0 z(9SFZ9nt6lReF$}E})6>?udidLJ$5w|Nrs-lmCbR-~E5<|HJ>+{!6p-h?wR?3&%YZ z_U&+Dl!#gKp3Uu9NPx!KS+SK&+e{ia`D=GqYAP^D9c_GJ#Go3PE8?ouyTp)#VS%$_ z+DZuqhl0*Ui_C5v+O@QmRY79wg~lZwObx9}Nm7elb$qgyWm$tJ6neL9NL#G&K!AZk zWXn=t1}=t(gjhy~*@BJ?3|E+3F02q^aAm#H#kVGdm4U&9!6b@-!C_6bAS;7Fw&|j) z5&|J}S8LlMD>=($AVO{IQN{=d-?&JI^$S;pyFnsV_D-|Gl5dc&9K+2n=0x;!#9o zQsKsHjTRe?85vxTvNAX-IWru)_iab?y+!Strz>A;OAT}8>N~okwDCyROOr`jybcq1 zx|XF}d#@qbTBuw+O(S!m#Sg7pjw=PW4X z{jj|HM9ec|z7>T9lV)X~Y)Fz|hOE zRHV^hH(Db==OB-H!e?b2alx zy-ofcT-&miOx5z-V0_f)7S|0I&KY9SqO3=HgjyMHMyYc(G&-;`OsG11kL3Uhqma6e zq~OY%r#B>bw^|8=gvM^y$=WUG!s5*PO4=vX88pMT?%*;JM$wS&RT^4rww;%Wyqs#a zMETlmr^LCMZv~h5>@A68U=m#5+*lxe>TTFrJC-#L`@$y7+Ty&hw0A+q+JhntirwrN zIyY9NGHx{#+#G%NQ2DnTJUS|79E}$g7#6Kkac-zv_)LQ_O4sPL?tv~wo+Rfm=_^bJ z7^E0pi!ie>C9mmZXk914zz}HQ$-ux+sV1se%+_Ec!oW7~hSF-TOBzfwB5wS?(XYEY zV(ZeRz)~g#i3T?I#*K^&YZy+jBplg0M`_!Ji>sIzI!a$h99+fIrlG*laB7wm3&R14 z9NvzGj*gDZX5X$=Of$6FLT6un)xng&?ZUutp(%lZ`9ZVO+Gs-_2L^^KY>WX{SQs`k zHFWic1v0ppusJd)F2?Ty%MG3o6^i*}xqeG{1@-lkg5es?pI#ZE_k zZBtWXVNULwYi|WNsNOSa)e&g4X?EK6A=c6W{d9G7Zx!IH2%ops`os?+;REC$FjpKC8cGU7#e=0$+*R6l^#}L zSTJEmN94*G9a^hqgsv5uoH)}--~!LFeTF9;-NIaVZSq=n=3D08U3)Zx9y=@wyK}%H zfMr9N$GXMkM|?JE9uQzTyqN7&Vh-=dXwz>j0t{gutt&RK>`d|%ViP|yNj1@hVS$E{ zfYVMNtz}GaR@JU+nkuM~bIzbgby~wRhAL^3ZmtzlTy19;IVk4NZ(Xz?!E|!2!VzW$ zjSCyP*cupJ0vkN~-rf*dviPOt_3Zs@;_U?re5?!%4`#72Ok-kb2xZLX=`f92yQ+hO zEzo3EmTr(K0~51Z;@MRTIT#iw8BHto5#F$hu}7ET(HaW|?JhP3h6mvrcot+Z99YE7 zp(i18p^JtZLx6u)))UzYaA2JBRi8j!BP0FTY!t==dP}pm)s4m#Z?% zXC+QbIJ511=Aqxyrg`usOtQbgTy2-RvC>Sb>tjD>|E@ODb-B+=;Z-c0dEE`}9R8xL;T+@*0~Yjy1Q zgYQg!38>-bmKReQH+>z!86o{^N^!pOQyE`;58jpj^F4i(K62aYyKgh^dEy^GO{ zk;O1T#rW;3j)p1MS23w{&$=*6ZPGC#foYts9EP4wYQ=NKHXPVur8FT;F@jTY>vRpr zkhLirj;C2`bCq4YWVVL6Lv(f9Lbe4=0XG`>SXizekYaJX*3jF@n$hg)#+=#A%g`<3 z5x9|&!6iCSN04E4q=nbU5C-YDM|q?f7(BM{Zrq;6$;BqPc9pZT0>g?f(bvf{mt{r; zI`T9uNa$U3n2DhwBjipwW2%Fr0s}|ceFhoM4So!QjEk?XTy$||grmU0hK;K(TW#6K z(cpSj%Suq1;lL`k5(Wl_rUlmonO81v@?m)yK0)B3783&lPa+qKD-Xk>qg_Y*Z8!rq z=1n}Q)gY>KbXO?r#;j(Au+WA8la(@NEON`wW^-(e3#k8ZFl}>L@h!&Yh3B}_e;CZ! zT=qW7Y359q={aluPhja!ZsaO)&YKENBbhDAL2W22X>5#xdt zo)b3+ww5J4kt(KF! zegx^aZ&X}F6hF(=FiUJ>lnxUEL&U}?9&6Ur*sqQ{D^>;g>P-2vVa*1G7ZToYpK_kcYGmM6 zWSq;%!o1L7VU~ykV*m?ViFo5}(X$*8tAiiAxF~2wE5D}^Ec2R=GVJ-KhKn8{!!K)b?xfYm3Ff=JCyjpNz z*V2^?3=CParlJDQj2CV&EC^KyP2+pw$k~*nsb;p4sZGo5mIi~EMA#ap8xh>RFeI@S*AO5 z|7CT!t5L9lC-3qp7NIgF@i+Wmm=(GgsTn7pzNzRMBh5KOV(BgU4M&#f?X!!Rob5VU zlzoz((3NF{%i?%)CR7M-@H?h><0hlRBwuHS!*L6_+^j4UwI8@L2J~!YSRxs4_?ifV zK=qrLXm%Gy1_tLhJg$r;M>i}AV`X4yxze=gz^}CtqPu0!KQ+lZ^(R4fHEVKM=Ms*# zWgJ{d225XO9gTamPH9&3kpoUIE*+XQL5gv1XZu|Z>E1R$hLtgn?$f)sMewp5Y-=`R zOu6piW3)_9Ni6X|Tx;f(O4ekdY-LulHcKwX%PvL?im&^YHp|}NN{HGzk5ytDBTIu% zLl09xXs_eNBnO`zObuDf4zgu1FlGF)X;8!Og=EvBe=&yNe-W>qV}n1q_cmUfJ`_V`g~wYhFf!s3^k)35gn+ z1q_U#8}-^4BDBH;9drb;)fyZxGAJ~NFw~Xv3Nw9^jyvq?I^kbsxV6xO-@WhLcdSUb z^gotY$+;^-iAmCETj|-}6U|fB)Y>=jer9zDoW0{kbWK3u%4ksrfl|SOHjj=&2M$e~ zkam#SmZ59KS)ns?=Gq%jOZ45tYro z=cuC7gp197pE*BFZsEMzwfDfA1v?p&S91O`ieL)qVp_Y-RAC`g*IBdG4IW9R%?zhF z*R-glL`HR8NYvgGx%q+{SC5X#>9k-&UcsOPO8Y0@RGXsOabsJS_oXuoA_{Am+j1`- z?3&f}<%QD$0mb65K#eu6p{yH%m?e^yCucIUF)+yP;xS`jP`H+Sm?QbhvYzHlMuvoJ z&Nk6#Ee3`L!QN|Df&m$qt|wk(VqoB6uqtI*z`&3s+PjE}K_MyIWC7EPR$X6*00vIq z%-f6+#y+eJ41LwjY#YKD7)2R)I2yJ(O#X3jRnyYeTPwJ-qQuuk&1z^&YGz_u5yilB zXtg6ab#dKb$jZR5 zVWY%1vo=-+21ggh1#wpsj;~wWo}kmd=`_>DsKBqQ935Bci1KlFD?F(oOd zLnaK;n?W-@3$ATg%BicgE3_mdL{PbFMa0GpeNvnZzIxocxdtK(3_Jna*N#{*bTBxq z6m}40UW6$O{b=e7e@}(H`A1 z%yX?+4HoNW9qox3P@DC9Rj~&CbKq zy0a%WB!!vIPV$m^o^rv^+AY}h?X9UN-Kw9zSa-0b;MkVAGqP6nL>2N`#&&K##uXqe zb7zBaP_(IM(~Ng2rD`*-i5wJI&6Kr~i6P_CydSexB(O3tF{rt{deD=(>L?4t6_K`e zix?Q(QnRzKurM(2Xqq)~F^INxWUiNBV91gX%bF;{5F&E;+BPNzhR`L^ItOlvyj>mS z5t)5;YLefq9XC3x+Yi;IYe@-uhPXlpJk}uwJlGi+7}mXwNNjb};o5i&tZ}BOP32Uc)3o~RW)9`3MD9~Y| z_J)}utMBYaVOB});>88VA#ON!@!i0BW)mM z(51;BmZZFZt)PL4AzLe=gCVQIkL3UxE5l;b2F75fy705&JT}%b$;bFUO$k3M&h_za zLGK3VgsSjX=LwR`6SwrhQ@nYLeM#v>8Ms7&ILcBwUtH6I(X*>+OVypuPqsh863wvzM7Ls`4^))=pAf z9NWdf*kJqmhWa;F1_zdehHjqMo{S6*M-SxP^^rWoBcY+xH6iKN+UtA)0R}ooX zZIN(b6lLhS$jI>G0!ITQ;}%dy*!*mm!(+=2SFN;uT&m2ovI$abWq-Q#>y4cy`#Ps_ zepxPV8*Nms*wQ3s{z9?wtrLII$HxtKAM`Yw-Tm{<5gE(am_D^c7B<=DbA9C-J-6m= zFh707Wo}e_`l9xokJFc{r|+4&c5m*7gj*4Bd{;kUa}5nK5uKeQ$huKHdydn_Yi~9r zC_mb0YQU(yD(P6Klo>N$l&>@6!DH*BS~WOVOt`5PqjURu=9-FQ6CEaMOjWoh+Nc+} zK!;}mpOE_2yw*3&qG!9F7;I!>T+!t1ylz#fW6lAd)^ay)#;M!b9oFt-m~}Aj+&Qk5 ztB;-bpQ_cP$DpOds91dMZV`_H69a=)59dN3?S>oCN#21Q!x%ibi1q|LYEa62b}V9% z(~(Vwa$9&fl5R5`i?}$+sl!#mh|Ph;nA^=qd(}FDrX3SsWw>zLuHZUxV^frT>ugZf zJ4q@+n4!VYL0O7*wU|NDh7BTXR`Z%2xE;#Pz@VTYrghDYhcT2v%w>5l1B-!nY45aK z3|h@Sd!wQ>l(o1R6s~D$GdnCWXwl`C+L9`;fQx}4C6E`izobE-dy&%$h9*-+7e-b# z#^{S#ISdyi=2{s_fYx`c6G$m3ki`CT z-*QL6olObTzBF%Ht~=qq=)S~X92|c4`4fVq3^G;jupHpxd%=Frz{5;QpC?E8sI|}y z4rPJRtVFSsRq@ZS)|gh`Sf6ZeS)f~)o3!fuD_Nrh8$AL~3b^Pnp7@sR?BnS2>S`G8 zgh@9JyRa~<-Li?HjfsIF%ihV5Cz?Ima^txW55dDmIZX+(vYJ*ltrjzUvu3I$2bWS- zbWSesT898ugChkOq*fcSx){8bF>n!WP;~B**tYhTRnydoX42JXgI~8jTedoF`gKO% z#_4|7&Mes)dLgz+^=wtJYRQ{kw!UrU9X>jEn}W{G=HK*JOM# zV{qtUWQ^Fwz}?XB@H?}Tj0+P3gG)411EU<5f(U~EZ$e{kKttG;YYGjE9MpmtbVQ^> z880jhWi()zF2OdhomaW3?EVL#sy7b1_vENCWxQuzzwtQVuG`yf@7o6MjId)|U?vnI zEHJa^ZvF)}mXmdp4_x5RyT$zCAma=Vv*pi!`^;owVi&Ry71-TY;lLEzq|w%0#jJ6a z@ye3hDLP%eZEdW=0+X+-atdQ)Sh!``f`lj^fnWxQF3zyP%NOMs1$qJ^U;Ah`FgUa{ zi!uLRBvD(0phn2A2IWbXQo?rRzO;>X02l%ALz@QU2$_g8s@0Euyyh-?t7uh7%S1_m~VH7~a4>hLhI3QWk` zFQ%5DD^>h7Q9d*P~~)En{HNSai*mkzq|#a~CVaYBoW};EM`k3=G_+ z3`;Wv7#J8XCNb(T3C}ZRaN}pN`M|JfYuIu>odtm*8`m*0w4F8MO4!20z{U_4epZxa zkM*VO7aLgqK3etDqoJ~F%k>M%oWEo@EKZ+2oncwW3SJg=l{L2+x19XmEw&@WJEmcp z!>M`aZLU7^NKj_X3VfVgSrERM<$uD&n=v!RIGDOLCeAg95IN%aSSWc#z6;jsLN8J)3>} z+U`ndoApIVpOkasJ$9@rDCDZZ%T<1pLRRaxc62ZD(8=gJuy}V!>iignm2UR`Ig^bNd%iYxuwKeIq{VP;ZR$-vF-evqQAvue%@PVd zye(oAX03?WZonY0QINY~(b}UODNGACq;YhxF|cglN@`+aSR|ILpU|bi7Pk3}6Eo|X z5?ix~sEJ_?g*=B>bx!Qt#MaQ!u;g0Ji#5tzVjWB?RwnmGM0GKCg!a0w=Hg&zxVYn5 z7sG+m21mL$7?^HkD6=h+P}0y+kXr1qQlTM`wd9RS^_m<;h6_q=CZJI)zqt|&0)pDt zlo~j$T@hdvF)(Fd&}o?A!fMhMvE6}zAy6QM!GZros#!9_m98X#Mms(RfdJlXH)d#b z+)!De$*?Gkm4VUPvXH4RTvkKi%WcDV$)-82kI%18<8G=bugJYxpepz0zVcF^UmbUr z`**Z{pDFL4QW%?X$yHuvLP6ukzMxpKf~rZM?T(sqDqjc)H+I|1{BFuz%O@FDxyQF= zC8^ovc_^QpWw2O_q2ZXMZ}8Ek84DIAL@}^R8|rW|bTKTmnlWX8o8Tsm1znd}cs4Ew zGh|>84V>s9_jX;ssP7$v_B-2he_!18Y{n#mpqqM~9#@$rB%fZ;G^;Dfbqb@4;53#5 zuG@NUs|EM0Xiz=4NRUA{L-yE=2EJv9&n{)g39OFlWcX`!^i)FVOR2?SYdLPMNK{CO z>X%DyiZbP2WVP*LLrbV>NJ2<%wkvZ3;~G{G0S?9sFZ38(`d7~M4!YoCv}10^YK>(K zDVsLPb}$5VEn#42n7VOuBjd)b&An|=feaJwu=xldbaDth8lo%xh9#7hk>P+?(&>QR zbNLz8tU9JG$i&RBu1TYd!5~ZjmfOa8xkt~qiUcr-21GL~U?{rA-Vm8vpwQ01&;jZt zH)y>GaB*cgvWtt0W5p}4l;c)8&TINWXYFlZV_3l?5g6*=cs0X;#bG5w!vSGAlLJSj zuCcHl771C~V7e$&hoNh#DN_RX1MX(Ved@AnL|)~2To>5LtdaWOliiK0%6!RgFz>#m zm_*dC>USEx+#N0X0vQJ*KATKvVfuBunNwh{kO? z7nv1CFfa&AYMT+~!ph+Ac2a|;*v8|_?;Ytnx=M>JyJv;M3XO;(2D#dfAq-n*BuTX0 z;yPjFpPlpO?b@GnmMVU8Q(CsSKT=K7%3%%nsg5Q?-fMYgy&=3d#gDWY0v{Jji7u&I z)i70yVXH)BNmruNVFb0v>RVy-*x>iJ(ubtGeN|brUBGKmB1|_D3ridFRUI7;uy|@r*zKua)MbyTN z&n^lqU{bhtgMs0K;t>Xh2GeVXj0p^mYkUQ|4VMKeFfC9BQtj$3i)6JqHr>sUfk9_l zEterf!%RU35gkX@4I9#qy09`ZEM3&GB0+$cO@Lvp6-y3-g8|oWh6acG^6X5qJ(6tf z#`@ElSld=IaG0%N$}nw6V0;t8aBuqAe!f4J9>=dGvag&~sXsecswTcb*6K~eHQ_no zOq+9yzq>eYC{L)0;HZ|0$ehrb!T9#Ch9m>S2UUiKf=vmISq@i%ne-cas!j_rC21z_ zS7j6GU_5xS#7AT0djIrXc30)=BElEuN%%4DX7Mp~U}@J8W8|q8Y+`VWm0?=oXMD&^ z@!q9bTnr8!>$MkYa4|I8yb#48vtd;lhlZC6BSQcqgM!5M2yTW2VFr3h0g9Q9j0UcZ zK5u-gS+59~>OME>TX*hIw6C@F`Ss;G*1gk~o_#sP(Rf~}qNMJ*sQwdO?T^;DFDVHx zk`3(OV0hgdvgp!_xGxD4T8t8EeW&blP;u;%6}ZS5!NXV_%guOb5}RoBs#b<&p*h=_ z8X7NXF&ucbG0u_mgy*3kM#1c5(SZ(YnUh=_CvNQIQsT()5_QmYRA*WlrFn>f!9Re- z;mU@>Ev!x}XI$g8E@)_IJejdIQ*Mh40|SEr(;S}=&?15duNW8@CQCCgFl?Q5a>E4{ zMg}#3m8Pe4Ozw(^iUvBmvKr|6Xm1mE-PZQm>e@!N1_p)&3=J2#7#J9|lJn0pFw`W7 z8a6Pz2w`bRW9A5DVPM!1`h11xYAHw1Z4hES(+m@Q8FU1XNF}TYP03+Mdg7I>dO(w* zPW-Hk^bPSE$0K|@_llo&5&fR-c_-QDEZ@&s^)HUr8<%d}aF>I@rE^chw6_dNXJY1b zvmRHxD$OZyFO5sEQ76mzper|rMF*#ag;Hbewi#t@Yp-rB7qqwVGARnmPMb6L@ZXzn z9?Rb3H*jv@>J0;{#S7;Z#t4Bl$`Hiz-Dny~a$vE)p*HIW-PZ;uU0=My|4c=kks zD@#Gr&|0n-H{(tZPmH#*Y@4FUi+8*X@dgxe8 zg3Iy-QwFOoQK11m4ABo9R=BygH!L`9!obk5;Nse@tx;=TH)I962psKdUBRTF6k$BO z(L8ABCWfSBF^MqW*}mCkH{2Lm1eh5Z3K$q2LV3BfCt1$U*_5W(G>fZ)i%BY*#etzg zAWB3wgN4EIfLVuIJ72F>!fmz&1`E(WD>udsGF&6w@nmN> zAjQD=N}uJTMU^3=>Je3rMO*n8c)F%D?qiqDVfZsUBYn>bhO)cOd?74f{dOGg=1RP7 z{gSz9V`Y7Uf~$+Jj=7Kh3+75GkLr8uLLEx2R#&+!_)gvOXb5nyUwfb3T!2CQoy)-l z;TbD~EIYaxbrdgdQ>?q7X8Je8!@aERn~>D<{ymGOLs=MA*XB6#=;rlli{&>(`IKsD zEepQtra1fPxd8WoJ1Ux7cD>@A4jem=HX{dTBHiWT?G#cbGI8HNrv5jp(Nb82Hp`JcRL8)YQ z@=dX=g=_hk+16w@Y`kf;f=gk>jZ0FBY>Y=4gqV`7d3c!`dbk)EB;-m~F!&vH6BLbJ z(F)qO&6IWHlGvgqUooaE25HxJjjn`Ssi4~vl&m%~FeI#Hb2!SuaE)t?4jTi5gCg&1 z5m2RD!So|la>@ZwAwK6^t|O~5eHmF;t{q_5H~p*`#~k)^8v+DC_+TIn6X&lSgr!z2xJqpkWyM3hMVw9*03uCISk?{PtU#t2!j|85kKD7O#-fW@un)xMj-Fa8Rn5p}}?5 z)}&rmQGw9F!zO|ZhvOIngryk*q6HmXUC#C_K7L{Dy7Z@OT0-80rz}nAt!+(M#UV9E zY_>>2qu=7d3tCKKEGv3XOYNDa&?2_fPau>#p+O~j(&OTI9|oH>7Z+Y@SXAM=P^oKW zv*LjX2h(J8x!Rc8(s-(K4~RGzvn1Tg>0xwmI3~uR*0snmA#@K11A{~KLAE2ic-t5l zW*ua@(q+oZ;2>cg+``NtnHR@PK6bNu#&BVrVVdViqCha(BhRKtUaszT9-O$L7TOzx{+O4{{mb zG^;o8DQNNaU|xI1e7W$>jmmz7H#`n7TAMyv=41Fq_giyV`roLjbE59ASI)e@^mM@U zE#X^PMK*R^RZ3WK^_)obMpIV?k)yLrI668yxVjcJU0oEm(ekvmTlAdr)oI6OEZ;jN z?Z))?o8NXyE%oAd)lg}2cy&=j&!i*IAYrluQ?`ssZia)=ji-IDqynzUO*j+jYIEhd zLesk9fQ|*1lFY^Gv!~`TGd6M@VqCXIx{b3#_bktAa~B6eOcpiu`X!Ly4Y1c`TSggB=*Fj*SQ!aDD>o}3?Nx~XR3#_~XuC5ei zbl5O;Yqv5pgUf*hT{=b!i@6vaj)*1CcNGi}5WP{tkPsbuHY4;%*D^u$8wm^zjM0nQ5B?N7oxsJ=QOXc#vM7r&U}Ne{F$TNu zcP=o_sAqq;y_IX(zT)$}78*+q_bvOoFF^3h_X8a%pHKF(2z9hHJ@x9Cu-tJ?u6W#( zRMl1u?t(N`y$t;$CmUIR&NSG&_j9BEZmx#iY;o95Nj)ywO5WN}-rgD)cktIL%w!v3bo7jpu%8M><0CZ@BBUQk*g zv8^miFuHqITWD^M@9G&`T?|@foKt6HsdFspyxFE}bZOg(toc6`cN^W5TdG~QP1m^R z){Pmt?%Vb)jz<8w@JEjwcpLFT21N;%hG8l_eIjQAA*Z zgXr9CxwmgIiIzl|iZTeio~D{5%)sFAT$EElxnY*svdC4rf+B&gJX>2C8CEbfyvTLE zx>89=t%)h=M#f}OY1TO&6FC_g${IL9XP+3XU3pfFi=k^lQ-%p>8yi;#D`<^7!=j8e z3>-(6azA8GWZ~dl#K_2Sae|1x&yy>{4Eht;8ypusk909*5L?UGEjBlap@)s7H-dqI zVV}Be+=dNO?{55g9cz52tcHUn1-LYi(QX8-clbGvc@t+wcCi?XZb>Va=`( z@57mL#ic{{KO4gZH~4vA3e1D-+kY_RIG!Migh% zEj3(`_}(M?+|YS+ebDIDYIn3csR#?8eL`F3-t z=;00Q3=RRphdI76F=R0W#`d{wWnfs4w5lmFnTcUV78663sj0-XL*FXqomBC@oOCZ= z$NKy_1EI^?0@A*okoaM8hbq@92glGwP#$5n)qnyV@3`S8G$xXb&;XwvK_RA zKILAJNwXrTa!oQVp4rL7kg(8A?Q{?5?lproS{)J$7bHSM<~A?}ge;!c=F6baHH$%v zxg(4r6f}dli;J!CYD{Hg2BU!zTMyd@XNG@nvhM`8{BP4P*;ZCy-DhQ^bm70+TjP>z zWd*;}Tm`u2%xp=yuT}E<0I!hY!4sDib{=GyX0!99`h*7!hI<-B0;O9FFK;maab{I`b5OsFkWZJ!WhEf!3_pHDm!N}f~OBqyMRxC5)^gC!$7{Yi(D3YbSldD0> z&{)#hkvCd8{VYpp$kvF*O^d$XTg1S?@oif#F*QC~gIMS6%C3WMJrBVd}HhlZS!9VdG5$UT<$<5eJ?CV`Jw)R~G@$j5Vs(SeDfZu(g< zj!*k8zI&6p!iiA7ck0$tXT>?EZior&DCPkz4*A{M8u4VyiBiesECER`gn71Ul^bp z$T-1pan9C|BWZyl0kW%QE-*SUcdTNX(BZatqwb1ZiWgp8c`4AnpoxQ{!Ap%rONoKO zL6n`%)8*odhE<8Ta#*@p7#eh$yn~qq83Yb*IB6ir7$9P*qq`TrqCOA5v^KQQK;q7TnMP?JnVMV93%GNKR*D{q&W=HH4Qb!i0lkf%Ar>SVnH| zVAcSZP-TXOhnvLbnai$___hB+8uwI(AJ2S0i#q-0KP4KjHR;p7polloM#`2P9=BUt zycHtkI%M`NSRu`jm&BNB!BF*+aYLPQR78%AEaws>#?^{R(%z4Cg-<%ZFBM96_Q};c zuB7-%`ijPi?njSZ88%B;$Obq%zRk^Xbq!f^P|kX*m>|QRk9`^p42#O{nTeV*u&@do zzP91kZK-7|7#Os)BG!O*oOfk1Fx+ruV_>UZ(`U8)=w-h4O$kqAww);m2s4(>m^y3w z_ItaYXVj}HFMktjeBS+bw2@NaE9ufg7MJTPhbM(-osf`Li#)x7tD`G!trt&LaN{F| zW>to#XCLUTWPH7TA;XoUUi=L`P61BhtJf=s-Y}G4_)x{$eMRU>z-xA?giPV33~f`^ zn;i(VZWOzn%o8mXIDp028T7XQ&(m&Ff^1loX=C>ZClVFG3nwV z50*=3WVXaGY;bUO4b)Z^%etkIeUyW@fwh4taJC2|gTQ4r7V!oR2avuSU8|T46S`e_ zeT1dgFflM>h|GO)C4-^4$C`P;wv!o|nhYHpRf3ERjHP$p^PXH4%gDgeyh204VWpr% zf@=ap$%+PsY!-(L3QP)87haewSg@eW;Rb`2CTKWcoa52%z`l*kh4}XG%Ccj+kng^` z%}X_)KHO``-RCQ%Pl*Gp!&Sj}n?G}vgmX?EY? zi96a-SBNi(ypmzUVtAcbr;DK>D#-Cq`L~x%{2KqPCwcSrH9S2>USx0kx>jz=?UiZYe>j~rnYyslXVJt- zlN{X~qa0UwyfTksJKSZeptXdlH*!XbUARk-gSg0pn2HAVIEF~MjD-wIGq0BTs4^$E z>u&W}({Qrt+Pdputfr>f&)lb6VdD`|IGv&)oU>KjW9=>I7{oVFX$aX<0@@_q{vdIq z(4GGe{@?$9>;JX?kN>~?f9n6U|JzG5*%<;%I9Dk#HLaS!n!KKCg>1&wM+OU|Ih)st zO;hN~U=u!~#K4f^!;v+!mw`dx8e^~20R@H*28o$Imk-G}_=GSY-eAP$J^Sh`-8Cya zm{w$l=4{Zr2FlM23`b`z;$m3P;%6w)z_>mwqF32O8BG~aXlrtIbgpvV!T@STD>P*A z@Y{W7aByetVCa`%NJvp-3Ok|^#VE4Y?{x@+%MvbzrW-N`nC#NeigCQL)+q~N_}Rbt znM}j3@*Uf}SOx#x4^=v2RF=uAcxZ;My}*M54zmIb-W2aY$Y6Gs+oh^Wia|!8pm}40 z;QUSNUAVhra+Vcs5psL*BSrgtQbqdGOD}VCSDmZa)ZexEaJzObzvzr*Q3u}$bC@z5 zzoo&Evixbq;h27QgUMpvOC|H8Hgq&4F>r7=IIf9vVRhkZ>$>);%~va72@8XRp@Hj_ zgR??iMFbc;gR?heZ!qU!cV%SoO@G^bi-AEaiSU`WwJPHZ3xh*o!$r=9g-p}T7#dbw-8fTh zQAboRw}=QsgJZYPD{%&f16?cnE^U;q4Nx{Z6%y6hC7KlD%-rCb6_J(})z!43pqas; znMqQbq49#$C59u1{MBx#Ok-eZ5}oau+qq&E16M;=*V(Y6EUYXV0;_o$A}u@_lD0(6 z6=OVbXjc;xmj=%lCGG_;1g?UP9}idrnGnlgv1g_s%GNILrwR$*KFCn5=W|7E z;*;ko4>kzAVdB4_)^f{(X-7u(!v?dM1-i!dnasO)nE6fhN?_#lNivmPldTf5Z0hG( znL&APHl-fbY4A{8-E6jKlJJ>jRtGcHJET_LOxViNa3hLg!laNuS3%~$tqCilM7Ell zM@I;-UNO*JdGy$|5CZ`Qk&T_(1240LI$UizcYAr(jjKnFi7+y-oW3pjen$V)(yK36 z*`x1%P7?FezcDjSEHC}>wyDhSx8KX&3=HiJyBHqS_431nC(LfE`czb3n{Q1OtFUZ1 zIC0Hy=AMnt35>6-Gz6v^N9+j;yI^!f@O>yXEhvFMBGT=T9K5TrK-Wez_>lH@nKOI69dPw zUEZ!nHyN84R;{?^F=JZtW(M~qtPBFuIf>pI^E4aySQr}qlmuR7Xpo+4$i%>KA<=P* zS+e3a)(}RKfTJfai6wV3DKHqZ1&cZ;9&{ID*?92KrKoM3ix`>~YGrM1XjpJjGwC2h z*kT@`MWLV-*yU}S3>O(1BGei78+a{Y5Y)9|Y2fluV+eId5m+r zY?Ab;XQ78DHdW*;DSoq|dF#SAQU}) z)xJFtb0E5Fhu8!MvFzNULzCXzasO`7efCIneC{#b&g_#<5;mEc-aD*jcj$@>>wK9F zt0Gt#wn}a~$iNc7`t@Fd>s#K%a^7am3=;$mc?@;#Wo=yC(J8S=pG%LBz7yeqxzdiJqy3Sl%@ zI5lTo!;KATtVedT9cq|rbfD;k!PaeSm~zgEFzRl%sW{NUG=qWBjZrZrB|vhLD@P9V z+?}D#4T+ig*=h&2<#}him~6hBxJL4TLE4!cl8Z$GxC|H$MKNE}II(YwfD(JQq)wyb zhLdj_%p6)leb>T;;TyWLB*m^>nKesoLD**Az}buq$KD#47$276i+1YEy#%LU_FSOvrEt*Xu}Y-nZ?DHG zNd+cz&Se{ip8K{l*SE$ha791!)?+byBqlCcu<^>WBEhp_OpXW7t!7%{$!f@38eqse zK}KWQTrP$gK|Kli$t$=R5_r`bB))ctIlet2$C_aE!hNyf+A~!RD)BnGJvRHU%nI1J zcvAOCU&G0hVi>RStl0iqeMi*fV?rBNn6OWXNZ?&D$MRU5V#}+A84Qv04~kTkGHkmk zd6;3+kyk=49&c0yrd{PYq@~5OSz^|5{^Fc#%I!5rZsa%a5S@KDSA)@e%>?Eop+#Y9 zZuPV>Yc(8bGZ1TVYmF3OFyZE7FbvwvE4G96)OnHB3?^y^cKK>YNZ$6?#@ejNuqy1W z@CJjcvp6jn7UkYPlXY0*@T!#(2bflgzMksWS)zx;>DKqHgxai5) zp140@lNm!#+=k`64m#^Z8XXzFq!`@xIX;QGY;t(#>@Pp-jIYg}d(HW|@!g#Hsd`$~ z?Sa+@uCKo_HAkMo*;jgvWJAQp86qYxP7&)DXBEg#j^}TXSl#!LlYt>1 zy3|*cmEp*}MIW{D*bYb~8%8iNC>*@TX1JD#L5r!0X~Vl2HHtU4e?4V$?Axqb!4wmt zHQ%8-O#?8RV>$R@+RF%r#(7M%qB^UmTOaHmg*<0nAy*C#BE~;b5yRK$}}#ffVB*t zOc+B&6SH&^RCKQS3LG%%z6rYX{zZhZ<}4NlhOIh2uYY=M^PM&;w}YucD)Po-2{SH+ zgyz3tf!^6n3=9o>d&7JW2{16M$p{TCWN&D?lXm!!5W|L&F0o$Fx;v2^xzxoB3=9)O z*J`aWWo8I4H85giXy{n6C~zZ}-%`)>41MMd4ANHwSPU2)HZnSJKk>F{Wj+vQlEj$f zxR`Z=U@uof1aAW)FN2)=Su>71=5yXIQaX@3*Ca<^N4~{vSJ#IB)?eF?q_Jynv*hP7 zSlB6(7jfh0Ej|T{2F};4x0Wb=;ALp=h!GHon_w@%FeOV_c+NcQC0`gLw^gB_%+Bp40OXq~gnW?I$ep*k~S&I;WH_YSt( zu@tn;x^kRn!L_gK)t(!^GDu8a%khAb;c|fK(bcoK7A$I;+mMuRelE^uHABM!4hDv- z%LysWtPBnuWh!iExLg9as)1%WyF{}Ymc#`g*dh@UcHnJlQqM-?h^VwDV#ZHqEm^dy zEnrGiBxBo>CBc=qo*sMHb*GcdWTLBQok@T$ldP>qe=LKj!kagaM`i^+nySYe(Gt5y zOTzrnK~Gxr z00RTVk)*{ZPc$Z2q_8w64B1U!0O3&N!S)Nn#CYslzz3V^%Mic6&_RFoK5Q( z7#b3fJ~MD}VPIY>I#+^$f%S;d?X=Yl3=9pW43`-mc2(Q?t>w$l*X&~m2rs(G zygidWAwhi&>+jaan3ywtGE0>hb*@D%o_lxKLyLF+OzqCK&Dwd%VA{T^Ur!Y75Oa7W zzLKkBszsm=i-W2s%Y=|Qron3#F)ZMn79nt%i-EzzM?jQ8AvBAPiGe*QPulLpQLm&U zGq2@++mlm&`^vkr&+8_(Kg+t;8k{4wEM$w|-StlU^AsnN3z0iDulaixEm3jJA-#xR?4kgje9+sn2zNwGiheJ z5q`0$C+*nTMb-|O&d6U#V$DBlH1!9+MLp<(ZwX{9m^r+ut7tLk%1w=cyVGs z2Lnsw3q4iP$vZFfcyy}2_=RN~u`wJtm$i6OD=P!Tg-Mmpu>y695CbWVfK8q!&8^DEoyN`gQ!9yn}Fcjt}vbjj@NE5G?_AN zsW#YD!t_tEXg3LmCCXtabmZnt+s_jzN6%9`X<<-9`9O7BezsM;t3sqdk za%I-UBM%Ns2}~()=8KyMT2d)$*<$#Xd6Tce#WRsoX01-l3Q-Bym>L)xCLG+wXu!ZA zIn{xOfu&)YQkc%>=gm9b-FV0#(D`K1wKt%#NLJpBjGb15JMp9h%m?^a*HjxlG9F%rmi*%GQ0J>>2$!?vUC_|9K%d=lreQ_3M_7@yP|M z`y&tL-9Ozh;oS-?iE9j3q6Hk*s!1{k+@7^kE9eBn#2G7l6%?f8A1yx7!oa}ewyI3M zb|PDY!0wluAN~rD-J`CNlJBz2d6^PNgTk`dSs@G$r)?`U*1Eh#t@MD`ti)Bp-w$7^ zTw}d^TB^w9Ln@aAUmcL}t&>>88_=|8?F^lUP)p%!2P{6^v0Pitx`2oE=4LVIPzNYO zGC+npKSz;J`-(KFfc4n{#1B1-@Ew|2j zDKj)Ap1$H_&C;-QtCXw+1A`7v^3G6ZMiJJK#4Vz$XDwx7n6Q*<2@^wu#Kk2H3=)9} zyle+nnL4wuu(0qf_`#WRWE%s+2R6~Q8yTV)l^GINnL30#Jjie)Tco;|QKWg1r~``& zJA>PDt_Frf`V0*Bp2_s^yo#Q2{6^rxmglC=15yJ1JMGGr6?LqPz|TxDf&@V=$qaC(a*k9T_S<`ta_)+Mf-ZTvDSfW=kt@P;VY)m|)X zZoQhi|JO0L>>B;Y^7eUUV(w3V_}TsH)G_!jccpQ+^8L*fSwcUXpC?_-@4Q<)@AnJ8 ziw--3BBy*1a(ifPa@gWP@$87ki;Cac#JO}PG>CNNvK*?*t&$H|bn`;h^E@W0o17P} zRt6tA$m6W?sGDiaAk%5*tU z%0pa&q5a)4)dj2`F1`yEblkdmsVi%x;^CdgZ%p{Hz)Q0!Vq@-Uo+OEe1yf1_W*aIf ztWd~G3Rc@VD=m2f1H*)c(_F3ErYNwACA2Vdh%Hc6&<*8eXi8kaGIRARE)6E8TMPmW zj)n#~E<6kjSre!3a%12Lv~KhlV-`s+VMtiKkc)xA!rxEVhJ%&iHJbvH38@5XIGBP}T%e>F+Y&qK={g~TbvWxCYmd+4&Vv_H9y&;J6%H8a)gze5H zhi`rQ^Vuo*WI2>vtG1($Dem03htf@tK@$FePn(4 z%Y)S?_*mDl#8?|UTuQPx4mq$mN%Y0fYEf57RzqRdBZco2nM0iwgG3!(i)@l^x4Pw5 zEx-^OoIR2G+9Ju+xkj67(z=fyTb2J^_IsVHnEmrfYP(NwD_w7S=T6$Izdz6C841c9db5o z*mdlinKLtkf=csJ-fKe4lNlHUHm+FZc93C%Qdq8uyUyBGtC$#?<|cNSN^cScohKZ5 zyG2-}`ZY%b(}D)k*>6}F7y^z&v5GQma0>w4$+bXiF{8qf{k#fH3}PSs%GtvrN}m&S4JQ_rimG53{V^&ugiFa%01C-3{+W_a)wb z;do0==Mz)2@q)SUtNotL`Ms^v(n9Ieyd!E=2MiBv;I?|Gwz^Xz=5NiKJ?l-c_{}fB zX7@ztxO{O|%o^9aiAPkG&MG(_iEdCTzIk;f4gq64Lb}R zv^JdOic(}?SfROSnXAtct!0U~7Bt*i(aX@Ku*vE&_w3t2zg6PD)?`}#J5-i>{&Pv; zI&EeBYX(O7wHj~V2+J-wQQCN-hVR(H3k>_XzVmGFJgj1o)ii1E9^nRlHj{`InW9NY zcFo()yrLm;#==MkwydLNGY*JooZIG`>>Yf&i5!EnrCOT^3% z9Lfva?rN@P*1E^LNajm$y6dR~#*PCLIc%4!SThYmjiM#1xj99v14Zw=YK(lN(#fQ8 zB`d;E!f5$428E8^Wm_i(YA`Seg{_Hj_hrvvblfA9?7D!FA=Gef-&s!1Gdi+YRxvO* zbf>M|v}qZr_SkVP@okhKGXtA;l7KE7H=C);5t-_2Ee3`JiN!rS$5${hBrO(ISS`vR zkbFc+mMtJqU~5|<6T^xGh67esEF7DcXfQN*w+L8Ru{AQftY(s!_kNMXu@$CUmoc>I z9!!+sVCZ3}`*ylo?n~*E?AN^EN^e81Nq5r|a&db;cL2=UbB>pjeX>vcTt>hs$iH zC$rR6HF)`TJd&ickgcbxlPx&vXt+s#^hJO9fKwt&1~KKOl`u~ zuR7<`7-wv%VqcKnsM4OYa7&NiRX&y_2RV)jEj5upxw^nKaDhaTS5f#BCq*X?w*1AG zWnx@y3$M*jTHwsa&GFVJ?9`bs0fu7?t9d6hMQwHLX>d@{bkH(-o}<`DY;x$f(#4}C3=rsMGY7j7<8oOT5V~SU=RqrIIY`* zmElN(X$RN%4n4EuXF1WEad1=rOm*>yb1D`K_{}414J-=vxsSbkBs4u@Rmh`T zbGeq31@+E(-!IJkaQVCIzU*PEKD=C1pRo3P<{#@178{$h%#C{|d~q=J+3crzW0G97 zNU*PCV7FKLt!R;u$5J}ebQl^kS~6bE2q~PkXaUo!BNtZ`A1Ha;w2(pJ$ZiqtF!L;5 zR)z!D4(-yZvwGgWSgdmWDSfeJZznRl8+oj{y6@!NqP0F$FC6 zqb#e`p%o1utK~CYQdlPZHD+3odE$fA^>+bnSIqrm1SDftaql| zTgx!p*iGUhM@PpZ<0%Xb3eFCx4o5C^oMZD4bUiMWgRxRaif5!auMFQ6{)oW{3uS^KlJu*w9>+Husn-o|dSm!qff1JTES+^QoRB z6Cok|HhI}WC6Noa@|kYf-Pm(r#!tyFGc}X=`pSd~4qSVXm-`{A^g?|7qaB40u5`C; zx*#|^{NBTfe^nHI-!J95qH0viz|audv(eRCjDex)NM!60gT+Ux7Ovr2Od+w%WgTYXTIv?#2-7ptzybvKZ$MHmrr#)eO|q;?AfUbFRN2^pEw=3n@?2P z2TeY8Ey6m1?SaC=8b@KL+pH?=Gfa|2E?g5ib*o~FQ{*?#jR89^sG2)C2%j`$ZE#!v z%BW{wnN-Q_iaf1HslwL+dA( z7_Y5(VagWBb0e%IjGd>1Negs~kU4AUVLkELIU=rw46auXsm*qBWMo+L0 zm1%X{JS+(bt}4??VmvP_-m~Mz966)cf3Al9s=hz{{Q4(5cS*b2Eb}%JUX!)OZLTBh zqb;UKdAx#^X0tFcsch*<*ZVyk?M3_PGb>b zWQf=eN&)L{f(|Xd*d6te@xr&ZR@H0HE}jO0fufGZ7X`K3e8paz`=J*Z1sVyM!_Kf_ z4J*TfO-(1HxFr}bya;e)VQ^rMHHb0<-2}|fRkBFb@hFo*QbQ1Xf*^C0KtPXUyHdx} zrIt4u6rPxEsuNhwFt6;4n9!e@1xGztCx1KE*DU9_TYZknT-CO!e*jneo6WDa*f8bCOV6oSmr9A-{9Glj z?Iq(>)D+^F`rpY+?J(QfO_bM;qi1h!JDk#5uud(@&Xn8XqKni) z$<)M4Jc|#%`n6V9t&N>mE9l^@(@pFw4V;WRT`U`f(s~U;jq=SMI3-h^(^!&>yP}>n zh!!95^S>q-AUux>Y=#go0QY7?!Fr>booyp9Q+aSBxQxfnjIZf zJD#LBJ9V8DH~CF_V6oyPivU+n^?h-HR@pfx1q!s-m!EI0lh#o%Y*@cL@$k*vY5TRG z{r#!8ChqiG-e)WC9zXr*!=m#?Oa*1nmD)atV40Bef<0vJKJ&Mm6SX*a_ji8v40s#R zpEh&LE!QrI%%rs&C`^X7hAR-OK@Gw z6!m|;*Rrq%7J&my(4i4KP&R`Mjc_wCFkH+sI4=0`|J(mR{y+Zz;{S{Pr~beB|K5*> zgF#7WosT{Cd0GPRL=eu!J^qxPG9{QImW646H9?+hZSzo zGcRt4@M~jR6iWEIK}~m#yrOP*UhpdUoSx!rd)Q91INX z1_}xZB~bzm)e|2qJj}o#5!xv47`I4(fq_?Q&BUk%rUeN*jF}zV1&=hmIFjUgwZm_T zNtAY$1k(zyRg$a>(T=PR0c-_~c4jhbI4acVK5~>DDAz#DxQ^ew3Qu=>s(}5wH7q-!TyCubpae zJ=*87v{??X{l8UbqIra;PV99sb8q8(!8;EK`gx_hdZ?HFAaw>T?zyRJTA*sa-c zW_HxgTg(g!T5XL|%bH6+el-j<)YVvZPc*w}^&$o{?~FK5%pPc36}UCX?J5HkgG12b zMUn!bQ+T#8G;}n7V`5TRrYbJFX)S|<)+ZA+p;t#Ig)o{jJD>4fb=bOTlTp%%Bdew6 z>z`S{l_D~GZ+n4yvE_wh6Bek3-cS%t_%g%KRm~*A!$60vv1GDhu$zOZ#Hz@7uZ03a z8Gft2NLV~kyOC*f@45!9yH{H{e;>PLy-iX2iaDcB&^-nQh5*fb(M4x(tY%_Jnq`t9 z#c+btfh8+fSITvJ1RKK&Yeoi!1IJ&gb%9R&O5k0gpfycwS+54ej;=!91cn5EW(I}@ zOdSkt4W=^~)*ki>G++>T%^=`#L5pJ~m#wSqxmRTJl` zFcyY@ga<1gGQ_E!5o3Ck>0y6pRRODTdGdjSOf4*CEz>tdg@1VX&9C#!)8>iQ`($4< zy1Y=herG{@!!e&`mHVIB|1vDv<}}Tf)6b{LIAZd)hRfn|42u*B6%xjm-YX_0`7;`h zJWY^dnqs&89=FF0^MlMY-mi|h$Yb{@>bL)`8`%uLYISzH_jEJ36rM`GxSPwhpySPA zHHL;&N=h@99ld6^Txn5RsY(Y^!>t=jR&gmcFfpXPa^PiQ=rPF*4Gd-7pyKOb7|5;A zcGc`QXM^k2IHP$%JD(nBm)SSlUUg>Jnus~2)Aw#Pp4VQu*iSC1bEW{xwPQU|DJg3$6w8F zNiWvqr zY?HBk>Xl0gA@9y>xOS!O5xsJuses``f`7=ZSD^}fOdPgoOJsR)gdJmPn3Bq<@PfsN z&5(DZWvJ&-LmdaUVC{t1Ycd7f6d%S!9oy$pCVJ$!{KA7=T(WvwB_bGQsvDR?STcm; zE;B4{3A0`>YfWgvky(sRjHzc`+ibd*F)%1ttzh`NeMMW}CYt~qA4e8f->YAvdDt2_ z*jjitgl%1`x2Wr^8GoDUY@VpeObrYY46favJ&g-`LVH2OB?}_1uXI*sW5`h!3k!H{ zHfsfkhAxMw!_}ZQj0_59QN|+LJI_wzVq#b%D9Y^cR+5>+WcsQ5#$0S)IJ%E1NHA1r zZ(Bug-R0)g=d~tQP8-d)nMwY!x$pUXTY$J_09#w5Bn26 z_LtsR_-}okba8;k;zI#-?>BzmuPsT6Q{lzq zB%=>3C%kgkPUx6DtH&#l=?4D>kHRUB6gCLEFb}mdY-4+&Y6v@&7v| zR?SQfhK3n>O_>sXhKvpuV~p1nRyZ&+NY`>$rZsnj3LlYR03C%kYa7Fj*tm^JenS2o z?p6}gZJ|?)@BXZf)Y3D3Gxeb9CW(v~Cfl~ly>~sN942w6w4^c3vglgy(Pf23Z`RsF zM(hULE??x$o4N7YZ%xhE{;ZpfM-uKHD|I??NcBYD@eSoF*^OKWR5`RaWQdeh?`Epd z3=Cno`TU-I7%QL6f`+^r=AMaf1YKQETHP?ZoG{5%l)>TXHr7@@1_lOh4u)l485X7L zJD8oCtWI@*y;jD@AHJ{GO+#fvvi!#I z9ZXZ&54Xv>&z>LMc_)3IRKpt0jjH(;TPHE_6c{r_9Of3tS~Nv)(adek-d4n6Qv zvqVd%qwVJ&srf4VcEs#Xi?=>-;T6M#>>P!J-!)mbQVs_;SS2*x;&EiqIMBHAuo6Q< z(?fpUzDEtZ3=Okd7R<9Pj~wZ^c>gAG^9J_;;g*e`}6YM;=A~U6Dky_P; zosPWKCaeO*YYMX$q*2-Gq{d2FeI?9iJp9<3v>wPt%MuVr+FC}7`atVjc0-C z_pqzG7BFxeU~qU7VAQloSC^@Q_24R90R{#(&Ii288H@}Jf4SdJWJ+og5ICX1mC&<> z@wPeJhm(wTtamOXU$}30K5^?hg-2NtVg);nA6UL)ed5w4j?l+?O3$=z3C-{Buu+J7 zUFQ9Tv3s$J=5+H-eiH>5m}6LO7%BeQrk}uGR>H~DGLhliP2cu?>;F!DDXM2S`}K;= zdN(9O8;|u~)ydctAYdZf*`&q9@X|rHW72|~*B|BjWbeuBVmgdTt7{Ktp3_ zx6XzQi@2B=99BiFs$ynfV>w}9=CWY-t8ER9JB;0!7!vxlhU~bUu zV!R-6#2}Z2Au#m9FvFb%YXmwHajwjE72|eyzh$RW`PbLqBg8jSk}8%MI!X zY<6HsoUugUwz|xPH!==!h38zB>^j25&e*f^WfrsK!^OEX<&*?Z3rEi6b(nW*v-g7Y zTMlWh-X?9jcK>{-tkxynOG^zI7$W!=Y;@4(OI~ZlkTj*_poVmVS%-kHAj1`t9I4q( z91IPMt{N~D9W`qy6?5FYF5HBRo#84|OLTi)V5vrzMnjj=tX8vCD;OD^7UYBqGBAY9 z?b;Z@z!2bI$RmA(iGx8*OX)`B_C-n#O-)@%`FCHKd~Rb>C^BUT)X~j362y4m2m=Gd ziPZWD0$V^^-j3{I;!1K=bbHYkz_a1S1qP)9@zWg~99D1CjaV#v`H&b#SEA@@C5MGk zM;IFTZeDL_<7W6Ldd8gLk8tur^O%$E+hPwkvK-joStM?y#kghfB>}G8=ZlNq@gI|$ zp^%gQJR(W_-dQo5?kgmFFf`5 zq4B=?$2u8bnzA_dO?y70iTzbkpo6OjBf~01Y0g=modLqP=k%{VmMRwd9P6w9oe%1(QR4 zK|Wr(9SjVQO>EvU7VW;hJ&}E;xyJNO+pN|28yFne7icjt{7qRabRo)X#hKNz8ngOM zZ#S=EU|0~zsO%lcz%a3A!K#_&n=eGQZE|Kv@R2LiV`LDpDset0#K5pXa(Y{>+ick@ zCL#tK6mv~`)?_7eNGYre^Ocsp3);5v#o*e)!wC!w)zPX_phG zju2lR#<0q2&0&V7NX>;uSs3<-%6#B>HNSvws+Yx<+g#7M7;A*zB`p=wd;4z6wYka? z|EE2#ZvFoDSd&8mgEULth32{g!YRBn4={3?zwk8hasMsJ{ODArm2LSirUO$JeKqS{ z{nqDCz}LvV594MROkaO({jsfSB_?%0*LAVq-NlgNBRG}mp4q~Ak3eT~Hu43sF41T^ zI*WC^THm!_LFsC|q71G*x6*<)a5Qiw@O5Oeg*q_w2j1~?H~u8X%FvZj>oAw2DbXTB ziDA#=$i2Vs%I3u`OW*tJ?wZfu<~yyjxvqF$>I_oaz||!qbEW&{m0ayLdnPwHaCQIV zl~b)~x-xA_?YvCx7Iv5Ioga=kvEJBh&Ai5RT4+Y!y?Oi$PKHhao;x_$nX|(eZg<$f zwbm`kAURg{Ck1!EV<7!Sc@FER~Qyum^P8Yjv<3>N+iP@ zcS+ucvu&aWB-B+I7#j2@hDGpSVP@ofVl^exnUBL`0jRa~z$}ADjNt+cLxW=ov(&+9 zVLA*9F1Zdzr*SDUaIkG~GgM_z_`u=7a=Az+yRD0XL9DblV=Kpkwo+FY2L{vX>0F%I z25g}184Lo33|XuUA!`^Hn4ENAHDF3$aL$Ro)v+=`imlC;E2~*`kyw|E?t`cW5!XXl z1z1=Z?unl1m-r!lr?pG=(AS>VTxnJe@7TVFtz6LjTC#L`-28P0%U455u*V6Pj&ZnPk!hg=C{b6QZ{ev!;UQ3$!{1M85?AoK+{&5 z+D)xZ4ByOVEaY;EJZ+|%!^Gq;edX$zGfRaTnnQg>Ss8g&G>J;PuWS|7X5(sF6`*{r z*m!Fi=$b;_u2~Kz7#I#5(q>@bwa{p|6?Su$DR&@)!v;@X!?no{Tq{;39zC=zGyk+s zt^w$p%Qc0p2N|xdy?lTvfuSVyLIWd%OW>NBD;z$pDQBv870EVaU{HR{7{K5lqATI& z?(lHMnFUH_5gU^-8K#L%2o*TOrrpsxi$N@eA^Jjx3qQ*~Rhbn6k8(E@NIre?O#5Mj z`-OLG&v#6^JZt@tsM|Slhfam3H$GutxyT!}A;DfDQG997UH>u|r#OuSv{s{q5tWeb|VGqP;72vZAMVB~Nj>)KK`UzeQRNh`O{+Q!wOk+EoPZ?8(k zTc3pI|3rUZzxQzdjPmL?*O!&~SN@+qZ=K$}o3UpnO}!nrB{$rA&$0hc7cD>Icd|=A z?vWGUAuCh8+*t7?F&@r7n@sL9uUW^pa;NrsIRg_prdO9cw*2bgR@f8O#PxLhp46Zw z6O$PiwjB-G$*Qy^Yx}N)?FSR41aDh5^%BRT*H5^6pDYeOyGy2V+xC5GcP=rcT&WZ0 zao|o6+)$ONa9~59P{9PhXHG1QKG~*Hj2pC67#I>RGPkAJ9Y|xy+_IKU$;!<&BqU&? zm08Zri+nx~A_)dMDMxnQGF!Wfp^0f`5o3T9Tc1F$UaW3{g5ZH$U9TJsR1B&ZcpBOa zIGB!$F*HP+)yi5KnV`wVz?3#iP@9S2fk&4k6N5vtV=@E75`o0tE{P-8Rxu^8@VGL? zd}9z`%3ug&U|7r4YucF1xQS6E!1ah);DIekNw-osW?c-LxY6ZmLn$+d*y=(hhJC7M z%-L*Y`^pkogU+57dd9^%kMH}(LwrG|@BJ8GXqqR@FE)SJ+_K@RImdwq`WMpozf?^) zC~S6XL&28BeG@0HVwl1E>Ey~~JI*l)G4mbK-t4^W=(=^&+8Q6^+>MAm^!IMX^&fU; zb{pob+Vy$WHoYIWUai&mD=fHT$1Tgp3^oiamfrI3X-t^G(AB5g)gW;6%^Mxi>Q-R` zT{VW3t{XQZLKztXw%&+PWnhrVKC%cjpS|X0mNpZER)V3RwROneoLOe1 zGWYA#vx@dtif>Ikb+jaYmn)BBLB)rJE^UpzW(TfETs3MZJ~O2oKffU9aP7gR&urnp zkFDH#)#-?3zG?6Qci#7+4wF_&sAqOOio7uEfJ;Y#*vznAjV;UWIJvq7-cSG#lD!EXwn)gf$J$_xw!8~5b|$eLQM zcD<*?u)u2D8O|g|hD(dr>bh=R1=^UsBEf-?fk7j5V(0{ky9!(k3>sWvsY{s{7#2+A z>d=y6U~m?Q7G+@QxgxcJX~9N6hK-DimoNpab!1>@*vGBUpq(V(z|6sr!Fb@!Nu!RY zrBR{MYc(2JSDcXIZ7_`peUQYk&-9EKSB>yfDe!;1xbV;L62B%feoU^p>t3HTI@3if0MH3g<= z6^slFYy5qCSsjjqFtV_SY&2xt=zNAn;q1E1`|G0o(r0|z#<$y={r&mN&60ta#e4O2 z7vJML!B_pDwrc((r=8A66`XaBH+Mfsy}qH0yWP0Txl>4Vv3}FVQz{};c$Z{4uU25I zl-=cVGsvU-T7uMW(Z!kGuZ=dvI~XlcarkwrXY*c%JSIb#DXHhQSXdH#nHISV1xioQ zVh}p^j)%3-`{bUrtUL@1FS45J7#MiA-4n^aA-Ab-awrqSt?ZE4+`CK+Q#F^g>O2Bn zMw%76ENOv=s<`$vvsFwC3ePfT>&S>U9PwXin$5^?K%(pFM&siepoaEBrWYX$8(y#l zbbc}T@SE|1MiK)9Lu98bgGj>*&MGzwJ%NJ_Yz__wwrt5uyc;B-vnD|_a-n ztZD3K6_@Vp^(gc=esGMTO83mkB)&(tJQR*N-wk?{l2Eksj-}rg$B;h}+GiiEQCVz} zA;%Q?URR2dLF3Yb8LJW)Hf5N!F?2|Z3NtG(-?$O|c5g2uL(`09E14J=G;XX`1nn)^ z8o2r@SHjb(EvvToZku)V;osvoitfIizJ2|gz4x!4cy%+TGX6Guys?FT=UkbbC$qlg zq{;G_gtQ3s&bggE@A=n971<`H4_j^@{@k#debFU>eQNDyjfYgZ%+IxI7DOb9RLwf< z*YsE7_Ns)Lp_{^e0;;bFU6Aed17MHJZFtEB79AI9sh(lwAB2)kS)W6>ECS6r>550N( z{_KFnLzCWn%U|>kR=L%BG9i-1g1ySa{? zk@h2@#3=FK&YbCZ#VN3{_xRopFXoQZKww34>uDk}56gy=#28IPq8dk5h7!(*5 z9A-#jDB6d2_paBzx`+A0QyJFiw`=xB+pUBtLJfh*x^8n=VbgN@7rg4tTv zHZlmTZV1gWVGKFI;=<0szy^wT6RutUQyyOkSZLGPsV7f=aMgAWOrvoR8GE6Y#ywU2q zsSkM%(is^%nXbsGkqO+B20Vi_7vT#+V-bJb=1?Ri(Fz8En5^n8=qBld%uwXoTRRTft6IBw2x~>82g=@vSkZzu(E7U zO!>1w=73$mt>fDy1*ME9zg@nD!LP+@nG9pbCdD)FS|>g#JkZd}aL_XB<(_>kybc?f z4z`HQh)s_4n5Y)9-F%8_nlLbg=zvD4<0fZJ$~-`%y6KQLFbBu!|H~B!%ECX3>sO^ zd5xi>4!W+q*=h@vI!qk{M5SFA4FgRta4~=fNLU++K~o}-0TR%u7Y}X*w(&CjfBygR z|F3@Dp8gRD_e{@(xPAVK*uS&S10C)94LRVFI4N%qO3Q5o_8G;cUYC3&-!d^ z{;-^3k%gbZfwDwJ-f3|Q&Yop@)151vTKTTT{fOUvR=zKdJD86jnSCtx3h$I}zIAE; z!{^;OIJNlD#plO!+dX&j%|4kfsPFdMP~*|nya-M<#!KHdJvTD!GdB}C5cYwA;pMDe zMM)!trbKfiS4Pvv>$+FY(omS>C*qjC==v7FtqrRLZ!#z(6g<0m$yY01c-qM?2R|_+ zD^Ab;Vtn;Lf3|^O$t6}}kSd{wwTbz3-B!-|Ga^Ug7( zNU+|m3~fB7bGD%7RY-}CB&Xn%3A?8A&SgmWaf+vdmHmdzq8X9w4!Ys1E5w*Z8sZpA z8XUQ`!?-hdpK1~euGZypcwErHa3IWu^8f>fV|%ng>HTL4%*`5HPTSJ{v)$b9?;0qQ zal}8XN}-qdC_b|QVcV;ExH!<@CKV)LWD__V}=xi>-HJb5(q`Rg?r2DT_IAw*tyK(8E7%TvT+JB8%O=Q}!2j^0q`*c; zQC0>9mVks<1_5CPM@F8ld} zIB@3eycvxOyH=VtclIuEO7t{7D%4;Xz?jp2!&Rn*EwOS-h>3@8L67Cx2^Tv1 zi|8LlhKSV}7c`h&h#c9neM_W>1Ea&m6;~LV7`M5e(FyrsVKd`<;n8zX?RIzEoXT0> z$o}|7ShJVKo#)m;-&Q`_vON6Tk-y#7>qAexPqV(a`+42!54^XXxG(LBPZ03qGpM-W z&k(|}E#*h8w_ve~!xPmF7NQG&ZN2m0HrMPeXD=swI$k@s?%DINKR;f%^)lCS%alb| zOUo~>6u+=AYRWRT7a8l^v}`5{F?2RD%(!L|yr%DphC)ZwtGiV~yezB@o3cbU2?iMY zG9K=d;F@#x)WSsnV{3PQPWpFk`PIuwlJoD!pNpHHlu}+QhHBg^0a=Q&-E z66lzq%<8@F%1(yPCwKO~yvmx;z_jRY%>3R4gF*3)6)}#c)>6-JTN@a-92OqqXlRu;k#eyME3sOx7ibW+dhbQ0 zCI`>AGqTo_ z;@0gYc#vVjl2u!+f)pBD8Uok!hi%-vij9MTEp%m;<7#fuO-qr?p4Zs;^(fFftt6#g(MOB*DP4HjIIVIW#&)`r7F&S9lye1XS6WL4$2R%a%(B zl&oND;0sz65xypZ^}s5QF5RQEIutZGR!BKA2r#^Pa*ste*nUg#W{#JB@8%XMzv3?Q zOPjK@rlBB#hh3agZb9{xbM2FqRQ2+xUM1eWH-CewwT`C?|p4%Sr{3`B?Yb4F^!PeD!^!QSZ9^|lv_dvul>w3%4+o%P#$ z{q$~=sbP!1G6~#Yc*v7gNviai$C3?75BsjJ%eDEa8(w;KH3P$wC+n`S4!gp;%-W&w z_T=5iyp`5GH!5MexHn!l?ws)roeZN3{d+%WDTd8DZvDMICk%!$hQ{hDdlGjohWY%QlFaQ9pNIF;m literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/wind.ogg b/src/main/resources/assets/wizardry/sounds/wind.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1b824691142b53371efe98cf110aa3fdd4d85369 GIT binary patch literal 107150 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 $kZ!Qg05RN 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%0A8UE~i znXEGXn#J!&3_TY;^Fz1xd{{Nbq-Q1*gTwEhwj&SKijwzhR&G;ytF~r!@2m2K4y%kSTZqU|rmJ=wLdI7cpZe@OIB`LB~+oZe#`+@#|r7&gUAvm;AVq*F$4wW0D; zO9MS?M!gL$9F&YUHZOY0^2pCTqU_ruKIKUVd#+ttcH@@rqQxa^XOwX;Ff=pzJ~*b( zwIJ+PTMg>r4H{4qr$ zh)u1BbzQsSg&VqThwT^`0t^<(T;LHss<68uipAqD4@1SNNk6@Wnj=kg6eez*W;bO~ z!VdcbOak4G8V6XER2ঐ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 controls). You can also switch spells by scrolling the mouse wheel while sneaking. + +SECTION Charging Wands +Charging your wand +-------------------- +To charge your wand, place the wand in the central slot of the arcane workbench and place some magic crystals in the upper of the two slots on the left, and then press apply. Each crystal is worth MANA_PER_CRYSTAL mana, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals so if the wand needs, for example, 30 more mana, MANA_PER_CRYSTAL_MINUS_30 mana will be lost when charging it. All wands will take an exact number of crystals to charge if they are empty, unless they have a storage upgrade applied. + +SECTION Upgrading Wands +Upgrading your wand +-------------------- +To upgrade your wand, you will need a tome of arcana of the appropriate tier (see Tiers) or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the lower of the two slots on the left, then press apply. + +Special wand upgrades improve a particular aspect of a wand. Each type of upgrade can stack up to three times, and the total number of upgrades that a wand can take depends on its tier. Upgrades cannot be removed. +PAGEBREAK +SECTION Flowers and Flasks +Flowers and Flasks +-------------------- +You will probably come across curious glowing flowers growing in the wild from time to time. These are crystal flowers, a naturally occurring source of mana. They can be harvested and crafted to extract the mana as crystals. + +Need to recharge your wand on the go? No problem! Mana can now be bottled. Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge. This process will consume the bottle. Some mana is lost during bottling. +PAGEBREAK +SECTION Tiers +Tiers +-------------------- +Wands and spells come in four tiers: BASIC_COLOURnoviceRESET_COLOUR, APPRENTICE_COLOURapprenticeRESET_COLOUR, ADVANCED_COLOURadvanced RESET_COLOURand MASTER_COLOURmasterRESET_COLOUR. Each tier is more powerful than the last. + +BASIC_COLOURNovice RESET_COLOURwands are the ones that can be crafted. They hold up to BASIC_MAX_CHARGE mana, and can only cast novice spells. Novice spells are simple enough to be cast by anyone and they do not usually cost much mana. This does not necessarily mean that they are useless at higher tiers however; their low cost makes some novice spells useful even when you have access to master spells. + +APPRENTICE_COLOURApprentice RESET_COLOURwands are the next tier up from novice wands. They hold up to APPRENTICE_MAX_CHARGE mana and can cast novice and apprentice spells. Apprentice spells are a little more impressive than novice spells but usually cost more. + +ADVANCED_COLOURAdvanced RESET_COLOURwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold ADVANCED_MAX_CHARGE mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on enemies. + +MASTER_COLOURMaster RESET_COLOURwands are the most powerful wands in existence. They hold up to MASTER_MAX_CHARGE mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution. +PAGEBREAK +SECTION Elements +Elements +-------------------- +Spells belong to different elements, which describe the nature of the spell and also have perks when used with certain wands. + +FIRE_COLOURFire +Perhaps the most destructive element, fire concerns burning, lava, and explosions. A powerful pyromancer will unleash hell upon their enemies and probably set the world alight in the process. Most fire attack spells set fire to their target, causing ongoing damage over time. However, be wary that fire spells may have no effect on nether mobs. + +ICE_COLOURIce +The element of ice is made of all that is cold. Frost spells often slow enemies down or freeze them completely, and are especially effective on creatures of fire. Frost magic can prove equally useful outside of combat, such as freezing water to cross a river. + +LIGHTNING_COLOURLightning +This element concerns lightning, storms, and the weather. A powerful storm mage is a force to be reckoned with, and some posess the ability to call down lightning at will. Lightning spells often damage multiple enemies at once and usually seek their target, making them an effective attack against any mob... but beware of creepers. + +NECROMANCY_COLOURNecromancy +Necromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon creatures to fight for you or even bend the will of your enemies. + +EARTH_COLOUREarth +The element of earth is focused on the natural world: animals, plants, the wind, and such like. Earth magic is diverse and takes a wide variety of forms, from poisoning enemies to unleashing the fury of the weather. Earth spells are a mixture of attack, defence and utility. + +SORCERY_COLOURSorcery +Sorcery is the element of force and change. Sorcerers manipulate light, gravity and even reality itself to fit their needs. Sorcery spells can be used, among other things, to grant their caster magical powers or move objects to their will. + +HEALING_COLOURHealing +The element of healing is concerned with defence and regeneration. Healers seek to protect themselves and their allies as much as possible and as such can be very difficult opponents. Though generally not used as an attack, the purifying light of some healing spells will do considerable damage to the undead. Healing spells are indispensable when in combat. + +The boundaries between the different elements are not always distinct, and some spells bear traits of elements other than their own. + +If you are lucky, you may happen upon an elemental wand. These wands will allow you to cast spells of the right element for more potency than usual. +PAGEBREAK +SECTION Wizard Armour +Wizard Armour +-------------------- +As a wizard, you will need something to protect you from the creatures you fight. No ordinary armour will do though. To make the most of your spells, you will need wizard armour: hat, robes, leggings and boots. Unlike ordinary armour, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much mana. Charge them as you would a wand in the arcane workbench or with a mana flask, but be careful - if they run out of mana, you will find yourself defenceless. + +You can obtain wizard armour by crafting it from magical silk, obtained by crafting string with a magic crystal. + +Those wizards who devote themselves to the practice of one element sometimes wear special garments which grant bonuses for that element. Full sets of such garments are very sought after among wizards and are not easy to find. + +Legend speaks of an arcane seal used by the most powerful wizards to greatly improve their armour. +PAGEBREAK +SECTION Wizards and Towers +Wizards and Towers +-------------------- +Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter tall towers with distinctive pointed roofs. These are the residences of fellow wizards. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder. If, however, it is a master spell you seek, you will need to speak to a specialist. + +Unfortunately, there are a few wizards out there who do not welcome visitors. These wizards are typically outcasts, and are hostile to anyone crossing their path. Approach these individuals with caution, and be prepared to defend yourself against powerful magic. Defeat them however, and their knowledge is yours for the taking. +PAGEBREAK +SECTION Crafting Recipes +Crafting Recipes +-------------------- +PAGEBREAK +PAGEBREAK +Crafting Recipes +-------------------- +PAGEBREAK +PAGEBREAK +Crafting Recipes +-------------------- +PAGEBREAK +PAGEBREAK +Crafting Recipes +-------------------- +PAGEBREAK +PAGEBREAK +Credits +-------------------- +Electroblob's Wizardry +Version VERSION +For Minecraft 1.10.2 + +Designed, coded and textured by Electroblob + +Thanks to Minecraft Forge and MCP, without which this mod would not have been possible. + +Thanks also to the Minecraft modding community, which always has an answer to my modding problems! + +In addition, I'd like to thank the following individuals for their contributions to the mod: + +Translations: + +- Russian: VilagVil +- Spanish and Mexican Spanish: MadWrist + +Lightning ray sound effect from OhhWowProductions \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/texts/handbook_en_US.txt b/src/main/resources/assets/wizardry/texts/handbook_en_US.txt new file mode 100644 index 00000000..95746130 --- /dev/null +++ b/src/main/resources/assets/wizardry/texts/handbook_en_US.txt @@ -0,0 +1,217 @@ +PAGEBREAK +LINEBREAK + + + + +The Wizard's Handbook + + + +By Electroblob +PAGEBREAK +Introduction +-------------------- + +Greetings, wizard! This book explains the many ways of the arcane and how to use them. + +Should you ever lose this book, you can get a new one by crafting a book with a magic crystal. +PAGEBREAK +Contents +-------------------- +PAGEBREAK +SECTION Setting up +Setting up +-------------------- +To get started with wizardry, you will need a few things: + +- A magic wand, crafted with a gold nugget, a stick, and a magic crystal. + +- An arcane workbench, crafted with 3 stone, 1 lapis lazuli block, 2 magic crystals, 2 gold nuggets and 1 purple carpet. + +- A spell book. These can be found in chests, dropped as loot, purchased from wizards, or you can make a beginner's spell, magic missile, with a book and 4 magic crystals. + +You will also need a bunch more magic crystals to supply your wand with mana. +PAGEBREAK +SECTION Mana +Mana +-------------------- +Mana is the arcane energy that gives wizards their powers. It manifests itself in naturally occurring crystals, which can be found embedded in rocks underground. Wands can store mana within them, and this mana is channeled into the spells that you cast. Different spells cost different amounts of mana, depending on how powerful they are and how long they last. + +Mouse over a wand to see how much mana is stored in it. +IMAGE CRYSTAL +LINEBREAK + + + + + + + Magic + Crystal Ore Crystal +PAGEBREAK +SECTION Wands +Wands +-------------------- +The wand is the implement of choice for a wizard. With it, you can cast any spell provided the wand can contain its power (see Tiers for a more in-depth explanation). Wands come in +various different varieties but you will almost certainly start with a basic magic wand. + +When holding a wand, a small heads-up display will show in the corner of the screen. This indicates the spell that is currently selected along with a pictorial representation of it, and, if the spell has been cast, a cooldown bar indicating the time until that spell can be cast again. +PAGEBREAK +SECTION Spells +Spells +-------------------- +A wand is useless without spells to cast with it. Spells are recorded in two forms: in books, which are permanent, and in scrolls, which are temporary. + +Spell books are of little use on their own; instead they are used to bind the spell they contain to wands. Spell books can be found throughout the world and it will not take long for you to come across one. When you do find one, you can mouse over the spell book to see basic information about the spell at a glance. You can also right-click whilst holding a spell book to read more detailed information about the spell. + +Scrolls, on the other hand, serve a different purpose: right-clicking whilst holding one will cast the spell that is bound to it, destroying the scroll in the process. Like spell books, scrolls can be found throughout the world, but you can also make them yourself by crafting a blank scroll from a piece of paper and some string. You can then bind a spell to the scroll using the arcane workbench, but only if you have knowledge of that spell. Doing so will consume a number of magic crystals equal to the mana cost of the spell (rounded up to the nearest MANA_PER_CRYSTAL). + +To the untrained eye, the magical runes with which spells are written are unreadable. In order to identify a spell, you could, of course, cast it and see what happens - though doing so may cause unwanted side-effects, and many spells need certain conditions in order to work. A safer and more reliable option is to use a scroll of identification, which can be found in chests or purchased from a wizard. Right- -clicking whilst holding one will identify the first unknown spell book or scroll on your hotbar, consuming the scroll of identification. + +Scrolls are quite useful when you need to use a spell once or twice on a particular quest but don't want it to take up a slot on your wand. It should be noted, however, that scrolls are at best an inefficient method of casting spells. +PAGEBREAK +SECTION Arcane Workbench +The Arcane Workbench +-------------------- +The arcane workbench is a block similar in appearance to the enchantment table where you can charge, upgrade, and bind spells to your wand. Simply place it anywhere and right click, and you will see a gui appear like the one to the right. +PAGEBREAK +IMAGE WORKBENCH +LINEBREAK + + + + + + + + + + + + + + The Arcane Workbench +PAGEBREAK +SECTION Binding Spells +Binding Spells +-------------------- +To bind a spell to your wand, simply place your wand in the central slot of the workbench, then place the spell book in one of the surrounding slots and press apply. You can bind up to five spells to a wand at one time, though this may be increased with attunement upgrades. When holding a wand, you can switch between spells with the NEXT_SPELL_KEY and PREVIOUS_SPELL_KEY keys (these can be changed in options -> controls). You can also switch spells by scrolling the mouse wheel while sneaking. + +SECTION Charging Wands +Charging your wand +-------------------- +To charge your wand, place the wand in the central slot of the arcane workbench and place some magic crystals in the upper of the two slots on the left, and then press apply. Each crystal is worth MANA_PER_CRYSTAL mana, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals so if the wand needs, for example, 30 more mana, MANA_PER_CRYSTAL_MINUS_30 mana will be lost when charging it. All wands will take an exact number of crystals to charge if they are empty, unless they have a storage upgrade applied. + +SECTION Upgrading Wands +Upgrading your wand +-------------------- +To upgrade your wand, you will need a tome of arcana of the appropriate tier (see Tiers) or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the lower of the two slots on the left, then press apply. + +Special wand upgrades improve a particular aspect of a wand. Each type of upgrade can stack up to three times, and the total number of upgrades that a wand can take depends on its tier. Upgrades cannot be removed. +PAGEBREAK +SECTION Flowers and Flasks +Flowers and Flasks +-------------------- +You will probably come across curious glowing flowers growing in the wild from time to time. These are crystal flowers, a naturally occurring source of mana. They can be harvested and crafted to extract the mana as crystals. + +Need to recharge your wand on the go? No problem! Mana can now be bottled. Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge. This process will consume the bottle. Some mana is lost during bottling. +PAGEBREAK +SECTION Tiers +Tiers +-------------------- +Wands and spells come in four tiers: BASIC_COLOURnoviceRESET_COLOUR, APPRENTICE_COLOURapprenticeRESET_COLOUR, ADVANCED_COLOURadvanced RESET_COLOURand MASTER_COLOURmasterRESET_COLOUR. Each tier is more powerful than the last. + +BASIC_COLOURNovice RESET_COLOURwands are the ones that can be crafted. They hold up to BASIC_MAX_CHARGE mana, and can only cast novice spells. Novice spells are simple enough to be cast by anyone and they do not usually cost much mana. This does not necessarily mean that they are useless at higher tiers however; their low cost makes some novice spells useful even when you have access to master spells. + +APPRENTICE_COLOURApprentice RESET_COLOURwands are the next tier up from novice wands. They hold up to APPRENTICE_MAX_CHARGE mana and can cast novice and apprentice spells. Apprentice spells are a little more impressive than novice spells but usually cost more. + +ADVANCED_COLOURAdvanced RESET_COLOURwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold ADVANCED_MAX_CHARGE mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on enemies. + +MASTER_COLOURMaster RESET_COLOURwands are the most powerful wands in existence. They hold up to MASTER_MAX_CHARGE mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution. +PAGEBREAK +SECTION Elements +Elements +-------------------- +Spells belong to different elements, which describe the nature of the spell and also have perks when used with certain wands. + +FIRE_COLOURFire +Perhaps the most destructive element, fire concerns burning, lava, and explosions. A powerful pyromancer will unleash hell upon their enemies and probably set the world alight in the process. Most fire attack spells set fire to their target, causing ongoing damage over time. However, be wary that fire spells may have no effect on nether mobs. + +ICE_COLOURIce +The element of ice is made of all that is cold. Frost spells often slow enemies down or freeze them completely, and are especially effective on creatures of fire. Frost magic can prove equally useful outside of combat, such as freezing water to cross a river. + +LIGHTNING_COLOURLightning +This element concerns lightning, storms, and the weather. A powerful storm mage is a force to be reckoned with, and some posess the ability to call down lightning at will. Lightning spells often damage multiple enemies at once and usually seek their target, making them an effective attack against any mob... but beware of creepers. + +NECROMANCY_COLOURNecromancy +Necromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon creatures to fight for you or even bend the will of your enemies. + +EARTH_COLOUREarth +The element of earth is focused on the natural world: animals, plants, the wind, and such like. Earth magic is diverse and takes a wide variety of forms, from poisoning enemies to unleashing the fury of the weather. Earth spells are a mixture of attack, defense and utility. + +SORCERY_COLOURSorcery +Sorcery is the element of force and change. Sorcerers manipulate light, gravity and even reality itself to fit their needs. Sorcery spells can be used, among other things, to grant their caster magical powers or move objects to their will. + +HEALING_COLOURHealing +The element of healing is concerned with defense and regeneration. Healers seek to protect themselves and their allies as much as possible and as such can be very difficult opponents. Though generally not used as an attack, the purifying light of some healing spells will do considerable damage to the undead. Healing spells are indispensable when in combat. + +The boundaries between the different elements are not always distinct, and some spells bear traits of elements other than their own. + +If you are lucky, you may happen upon an elemental wand. These wands will allow you to cast spells of the right element for more potency than usual. +PAGEBREAK +SECTION Wizard Armor +Wizard Armor +-------------------- +As a wizard, you will need something to protect you from the creatures you fight. No ordinary armor will do though. To make the most of your spells, you will need wizard armor: hat, robes, leggings and boots. Unlike ordinary armor, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much mana. Charge them as you would a wand in the arcane workbench or with a mana flask, but be careful - if they run out of mana, you will find yourself defenseless. + +You can obtain wizard armor by crafting it from magical silk, obtained by crafting string with a magic crystal. + +Those wizards who devote themselves to the practice of one element sometimes wear special garments which grant bonuses for that element. Full sets of such garments are very sought after among wizards and are not easy to find. + +Legend speaks of an arcane seal used by the most powerful wizards to greatly improve their armor. +PAGEBREAK +SECTION Wizards and Towers +Wizards and Towers +-------------------- +Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter tall towers with distinctive pointed roofs. These are the residences of fellow wizards. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder. If, however, it is a master spell you seek, you will need to speak to a specialist. + +Unfortunately, there are a few wizards out there who do not welcome visitors. These wizards are typically outcasts, and are hostile to anyone crossing their path. Approach these individuals with caution, and be prepared to defend yourself against powerful magic. Defeat them however, and their knowledge is yours for the taking. +PAGEBREAK +SECTION Crafting Recipes +Crafting Recipes +-------------------- +PAGEBREAK +PAGEBREAK +Crafting Recipes +-------------------- +PAGEBREAK +PAGEBREAK +Crafting Recipes +-------------------- +PAGEBREAK +PAGEBREAK +Crafting Recipes +-------------------- +PAGEBREAK +PAGEBREAK +Credits +-------------------- +Electroblob's Wizardry +Version VERSION +For Minecraft 1.10.2 + +Designed, coded and textured by Electroblob + +Thanks to Minecraft Forge and MCP, without which this mod would not have been possible. + +Thanks also to the Minecraft modding community, which always has an answer to my modding problems! + +In addition, I'd like to thank the following individuals for their contributions to the mod: + +Translations: + +- Russian: VilagVil +- Spanish and Mexican Spanish: MadWrist + +Lightning ray sound effect from OhhWowProductions \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/texts/handbook_es_ES.txt b/src/main/resources/assets/wizardry/texts/handbook_es_ES.txt new file mode 100644 index 00000000..9747dc36 --- /dev/null +++ b/src/main/resources/assets/wizardry/texts/handbook_es_ES.txt @@ -0,0 +1,311 @@ +PAGEBREAK +LINEBREAK + + + + +El Manual del Mago + + + +Por Electroblob +PAGEBREAK +Introduccion +-------------------- + +Saludos, mago! Este libro explica las diferentes formas de lo arcano y como +usarlas. + +Si alguna vez pierde este libro, lo puede volver a fabricar con un libro y un cristal magico. +PAGEBREAK +Contents +-------------------- +PAGEBREAK +SECTION Comenzando +Comenzando +-------------------- +Para iniciar con Wizardry, necesitaras algunas cosas: + +- Una varita magica, crafteada con una pepita de oro, un palo y un cristal magico. + +- Una Mesa de Trabajo Arcana, crafteada con 3 piedras, 1 bloque de lapis lazuli, +2 cristales magicos, 2 pepitas de oro y 1 alfombra morada. + +- Un libro de hechizos. Estos pueden ser encontrados en cofres, arrojados como botin, +comprados a magos, o puedes hacer el hechizo del aprendiz, Misil Magico, con un +libro y 4 cristales magicos. + +Tambien necesitaras un monton de cristales magicos para suplir tu varita con mana. +PAGEBREAK +SECTION Mana +Mana +-------------------- +Mana es la energia arcana que le da a los magos sus poderes. Se manifiesta en cristales que aparecen naturalmente, los cuales aparecen incrustados bajo roca. Las varitas almacenan mana dentro de ellas, y este mana es canalizado en los hechizos que tu lanzas. Cada hechizo cuesta una cantidad diferente de mana, dependiendo de que tan +poderosos sean y que tanto duran. + +Coloca tu raton sobre una varita para ver la cantidad de mana que tiene. +IMAGE CRYSTAL +LINEBREAK + + + + + + + Mena +de Cristal Magico Cristal +PAGEBREAK +SECTION Varitas +Varitas +-------------------- +La varita es la herramienta de eleccion de un mago. Con ella, puedes lanzar cualquier +hechizo, solo si la varita contiene dicho poder (ver Nivel de varitas para entender mejor). +Las varitas vienen en variedades diferentes, es muy probable que empieces con la varita magica +basica. + +Cuando tienes una varita en tu mano, aparecera una pequena ventana en el esquina de la +pantalla. Esto indica el hechizo que esta seleccionado actualmente con una representacion +de este, y, si el hechizo ha sido lanzado, una barra con el tiempo de reactivacion para que +el hechizo pueda volcver a ser lanzado de nuevo. +PAGEBREAK +SECTION Hechizos +Hechizos +-------------------- +Una varita es inservible sin hechizos que lanzar. Los hechizos estan guardados en dos +formas: en libros, los cuales son permanentes, y en pergaminos, que son temporales. + +Los libros de hechizos son poco utiles ellos solos, por eso se suele ligar el hechizo +que contienen a las varitas. Los libros de hechizos pueden ser encontrados por todo el +mundo. Cuando encuentres uno, puedes colocar el raton sobre el libro para ver su informacion. +Tambien puede hacer clic derecho mientras lo tiene en su mano para ver mas informacion. + +Pergaminos, por otro lado, sirven un proposito diferente: hacer clic derecho con +el en la mano, lanzara el hechizo que tenga ligado a el, destruyendo el papel en el +proceso. Como los libros, los hechizos pueden ser encontrados por todo el mundo, pero +tambien puedes hacerlos tu mismo al craftear un pergamino vacio con papel y un poco de +hilo. Puedes ligarle un hechizo usando una Mesa de Trabajo Arcana, pero solo si ya conoces +dicho hechizo. Hacer esto consumira un cantidad de cristales magicos equivalente al mana +que cuesta lanzar el hechizo (redondeado al MANA_PER_CRYSTAL mas cercano). + +Para el ojo sin experiencia, las runas magicas con las cuales los hechizos son escritos +son ilegibles. Por eso, para identificar un hechizo, podrias lanzarlo y ver sus efectos +pero quizas ocasione efectos no deseados, y algunos hechizos necesitan condicione necesarias +para funcionar. Una forma mas segura, es usar un Pergamino de la Identificacion, el cual +puede ser comprado a magos. Hacer clic derecho con uno en la mano identificara el +primer hechizo desconocido en tu barra. + +Los pergaminos son utiles cuando necesitas lanzar un hechizo una o dos veces en una +ocasion en particular pero no quieres que te ocupe un espacio en tu varita. Hay que +resaltar, como sea, que los pergaminos son un metodo ineficiente de lanzar hechizos. +PAGEBREAK +SECTION Mesa de Trabajo Arcana +La Mesa de Trabajo Arcana +-------------------- +La Mesa de Trabajo Arcana es un bloque similar en apariencia a la mesa de encantamiento +donde puedes cargar, mejorar y ligar hechizos a una varita. Simplemente coloca donde sea +y haz clic derecho, y veras una interfaz aparecer parecida a la de la derecha. +PAGEBREAK +IMAGE WORKBENCH +LINEBREAK + + + + + + + + + + + + + + La Mesa de Trabajo Arcana +PAGEBREAK +SECTION Ligando Hechizos +Ligando Hechizos +-------------------- +Para ligar un hechizo a tu varita, simplemente coloca tu varita en el espacio central +de la Mesa de Trabajo Arcana, luego coloca el libro de hechizo en uno de los espacios +que estan alrededor y pulsa Aplicar. Puedes ligar 5 hechizos a la vez, esto puede ser +aumentado con mejoras. Cuando tienes una varita en la mano, puedes cambiar los hechizos +con las NEXT_SPELL_KEY y PREVIOUS_SPELL_KEY teclas. Tambien puedes cambiarlo al agacharte +y moviendo la rueda del raton. + +SECTION Cargando varitas +Cargando varitas +-------------------- +Para cargar tu varita, coloca la varita en el espacio central de la Mesa de Trabajo Arcana +y coloca algunos cristales magicos en el espacio mas arriba en la izquierda, y despues +pulsa Aplicar. Cada cristal vale MANA_PER_CRYSTAL mana, y la varita solo toma lo que +necesita, asi que puedes mantener cristales en la Mesa de Trabajo Arcana para cuando +los necesites. Todas las varitas tomaran un numero exacto de cristales para cargarla si esta +vacia, a menos que tengan una mejora de almacenamiento aplicada. + +SECTION Mejorando varitas +Mejorando tu varita +-------------------- +Para mejorar tu varita, necesitaras un Tomo de lo Arcano de tu nivel apropiado (ver +Niveles) o una mejora de varita especial. Ambos pueden ser encontrados como botin o +comprado a un mago. Para mejorar tu varita, colocala en el espacio central de la +Mesa de Trabajo Arcana y la mejora en el espacio inferior a la izquierda, y pulsar Aplicar. + +Mejoras de varita especiales mejorar un aspecto particular de la varita. Cada tipo de mejora +se puede apilar 3 veces, y el total de mejoras que puede tener una varita depende del nivel. +Las mejoras no pueden ser removidas. +PAGEBREAK +SECTION Flores y Frascos +Flores y Frascos +-------------------- +Es probable que te encuentres con flores brillantes creciendo en el suelo de tiempo +en tiempo. Esas son flores de cristal magico, una fuente de mana natural. Pueden ser +cosechadas y crafteadas para extraer mana en cristales. + +Necesitas recargar tu varita de camino? No hay problema! El mana puede ser enfrascado. +Simplemente craftea un frasco de mana con una botella de cristal y ocho cristales magicos +y llevatelo contigo. Cuando necesites mana, solo craftea la varita con el frasco para +recargar un poco. Este proceso consumira la botella. Un poco de mana se perdera en el +proceso de enfrascamiento. +PAGEBREAK +SECTION Niveles +Niveles +-------------------- +Las varitas y los hechizos vienen en cuatro niveles: BASIC_COLOURBasicoRESET_COLOUR, APPRENTICE_COLOURAprendizRESET_COLOUR, ADVANCED_COLOURAvanzadoRESET_COLOUR y MASTER_COLOURMaestroRESET_COLOUR. Cada nivel es mejor que el anterior. + +Las varitas BASIC_COLOURBasico RESET_COLOURson las que pueden ser crafteadas. Almacenan +BASIC_MAX_CHARGE mana, y solo pueden lanzar hechizos basicos. Hechizos basicos son suficientemente simples para ser lanzados por cualquiera y no usan mucho mana. Esto +no significa que son inservibles en niveles mas altos, sin embargo; su costo pequeno +hace que algunos hechizos basicos sean utiles cuando tienes acceso a hechizos maestros. + +Las varitas APPRENTICE_COLOURAprendiz RESET_COLOURson el siguiente nivel despues de las +varitas basicas. Almacenan APPRENTICE_MAX_CHARGE mana y pueden lanzar hechizos basicos y de +aprendiz. Los hechizos de aprendiz son mas llamativos que los basicos, pero cuestan mas. + +Las varitas ADVANCED_COLOURAvanzado RESET_COLOURson muy raras y mucho mas poderosas. +Pueden lanzar todos los hechizos excepto los maestros, y almacenar ADVANCED_MAX_CHARGE mana. +Los hechizos avanzados pueden otorgar poderes de superhumano como invisibilidad y causar +mucho dano a los enemigos. + +Las varitas MASTER_COLOURMaestro RESET_COLOURson las mas poderosas varitas que existen. Almacenan MASTER_MAX_CHARGE mana, y pueden lanzar cualquier hechizo. Los libros de hechizos +maestros son muy raros y los hechizos pueden causar una gran devastacion, no solo a los enemigos +si no al mundo en si. Usar con precaucion. +PAGEBREAK +SECTION Elementos +Elementos +-------------------- +Los hechizos pertenecen a diferentes elementos, los cuales describen la naturaleza +del hechizo y tambien tienen ventajas cuando son lanzados con ciertas varitas. + +FIRE_COLOURFuego +Quizas el elemento mas destructivo, fuego conlleva quemaduras, lava, y explosiones. Un piromano poderoso desatara el infierno sobre sus enemigos y probablemente encienda +el mundo en el proceso. La mayoria de los ataques de fuego queman a sus objetivos, +causando dano extra sobre el tiempo. Sin embargo, te en cuenta que no tendran efecto +en monstruos del Nether. + +ICE_COLOURHielo +El elemento de hielo esta formado por todo lo que es frio. Los hechizos de hielo +frencuentemente ralentizan a los enemigos o los congelan completamente, y son +efectivos contra criaturas de fuego. La magia de hielo puede ser util fuera de +combate, como para congelar un rio para poder cruzarlo a pie. + +LIGHTNING_COLOURRayo +Este elemento conlleva relampagos, tormentas y el clima. Un mago de tormenta poderoso +es una fuerza dura de vencer, y algunos son capaces de llamar rayos a voluntad. Los +hechizos de rayo con frecuencia hacen dano a varios enemigos a la vez y usualmente +persiguen a su objetivo, haciendolos efectivos para atacar a cualquier monstruo... +pero cuidado con los creepers. + +NECROMANCY_COLOURNigromancia +Nigromancia es el elemento de oscuridad, caos y lo no-muerto. Nigromantes son +misteriosos y a veces considerados malos, aunque no siempre es el casp. Los +hechizos de nigromancia son usados para invocar criaturas que pelearan por ti o +hasta controlar la voluntad de tus enemigos. + +EARTH_COLOURTierra +El elemento de tierra esta enfocado en el mundo natural: animales, plantas, el viento, y cosas asi. La magia de tierra es diversa y toma una gran variedad de formas, desde envenerar enemigos hasta desatar la furia del clima. Los hechizos de tierra son una liga de ataque, defensa y utilidad. + +SORCERY_COLOURHechiceria +La hechiceria es el elemento de la fuerza y el cambio. Los hechiceros manipulan la luz, +la gravedad y hasta la realidad para su beneficio. Los hechizos de hechiceria pueden +ser usados, entre otras cosas, para conceder poderes magicos y mover objetos. + +HEALING_COLOURCuracion +El elemento de curacion conlleva defensa y regeneracion. Los sanadores buscan +protegerse y a sus aliados lo mas posble, lo cual puede ser dificil para los +oponentes. A pesar de no considerarse como un ataque, la luz purificadora de sus +hechizos de curacion puede ser letales para los no-muertos. Los hechizos de +curacion son indispensables cuando se esta dentro de combate. + +Los limites entre los diferentes elementos no siempre son distintos, y algunos hechizos +tienen atributos de otros elementos mas que del suyo. + +Si eres suertudo, puedes que te encuentres una varita elemental. Estas varitas te +permiten lanzar hechizos del elemento correcto con mas potencia de lo usual. +PAGEBREAK +SECTION Armadura de Mago +Armadura de Mago +-------------------- +Como mago, necesitaras algo para protegerte de las criaturas que combates. +Ninguna armadura ordinal valdra. Para sacarle provecho a tus hechizos, necesitas +armadura de mago: sombrero, tunica, pantalones y botas. A diferencia de las otras, +estas no se romperan. Sin embargo, usaran energia arcana para proteger al usuario. +Esto significa que deben ser cargados con cristales magicos. Ventajosamente no +consumen mucho mana. Recargalos en la mesa o con frascos. + +Puedes obtener armadura de mago crafteandola con Seda Magica, obtenida al craftear +hilo con un cristal magico. + +Esos magos que se dedican a practicar un solo elemento algunas veces visten +piezas especiales las cuales ofrecen bonus a dicho elemento. Los sets completos +de esta armadura son muy codiciados entre magos y no son faciles de conseguir. + +Hay una legenda que habla sobre un sello arcano usado por los magos mas poderosos +para mejorar en sobre manera su armadura. +PAGEBREAK +SECTION Magos y Torres +Magos y Torres +-------------------- +No temas - no eres el unico que practica magia en este mundo. En tus viajes, te encontraras con torres altas con unos distintivos techos puntiagudos. +Estas son las residencias de varios magos. Una vida de soledad puede hacer que los magos se vuelvan grunones, pero usualmente son seres amigables que estan +dispuestos a compartir su conocimiento contigo - con un precio. Preparate para pagar con gemas y metales preciosos, y a cambio recibiras grandezas arcanas. +Si, en dado caso, un hechizo maestro es lo que buscas, deberar hablar con un especialista en dicho elemento. + +Desafortunadamente, hay algunos magos que no le dan la bienvenida a los visitantes. Estos magos son marginados y son hostiles hacia cualquiera que cruce su camino. Aproximate a ellos con cautela, y preparate para defenderte contra magia sumamente poderosa. Derrotalos, y su conocimiento sera tuyo. +PAGEBREAK +SECTION Recetas de Crafteo +Recetas de Crafteo +-------------------- +PAGEBREAK +PAGEBREAK +Recetas de Crafteo +-------------------- +PAGEBREAK +PAGEBREAK +Recetas de Crafteo +-------------------- +PAGEBREAK +PAGEBREAK +Recetas de Crafteo +-------------------- +PAGEBREAK +PAGEBREAK +Creditos +-------------------- +Electroblob's Wizardry +Version VERSION +Para Minecraft 1.10.2 + +Disenado, codificado y texturizado por Electroblob + +Gracias a Minecraft Forge y MCP, porque sin estos esto no hubiese sido posible. + +Gracias tambien a la comunidad de Minecraft que crea mods, la cual siempre tiene una respuesta para mis problemas! + +In addition, I'd like to thank the following individuals for their contributions to the mod: + +Translations: + +- Russian: VilagVil +- Spanish and Mexican Spanish: MadWrist + +Lightning ray sound effect from OhhWowProductions \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/texts/handbook_es_MX.txt b/src/main/resources/assets/wizardry/texts/handbook_es_MX.txt new file mode 100644 index 00000000..9747dc36 --- /dev/null +++ b/src/main/resources/assets/wizardry/texts/handbook_es_MX.txt @@ -0,0 +1,311 @@ +PAGEBREAK +LINEBREAK + + + + +El Manual del Mago + + + +Por Electroblob +PAGEBREAK +Introduccion +-------------------- + +Saludos, mago! Este libro explica las diferentes formas de lo arcano y como +usarlas. + +Si alguna vez pierde este libro, lo puede volver a fabricar con un libro y un cristal magico. +PAGEBREAK +Contents +-------------------- +PAGEBREAK +SECTION Comenzando +Comenzando +-------------------- +Para iniciar con Wizardry, necesitaras algunas cosas: + +- Una varita magica, crafteada con una pepita de oro, un palo y un cristal magico. + +- Una Mesa de Trabajo Arcana, crafteada con 3 piedras, 1 bloque de lapis lazuli, +2 cristales magicos, 2 pepitas de oro y 1 alfombra morada. + +- Un libro de hechizos. Estos pueden ser encontrados en cofres, arrojados como botin, +comprados a magos, o puedes hacer el hechizo del aprendiz, Misil Magico, con un +libro y 4 cristales magicos. + +Tambien necesitaras un monton de cristales magicos para suplir tu varita con mana. +PAGEBREAK +SECTION Mana +Mana +-------------------- +Mana es la energia arcana que le da a los magos sus poderes. Se manifiesta en cristales que aparecen naturalmente, los cuales aparecen incrustados bajo roca. Las varitas almacenan mana dentro de ellas, y este mana es canalizado en los hechizos que tu lanzas. Cada hechizo cuesta una cantidad diferente de mana, dependiendo de que tan +poderosos sean y que tanto duran. + +Coloca tu raton sobre una varita para ver la cantidad de mana que tiene. +IMAGE CRYSTAL +LINEBREAK + + + + + + + Mena +de Cristal Magico Cristal +PAGEBREAK +SECTION Varitas +Varitas +-------------------- +La varita es la herramienta de eleccion de un mago. Con ella, puedes lanzar cualquier +hechizo, solo si la varita contiene dicho poder (ver Nivel de varitas para entender mejor). +Las varitas vienen en variedades diferentes, es muy probable que empieces con la varita magica +basica. + +Cuando tienes una varita en tu mano, aparecera una pequena ventana en el esquina de la +pantalla. Esto indica el hechizo que esta seleccionado actualmente con una representacion +de este, y, si el hechizo ha sido lanzado, una barra con el tiempo de reactivacion para que +el hechizo pueda volcver a ser lanzado de nuevo. +PAGEBREAK +SECTION Hechizos +Hechizos +-------------------- +Una varita es inservible sin hechizos que lanzar. Los hechizos estan guardados en dos +formas: en libros, los cuales son permanentes, y en pergaminos, que son temporales. + +Los libros de hechizos son poco utiles ellos solos, por eso se suele ligar el hechizo +que contienen a las varitas. Los libros de hechizos pueden ser encontrados por todo el +mundo. Cuando encuentres uno, puedes colocar el raton sobre el libro para ver su informacion. +Tambien puede hacer clic derecho mientras lo tiene en su mano para ver mas informacion. + +Pergaminos, por otro lado, sirven un proposito diferente: hacer clic derecho con +el en la mano, lanzara el hechizo que tenga ligado a el, destruyendo el papel en el +proceso. Como los libros, los hechizos pueden ser encontrados por todo el mundo, pero +tambien puedes hacerlos tu mismo al craftear un pergamino vacio con papel y un poco de +hilo. Puedes ligarle un hechizo usando una Mesa de Trabajo Arcana, pero solo si ya conoces +dicho hechizo. Hacer esto consumira un cantidad de cristales magicos equivalente al mana +que cuesta lanzar el hechizo (redondeado al MANA_PER_CRYSTAL mas cercano). + +Para el ojo sin experiencia, las runas magicas con las cuales los hechizos son escritos +son ilegibles. Por eso, para identificar un hechizo, podrias lanzarlo y ver sus efectos +pero quizas ocasione efectos no deseados, y algunos hechizos necesitan condicione necesarias +para funcionar. Una forma mas segura, es usar un Pergamino de la Identificacion, el cual +puede ser comprado a magos. Hacer clic derecho con uno en la mano identificara el +primer hechizo desconocido en tu barra. + +Los pergaminos son utiles cuando necesitas lanzar un hechizo una o dos veces en una +ocasion en particular pero no quieres que te ocupe un espacio en tu varita. Hay que +resaltar, como sea, que los pergaminos son un metodo ineficiente de lanzar hechizos. +PAGEBREAK +SECTION Mesa de Trabajo Arcana +La Mesa de Trabajo Arcana +-------------------- +La Mesa de Trabajo Arcana es un bloque similar en apariencia a la mesa de encantamiento +donde puedes cargar, mejorar y ligar hechizos a una varita. Simplemente coloca donde sea +y haz clic derecho, y veras una interfaz aparecer parecida a la de la derecha. +PAGEBREAK +IMAGE WORKBENCH +LINEBREAK + + + + + + + + + + + + + + La Mesa de Trabajo Arcana +PAGEBREAK +SECTION Ligando Hechizos +Ligando Hechizos +-------------------- +Para ligar un hechizo a tu varita, simplemente coloca tu varita en el espacio central +de la Mesa de Trabajo Arcana, luego coloca el libro de hechizo en uno de los espacios +que estan alrededor y pulsa Aplicar. Puedes ligar 5 hechizos a la vez, esto puede ser +aumentado con mejoras. Cuando tienes una varita en la mano, puedes cambiar los hechizos +con las NEXT_SPELL_KEY y PREVIOUS_SPELL_KEY teclas. Tambien puedes cambiarlo al agacharte +y moviendo la rueda del raton. + +SECTION Cargando varitas +Cargando varitas +-------------------- +Para cargar tu varita, coloca la varita en el espacio central de la Mesa de Trabajo Arcana +y coloca algunos cristales magicos en el espacio mas arriba en la izquierda, y despues +pulsa Aplicar. Cada cristal vale MANA_PER_CRYSTAL mana, y la varita solo toma lo que +necesita, asi que puedes mantener cristales en la Mesa de Trabajo Arcana para cuando +los necesites. Todas las varitas tomaran un numero exacto de cristales para cargarla si esta +vacia, a menos que tengan una mejora de almacenamiento aplicada. + +SECTION Mejorando varitas +Mejorando tu varita +-------------------- +Para mejorar tu varita, necesitaras un Tomo de lo Arcano de tu nivel apropiado (ver +Niveles) o una mejora de varita especial. Ambos pueden ser encontrados como botin o +comprado a un mago. Para mejorar tu varita, colocala en el espacio central de la +Mesa de Trabajo Arcana y la mejora en el espacio inferior a la izquierda, y pulsar Aplicar. + +Mejoras de varita especiales mejorar un aspecto particular de la varita. Cada tipo de mejora +se puede apilar 3 veces, y el total de mejoras que puede tener una varita depende del nivel. +Las mejoras no pueden ser removidas. +PAGEBREAK +SECTION Flores y Frascos +Flores y Frascos +-------------------- +Es probable que te encuentres con flores brillantes creciendo en el suelo de tiempo +en tiempo. Esas son flores de cristal magico, una fuente de mana natural. Pueden ser +cosechadas y crafteadas para extraer mana en cristales. + +Necesitas recargar tu varita de camino? No hay problema! El mana puede ser enfrascado. +Simplemente craftea un frasco de mana con una botella de cristal y ocho cristales magicos +y llevatelo contigo. Cuando necesites mana, solo craftea la varita con el frasco para +recargar un poco. Este proceso consumira la botella. Un poco de mana se perdera en el +proceso de enfrascamiento. +PAGEBREAK +SECTION Niveles +Niveles +-------------------- +Las varitas y los hechizos vienen en cuatro niveles: BASIC_COLOURBasicoRESET_COLOUR, APPRENTICE_COLOURAprendizRESET_COLOUR, ADVANCED_COLOURAvanzadoRESET_COLOUR y MASTER_COLOURMaestroRESET_COLOUR. Cada nivel es mejor que el anterior. + +Las varitas BASIC_COLOURBasico RESET_COLOURson las que pueden ser crafteadas. Almacenan +BASIC_MAX_CHARGE mana, y solo pueden lanzar hechizos basicos. Hechizos basicos son suficientemente simples para ser lanzados por cualquiera y no usan mucho mana. Esto +no significa que son inservibles en niveles mas altos, sin embargo; su costo pequeno +hace que algunos hechizos basicos sean utiles cuando tienes acceso a hechizos maestros. + +Las varitas APPRENTICE_COLOURAprendiz RESET_COLOURson el siguiente nivel despues de las +varitas basicas. Almacenan APPRENTICE_MAX_CHARGE mana y pueden lanzar hechizos basicos y de +aprendiz. Los hechizos de aprendiz son mas llamativos que los basicos, pero cuestan mas. + +Las varitas ADVANCED_COLOURAvanzado RESET_COLOURson muy raras y mucho mas poderosas. +Pueden lanzar todos los hechizos excepto los maestros, y almacenar ADVANCED_MAX_CHARGE mana. +Los hechizos avanzados pueden otorgar poderes de superhumano como invisibilidad y causar +mucho dano a los enemigos. + +Las varitas MASTER_COLOURMaestro RESET_COLOURson las mas poderosas varitas que existen. Almacenan MASTER_MAX_CHARGE mana, y pueden lanzar cualquier hechizo. Los libros de hechizos +maestros son muy raros y los hechizos pueden causar una gran devastacion, no solo a los enemigos +si no al mundo en si. Usar con precaucion. +PAGEBREAK +SECTION Elementos +Elementos +-------------------- +Los hechizos pertenecen a diferentes elementos, los cuales describen la naturaleza +del hechizo y tambien tienen ventajas cuando son lanzados con ciertas varitas. + +FIRE_COLOURFuego +Quizas el elemento mas destructivo, fuego conlleva quemaduras, lava, y explosiones. Un piromano poderoso desatara el infierno sobre sus enemigos y probablemente encienda +el mundo en el proceso. La mayoria de los ataques de fuego queman a sus objetivos, +causando dano extra sobre el tiempo. Sin embargo, te en cuenta que no tendran efecto +en monstruos del Nether. + +ICE_COLOURHielo +El elemento de hielo esta formado por todo lo que es frio. Los hechizos de hielo +frencuentemente ralentizan a los enemigos o los congelan completamente, y son +efectivos contra criaturas de fuego. La magia de hielo puede ser util fuera de +combate, como para congelar un rio para poder cruzarlo a pie. + +LIGHTNING_COLOURRayo +Este elemento conlleva relampagos, tormentas y el clima. Un mago de tormenta poderoso +es una fuerza dura de vencer, y algunos son capaces de llamar rayos a voluntad. Los +hechizos de rayo con frecuencia hacen dano a varios enemigos a la vez y usualmente +persiguen a su objetivo, haciendolos efectivos para atacar a cualquier monstruo... +pero cuidado con los creepers. + +NECROMANCY_COLOURNigromancia +Nigromancia es el elemento de oscuridad, caos y lo no-muerto. Nigromantes son +misteriosos y a veces considerados malos, aunque no siempre es el casp. Los +hechizos de nigromancia son usados para invocar criaturas que pelearan por ti o +hasta controlar la voluntad de tus enemigos. + +EARTH_COLOURTierra +El elemento de tierra esta enfocado en el mundo natural: animales, plantas, el viento, y cosas asi. La magia de tierra es diversa y toma una gran variedad de formas, desde envenerar enemigos hasta desatar la furia del clima. Los hechizos de tierra son una liga de ataque, defensa y utilidad. + +SORCERY_COLOURHechiceria +La hechiceria es el elemento de la fuerza y el cambio. Los hechiceros manipulan la luz, +la gravedad y hasta la realidad para su beneficio. Los hechizos de hechiceria pueden +ser usados, entre otras cosas, para conceder poderes magicos y mover objetos. + +HEALING_COLOURCuracion +El elemento de curacion conlleva defensa y regeneracion. Los sanadores buscan +protegerse y a sus aliados lo mas posble, lo cual puede ser dificil para los +oponentes. A pesar de no considerarse como un ataque, la luz purificadora de sus +hechizos de curacion puede ser letales para los no-muertos. Los hechizos de +curacion son indispensables cuando se esta dentro de combate. + +Los limites entre los diferentes elementos no siempre son distintos, y algunos hechizos +tienen atributos de otros elementos mas que del suyo. + +Si eres suertudo, puedes que te encuentres una varita elemental. Estas varitas te +permiten lanzar hechizos del elemento correcto con mas potencia de lo usual. +PAGEBREAK +SECTION Armadura de Mago +Armadura de Mago +-------------------- +Como mago, necesitaras algo para protegerte de las criaturas que combates. +Ninguna armadura ordinal valdra. Para sacarle provecho a tus hechizos, necesitas +armadura de mago: sombrero, tunica, pantalones y botas. A diferencia de las otras, +estas no se romperan. Sin embargo, usaran energia arcana para proteger al usuario. +Esto significa que deben ser cargados con cristales magicos. Ventajosamente no +consumen mucho mana. Recargalos en la mesa o con frascos. + +Puedes obtener armadura de mago crafteandola con Seda Magica, obtenida al craftear +hilo con un cristal magico. + +Esos magos que se dedican a practicar un solo elemento algunas veces visten +piezas especiales las cuales ofrecen bonus a dicho elemento. Los sets completos +de esta armadura son muy codiciados entre magos y no son faciles de conseguir. + +Hay una legenda que habla sobre un sello arcano usado por los magos mas poderosos +para mejorar en sobre manera su armadura. +PAGEBREAK +SECTION Magos y Torres +Magos y Torres +-------------------- +No temas - no eres el unico que practica magia en este mundo. En tus viajes, te encontraras con torres altas con unos distintivos techos puntiagudos. +Estas son las residencias de varios magos. Una vida de soledad puede hacer que los magos se vuelvan grunones, pero usualmente son seres amigables que estan +dispuestos a compartir su conocimiento contigo - con un precio. Preparate para pagar con gemas y metales preciosos, y a cambio recibiras grandezas arcanas. +Si, en dado caso, un hechizo maestro es lo que buscas, deberar hablar con un especialista en dicho elemento. + +Desafortunadamente, hay algunos magos que no le dan la bienvenida a los visitantes. Estos magos son marginados y son hostiles hacia cualquiera que cruce su camino. Aproximate a ellos con cautela, y preparate para defenderte contra magia sumamente poderosa. Derrotalos, y su conocimiento sera tuyo. +PAGEBREAK +SECTION Recetas de Crafteo +Recetas de Crafteo +-------------------- +PAGEBREAK +PAGEBREAK +Recetas de Crafteo +-------------------- +PAGEBREAK +PAGEBREAK +Recetas de Crafteo +-------------------- +PAGEBREAK +PAGEBREAK +Recetas de Crafteo +-------------------- +PAGEBREAK +PAGEBREAK +Creditos +-------------------- +Electroblob's Wizardry +Version VERSION +Para Minecraft 1.10.2 + +Disenado, codificado y texturizado por Electroblob + +Gracias a Minecraft Forge y MCP, porque sin estos esto no hubiese sido posible. + +Gracias tambien a la comunidad de Minecraft que crea mods, la cual siempre tiene una respuesta para mis problemas! + +In addition, I'd like to thank the following individuals for their contributions to the mod: + +Translations: + +- Russian: VilagVil +- Spanish and Mexican Spanish: MadWrist + +Lightning ray sound effect from OhhWowProductions \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/texts/handbook_ru_RU.txt b/src/main/resources/assets/wizardry/texts/handbook_ru_RU.txt new file mode 100644 index 00000000..81d2fcb9 --- /dev/null +++ b/src/main/resources/assets/wizardry/texts/handbook_ru_RU.txt @@ -0,0 +1,222 @@ +PAGEBREAK +LINEBREAK + + + + +Книга Волшебника + + + +от Electroblob +PAGEBREAK +Введение +------------------------------ + +ПриветÑтвую ваÑ, волшебник! Эта книга объÑÑнÑет многие ÑпоÑобы ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¼Ð°Ð³Ð¸Ð¸ и ÑпоÑобы ее иÑпользованиÑ. + +ЕÑли вы когда-нибудь потерÑете Ñту книгу, вы можете получить новую, Ñоеденив книгу Ñ Ð¼Ð°Ð³Ð¸Ñ‡ÐµÑким криÑталлом. +PAGEBREAK +Содержание +------------------------------ +PAGEBREAK +SECTION Ðачало +Ðачало +------------------------------ +Чтобы начать работу Ñ Ð¼Ð°Ð³Ð¸ÐµÐ¹, вам понадобÑÑ‚ÑÑ Ð½ÐµÑколько вещей: + +- Волшебный жезл, Ñделанный из золотого Ñамородка, палки и магичеÑкого криÑталла. + +- ЧародейÑкий Ñтол, выполненный из 3 камней, 1 блока лазурита, 2 магичеÑких криÑталлов, 2 золотых Ñамородков и 1 фиолетового ковра. + +- Книга заклинаний. Они могут быть найдены в Ñундуках, выбиты как дроп, куплены у волшебников, или вы можете Ñделать заклинание Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ‡ÐºÐ°, магичеÑкую ракету, Ñ ÐºÐ½Ð¸Ð³Ð¾Ð¹ и 4 магичеÑкими криÑталлами. + +Вам также понадобитÑÑ ÐºÑƒÑ‡Ð° магичеÑких криÑталлов, чтобы Ñнабжать ваш жезл маной. +PAGEBREAK +SECTION Мана +Мана +------------------------------ +Мана - Ñто Ñ‚Ð°Ð¹Ð½Ð°Ñ ÑнергиÑ, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð´Ð°ÐµÑ‚ волшебникам их Ñилы. Она проÑвлÑетÑÑ Ð² вÑтречающихÑÑ Ð² природе криÑталлах, которые можно обнаружить в подземных породах. Жезлы могут хранить ману, и Ñта мана направлÑетÑÑ Ð² заклинаниÑ, которые вы иÑпользуете. Различные Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ ÑтоÑÑ‚ разного количеÑтва маны, в завиÑимоÑти от того, наÑколько они Ñильны и долговечны. +Ðаведите указатель мыши на жезл, чтобы увидеть, Ñколько маны хранитÑÑ Ð² нём. +LINEBREAK +IMAGE CRYSTAL + + + + + + + + + + + МагичеÑкого + Руда КриÑталл КриÑталла +PAGEBREAK +SECTION Жезлы +Жезлы +------------------------------ +Жезл - Ñто инÑтрумент Ð´Ð»Ñ Ð¼Ð°Ñтера. С его помощью вы можете иÑпользовать любое заклинание, еÑли жезл может Ñодержать его Ñилу (Ñм. Раздел «Уровни» Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ подробного объÑÑнениÑ). Жезлов +различные варианты, но вы почти навернÑка начнете Ñ Ð¾Ñновного волшебного жезла. + +Когда вы держите палочку, в углу Ñкрана будет отображатьÑÑ Ð½ÐµÐ±Ð¾Ð»ÑŒÑˆÐ¾Ð¹ Ñкран Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð¼. Это указывает на выбранное в наÑтоÑщий момент заклинание вмеÑте Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸ÐµÐ¼, и, еÑли заклинание было иÑпользоно, кулдаун указывает времÑ, до которого заклинание может быть Ñнова иÑпользовано. +PAGEBREAK +SECTION Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ +Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ +------------------------------ +Жезл беÑполезен без заклинаний. Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð·Ð°Ð¿Ð¸ÑываютÑÑ Ð² двух формах: в книгах, которые ÑвлÑÑŽÑ‚ÑÑ Ð¿Ð¾ÑтоÑнными, и в Ñвитках, которые ÑвлÑÑŽÑ‚ÑÑ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð½Ñ‹Ð¼Ð¸. + +Книги заклинаний мало нужны Ñами по Ñебе; ВмеÑто Ñтого они иÑпользуютÑÑ Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð²Ñзки заклинаниÑ, которое они Ñодержат к жезлам. Книги заклинаний можно найти по вÑему миру, и вам не придетÑÑ Ð´Ð¾Ð»Ð³Ð¾ иÑкать их. Когда вы её найдете, вы можете навеÑти курÑор мыши на книгу заклинаний, чтобы Ñразу увидеть оÑновную информацию о заклинании. Ð’Ñ‹ также можете щелкнуть правой кнопкой мыши, ÑƒÐ´ÐµÑ€Ð¶Ð¸Ð²Ð°Ñ ÐºÐ½Ð¸Ð³Ñƒ заклинаний, чтобы прочитать более подробную информацию о заклинании. + +С другой Ñтороны, Ñвитки Ñлужат Ð´Ð»Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð¹ цели: щелчок правой кнопкой мыши в то Ð²Ñ€ÐµÐ¼Ñ ÐºÐ°Ðº удержание одной вызывает заклинание, ÑвÑзанное Ñ Ð½Ð¸Ð¼, уничтожает Ñвиток в Ñтом процеÑÑе. Как и книги заклинаний, Ñвитки можно найти по вÑему миру, но вы также можете Ñделать их Ñами, Ñоздав пуÑтой Ñвиток Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ лиÑта бумаги и нити. Затем вы можете привÑзать заклинание к Ñвитку Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ чародейÑкого Ñтола обычным ÑпоÑобом. Это приведет к тому, что количеÑтво магичеÑких криÑталлов будет равно мана-ÑтоимоÑти Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ (округлено до ближайшего к MANA_PER_CRYSTAL). + +Однако, чтобы ÑвÑзать заклинание Ñ Ñвитком, требуетÑÑ Ð·Ð½Ð°Ð½Ð¸Ðµ Ñтого заклинаниÑ, полученное только при его иÑпользовании, поÑтому еÑли вы найдете мощную книгу заклинаний, но не имеете жезла Ð´Ð»Ñ Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ, вы не можете проÑто Ñоздать Ñвиток и иÑпользовать. Тем не менее, еÑли вы найдете мощное заклинание и книгу заклинаний Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ и того же заклинаниÑ, вы можете Ñделать Ñтолько Ñвитков Ð´Ð»Ñ Ð½ÐµÐ³Ð¾, Ñколько хотите, и произнеÑти заклинание, даже не нуждаÑÑÑŒ в доÑтаточно мощной палочке. + +Свитки в оÑновном полезны, когда вам нужно иÑпользовать заклинание один или два раза в конкретном меÑте, но не хотите, чтобы он занимал Ñлот в вашем жезле. + +Однако Ñледует отметить, что Ñвитки в лучшем Ñлучае ÑвлÑÑŽÑ‚ÑÑ Ð½ÐµÑффективным методом иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ð¹. +PAGEBREAK +SECTION ЧародейÑкий Стол +ЧародейÑкий Стол +------------------------------ +ЧародейÑкий Стол - Ñто блок, похожий по внешнему виду на Ñтол зачарованиÑ, где вы можете зарÑжать, модернизировать и ÑвÑзывать Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ñ Ð²Ð°ÑˆÐ¸Ð¼ жезлом. ПроÑто помеÑтите его в любом меÑте и щелкните правой кнопкой мыши, и вы увидите интерфейÑ. +PAGEBREAK +IMAGE WORKBENCH +LINEBREAK + + + + + + + + + + + + + + ЧародейÑкий Стол +PAGEBREAK +SECTION СвÑзывание заклинаний +СвÑзывание заклинаний +------------------------------ +Чтобы привÑзать заклинание к Ñвоему жезлу, проÑто помеÑтите книгу заклинаний в один из пÑти Ñлотов вокруг ÐºÑ€Ð°Ñ Ñ€Ð°Ð±Ð¾Ñ‡ÐµÐ³Ð¾ Ñтола и жезла в центральном Ñлоте и нажмите кнопку ПринÑть. Одновременно можно ÑвÑзать до пÑти заклинаний Ñ Ð¶ÐµÐ·Ð»Ð¾Ð¼. Ð£Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°Ñ Ð¶ÐµÐ·Ð», вы можете переключатьÑÑ Ð¼ÐµÐ¶Ð´Ñƒ заклинаниÑми Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ клавиш NEXT_SPELL_KEY и PREVIOUS_SPELL_KEY (их можно изменить в наÑтройках -> управлениÑ). + +SECTION ЗарÑдка жезлов +ЗарÑди Ñвой жезл +------------------------------ +Чтобы зарÑдить Ñвой жезл, помеÑтите жезл в центральный Ñлот чародейÑкого верÑтака и помеÑтите некоторые магичеÑкие криÑталлы в Ñлот влево, а затем нажмите Применить. Каждый криÑталл Ñтоит MANA_PER_CRYSTAL маны, и жезл будет принимать только то, что ему нужно, поÑтому вы можете Ñохранить Ð·Ð°Ð¿Ð°Ñ ÐºÑ€Ð¸Ñталлов в рабочем меÑте, когда вам Ñто нужно. Однако, имейте в виду, что жезл может взÑть только целые криÑталлы, поÑтому, еÑли жезлу понадобитÑÑ, например, еще 30 маны, MANA_PER_CRYSTAL_MINUS_30 маны будет потерÑно при зарÑдке. Ð’Ñе жезлы будут брать точное количеÑтво криÑталлов Ð´Ð»Ñ Ð·Ð°Ñ€Ñдки, еÑли они пуÑты, еÑли только они не применены к улучшению хранилища. + +SECTION Улучшение Жезла +Улучши Свой Жезл +------------------------------ +Чтобы обновить жезл, вам понадобитÑÑ Ñ„Ð¾Ð»Ð¸Ð°Ð½Ñ‚ арканы ÑоответÑтвующего ÑƒÑ€Ð¾Ð²Ð½Ñ (Ñм. Раздел «Уровни») или Ñпециальное улучшение жезла. Оба они могут быть найдены как добыча или приобретены у волшебника. Чтобы обновить жезл, помеÑтите его в центральный Ñлот и помеÑтите улучшение, затем нажмите «Применить». + +Специальные ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ð¶ÐµÐ·Ð»Ð° улучшают конкретный аÑпект жезла. Каждый тип ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ ÑкладыватьÑÑ Ð´Ð¾ трех раз, и общее количеÑтво улучшений, которые может взÑть жезл, завиÑит от его уровнÑ. Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ улучшениÑ. +PAGEBREAK +SECTION Цветы И Бутылки +Цветы И Бутылки +------------------------------ +Ð’Ñ‹, вероÑтно, ÑтолкнетеÑÑŒ Ñ Ð»ÑŽÐ±Ð¾Ð¿Ñ‹Ñ‚Ð½Ñ‹Ð¼Ð¸ ÑветÑщимиÑÑ Ñ†Ð²ÐµÑ‚Ð°Ð¼Ð¸, которые Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ‚ времени раÑтут в дикой природе. Это хруÑтальные цветы, еÑтеÑтвенный иÑточник маны. Они могут быть Ñобраны и обработаны Ð´Ð»Ñ Ð¸Ð·Ð²Ð»ÐµÑ‡ÐµÐ½Ð¸Ñ Ð¼Ð°Ð½Ñ‹ в виде криÑталлов. + +Вам нужно зарÑдить жезл на ходу? Ðет проблем! Теперь можно разливать ману. ПроÑто Ñоздайте колбу маны Ñо ÑтеклÑнной бутылкой и воÑемью магичеÑкими криÑталлами и возьмите ее Ñ Ñобой. Когда вам нужно иÑпользовать его, проÑто Ñоедените его Ñвоим жезлом, и он воÑÑтановит чаÑть зарÑда. Этот процеÑÑ Ð±ÑƒÐ´ÐµÑ‚ потреблÑть бутылку. ÐÐµÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¼Ð°Ð½Ð° терÑетÑÑ Ð²Ð¾ Ð²Ñ€ÐµÐ¼Ñ Ñ€Ð¾Ð·Ð»Ð¸Ð²Ð°. +PAGEBREAK +SECTION Уровни +Уровни +------------------------------ +Жезлы и Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´ÑÑ‚ в четыре уровнÑ: BASIC_COLOURначинающийRESET_COLOUR, APPRENTICE_COLOURученикRESET_COLOUR, ADVANCED_COLOURпродвинутый RESET_COLOURи MASTER_COLOURмаÑтерRESET_COLOUR. Каждый уровень более мощный, чем поÑледний. + +BASIC_COLOURначинающий RESET_COLOURжезлы-которые могут быть Ñозданы. Они выдерживают BASIC_MAX_CHARGE мана, и может иÑпользовать только Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð´Ð»Ñ Ð½Ð°Ñ‡Ð¸Ð½Ð°ÑŽÑ‰Ð¸Ñ…. Ðачинающие Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð´Ð¾Ñтаточно проÑты, чтобы их броÑали вÑе, и они обычно не ÑтоÑÑ‚ много маны. Это не обÑзательно означает, что они беÑполезны на более выÑоких уровнÑÑ…; Их Ð½Ð¸Ð·ÐºÐ°Ñ ÑтоимоÑть делает некоторые Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð½Ð°Ñ‡Ð¸Ð½Ð°ÑŽÑ‰Ð¸Ñ… полезными даже тогда, когда у Ð²Ð°Ñ ÐµÑть доÑтуп к маÑтер-заклинаниÑм.. + +APPRENTICE_COLOURУченик RESET_COLOURжезлы Ñледующие поÑле начинающих. Они выдерживают APPRENTICE_MAX_CHARGE ману и может применÑть Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð´Ð»Ñ Ð½Ð°Ñ‡Ð¸Ð½Ð°ÑŽÑ‰Ð¸Ñ… и учеников. Ученики заклинаний немного более впечатлÑющие, чем Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð½Ð°Ñ‡Ð¸Ð½Ð°ÑŽÑ‰Ð¸Ñ…, но обычно ÑтоÑÑ‚ дороже. + +ADVANCED_COLOURПродвинутый RESET_COLOURжезлы довольно редки и гораздо мощнее. Они могут иÑпользовать вÑе заклинаниÑ, кроме маÑтер-заклинаний, и удерживать ADVANCED_MAX_CHARGE ману. РаÑширенные Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ предоÑтавлÑть ÑверхчеловечеÑкие Ñилы, такие как невидимоÑть и наноÑить урон врагам. + +MASTER_COLOURМаÑтер RESET_COLOURжезлы Ñамые могучие в мире. Они выдерживают MASTER_MAX_CHARGE ману, И может накладывать любое заклинание. МагиÑтры заклинаний очень редки, и Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ нанеÑти полный урон не только врагам, но даже Ñамому миру. ИÑпользуйте Ñ Ð¾ÑторожноÑтью. +PAGEBREAK +SECTION Стихии +Стихии +------------------------------ +Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð½Ð°Ð´Ð»ÐµÐ¶Ð°Ñ‚ к различным Ñлементам, которые опиÑывают природу Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¸ также имеют перки при иÑпользовании Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ñ‹Ð¼Ð¸ жезлами. + +FIRE_COLOURОгонь +Пожалуй, Ñамый разрушительный Ñлемент, огонь каÑаетÑÑ Ð³Ð¾Ñ€ÐµÐ½Ð¸Ñ, лавы и взрывов. Мощный пиромант развÑжет ад Ñвоим врагам и, возможно, запуÑтит мир в Ñтом процеÑÑе. БольшинÑтво заклинаний Ñ Ð¾Ð³Ð½ÐµÐ½Ð½Ð¾Ð¹ атакой поджигает цель, наноÑÑ ÐµÐ¹ поÑтоÑнный урон Ñ Ñ‚ÐµÑ‡ÐµÐ½Ð¸ÐµÐ¼ времени. Однако будьте оÑторожны, что Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¾Ð³Ð½Ñ Ð¼Ð¾Ð³ÑƒÑ‚ не влиÑть на нижних мобов. + +ICE_COLOURЛёд +Элемент льда Ñделан из вÑего, что холодно. Морозные Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ñ‡Ð°Ñто замедлÑÑŽÑ‚ врагов или замораживают их полноÑтью, и оÑобенно Ñффективны против ÑущеÑтв огнÑ. ÐœÐ°Ð³Ð¸Ñ Ð¼Ð°Ð³Ð¸Ð¸ льда может оказатьÑÑ Ñтоль же полезной и вне боÑ, как замораживание воды Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑÐµÑ‡ÐµÐ½Ð¸Ñ Ñ€ÐµÐºÐ¸. + +LIGHTNING_COLOURÐœÐ¾Ð»Ð½Ð¸Ñ +Этот Ñлемент каÑаетÑÑ Ð¼Ð¾Ð»Ð½Ð¸Ð¸, штормов и погоды. Мощный штормовой маг - Ñто Ñила, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð¹ нужно ÑчитатьÑÑ, а некоторые обладают ÑпоÑобноÑтью призывать молнию по желанию. МолниеноÑные Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ñ‡Ð°Ñто наноÑÑÑ‚ урон множеÑтву врагов Ñразу и обычно ищут Ñвою цель, Ð´ÐµÐ»Ð°Ñ Ð¸Ñ… Ñффективной атакой против любых мобов ... но оÑтерегайтеÑÑŒ криперов. + + +NECROMANCY_COLOURÐÐµÐºÑ€Ð¾Ð¼Ð°Ð½Ñ‚Ð¸Ñ +ÐÐµÐºÑ€Ð¾Ð¼Ð°Ð½Ñ‚Ð¸Ñ - Ñто Ñлемент тьмы, хаоÑа и нежити. Ðекроманты таинÑтвенны и чаÑто раÑÑматриваютÑÑ ÐºÐ°Ðº злые, Ñ…Ð¾Ñ‚Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ð¾ Ñто не так. Ð—Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð½ÐµÐºÑ€Ð¾Ð¼Ð°Ð½Ñ‚Ð¸Ð¸ обычно иÑпользуютÑÑ, чтобы призвать ÑущеÑтв, чтобы ÑражатьÑÑ Ð·Ð° Ð²Ð°Ñ Ð¸Ð»Ð¸ даже Ñгибать волю ваших врагов. + +EARTH_COLOURÐ—ÐµÐ¼Ð»Ñ +Элемент земли ÑфокуÑирован на природном мире: животных, раÑтениÑÑ…, ветре и Ñ‚. п. ÐœÐ°Ð³Ð¸Ñ Ð—ÐµÐ¼Ð»Ð¸ разнообразна и принимает Ñамые различные формы: от Ð¾Ñ‚Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð²Ñ€Ð°Ð³Ð¾Ð² до развÑÐ·Ñ‹Ð²Ð°Ð½Ð¸Ñ ÑроÑти погоды. Земные Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¿Ñ€ÐµÐ´ÑтавлÑÑŽÑ‚ Ñобой ÑмеÑÑŒ атак, защиты и полезноÑти. + +SORCERY_COLOURКолдовÑтво +ВолшебÑтво - Ñто Ñлемент Ñилы и изменениÑ. Волшебники манипулируют Ñветом, гравитацией и даже Ñамой реальноÑтью, чтобы ÑоответÑтвовать их потребноÑÑ‚Ñм. КолдовÑкие Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользоватьÑÑ, помимо вÑего прочего, Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾ÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð°Ð³Ð¸Ñ‡ÐµÑким Ñилам Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€ÐµÐ´Ð¼ÐµÑ‚Ð¾Ð² по их желанию. + +HEALING_COLOURИÑцеление +Элемент иÑÑ†ÐµÐ»ÐµÐ½Ð¸Ñ ÑвÑзан Ñ Ð·Ð°Ñ‰Ð¸Ñ‚Ð¾Ð¹ и регенерацией. Целители ÑтараютÑÑ ÐºÐ°Ðº можно больше защитить ÑÐµÐ±Ñ Ð¸ Ñвоих Ñоюзников и как таковые могут быть очень трудными противниками. Ð¥Ð¾Ñ‚Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ð¾ не иÑпользуетÑÑ Ð² качеÑтве атаки, очищающий Ñвет некоторых иÑцелÑющих заклинаний нанеÑет значительный урон нежити. ИÑцелÑющие Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð½ÐµÐ·Ð°Ð¼ÐµÐ½Ð¸Ð¼Ñ‹ в бою. + +Границы между различными Ñлементами не вÑегда различны, и некоторые Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð½ÐµÑут в Ñебе черты других Ñлементов, отличных от их ÑобÑтвенных. + +ЕÑли вам повезет, вы можете напаÑть на Ñлементарный жезл. Эти жезлы позволÑÑ‚ вам иÑпользовать Ð·Ð°ÐºÐ»Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð¾Ð³Ð¾ Ñлемента Ð´Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐµÐ¹ Ñилы, чем обычно. +PAGEBREAK +SECTION ОдеÑние Волшебника +ОдеÑние Волшебника +------------------------------ +Как волшебник, вам понадобитÑÑ Ñ‡Ñ‚Ð¾-то, чтобы защитить Ð²Ð°Ñ Ð¾Ñ‚ ÑущеÑтв, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼Ð¸ вы ÑражаетеÑÑŒ. Однако обычные доÑпехи не Ñделают Ñтого. Чтобы макÑимально иÑпользовать ваши заклинаниÑ, вам понадобÑÑ‚ÑÑ Ð¼Ð°Ð³Ð¸Ñ‡ÐµÑкие доÑпехи: шлÑпа, халаты, лоÑины и Ñапоги. Ð’ отличие от обычной брони, они не ÑломаютÑÑ. ВмеÑто Ñтого они иÑпользуют тайную Ñнергию Ð´Ð»Ñ Ð·Ð°Ñ‰Ð¸Ñ‚Ñ‹ ноÑителÑ. Это, конечно, означает, что они должны быть зарÑжены магичеÑкими криÑталлами, как и жезлы. К ÑчаÑтью, Ñти предметы одежды не потреблÑÑŽÑ‚ много маны. ЗарÑдите их, как жезл в чародейÑком Ñтоле или в колбе маны, но будьте оÑторожны - еÑли у них закончитÑÑ Ð¼Ð°Ð½Ð°, вы окажетеÑÑŒ беззащитными. + +Ð’Ñ‹ можете получить волшебную броню, ÑÐ¾Ð·Ð´Ð°Ð²Ð°Ñ ÐµÐµ из магичеÑкого шелка, получаемого при Ñоздании нитки Ñ Ð¼Ð°Ð³Ð¸Ñ‡ÐµÑким криÑталлом. + +Те волшебники, которые поÑвÑщают ÑÐµÐ±Ñ Ð¿Ñ€Ð°ÐºÑ‚Ð¸ÐºÐµ одного Ñлемента, иногда ноÑÑÑ‚ Ñпециальные одежды, которые дают бонуÑÑ‹ за Ñтот Ñлемент. Полные комплекты такой одежды очень популÑрны Ñреди маÑтеров, и их не так проÑто найти. + +Легенда говорит о тайной печати, иÑпользуемой Ñамыми могущеÑтвенными волшебниками, чтобы значительно улучшить их броню. +PAGEBREAK +SECTION Волшебники И Башни +Волшебники И Башни +------------------------------ +Ðе бойтеÑÑŒ - вы не единÑтвенный практикующий в Ñтом мире. Ð’ ваших путешеÑтвиÑÑ… вы можете вÑтретить выÑокие башни Ñ Ñ…Ð°Ñ€Ð°ÐºÑ‚ÐµÑ€Ð½Ñ‹Ð¼Ð¸ оÑтроконечными крышами. Это резиденции волшебников. Жизнь одиночеÑтва может иногда приводить в замешательÑтво магов, но они, как правило, дружелюбные люди, которые готовы поделитьÑÑ Ñ Ð²Ð°Ð¼Ð¸ Ñвоими знаниÑми, Ñ…Ð¾Ñ‚Ñ Ð¸ за определенную плату. Ожидайте оплатить драгоценные металлы и драгоценные камни, и взамен вы получите много чудеÑных загадок. ЕÑли, однако, Ñто магичеÑкое заклинание, которое вы ищете, вам нужно поговорить Ñо ÑпециалиÑтом. +PAGEBREAK +PAGEBREAK +SECTION Рецепты +Рецепты +------------------------------ +PAGEBREAK +PAGEBREAK +Рецепты +------------------------------ +PAGEBREAK +PAGEBREAK +Рецепты +------------------------------ +PAGEBREAK +PAGEBREAK +Рецепты +------------------------------ +PAGEBREAK +PAGEBREAK +Credits +------------------------------ +Electroblob's Wizardry +Version VERSION +For Minecraft 1.10.2 + +Designed, coded and textured by Electroblob + +Thanks to Minecraft Forge and MCP, without which this mod would not have been possible. + +Thanks also to the Minecraft modding community, which always has an answer to my modding problems! + +In addition, I'd like to thank the following individuals for their contributions to the mod: + +Translations: + +- Russian: VilagVil +- Spanish and Mexican Spanish: MadWrist + +Lightning ray sound effect from OhhWowProductions \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/textures/armour/invisible_armour.png b/src/main/resources/assets/wizardry/textures/armour/invisible_armour.png new file mode 100644 index 0000000000000000000000000000000000000000..892b9537a21e50551194322f4d148dfdddd39f2b GIT binary patch literal 2411 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEb}-In zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifGI0tDiOQW+7GhxF_~Gf|7*cWTZFF>w zOt|E~XGLY#cE_#XURIVIq`tIsqwH?4rN>y0iacd>-C{b$tB-}%iG?+=`N^K8i?l?( zGBPRDN1CzgeGeU%OR$eRRIUeE-%q7)5MxwP|7&b&GE z?#N>On>(0`Hw%_-~SPBH|AkpdaRnSZrhVT%fJ6y`{d7d{WA+Dvd8!Pnx!&s z?8x}r9WLvFrK)`{8kBxoBEG}l54h07RR-11t6I)a`BO}`s zST^q3*HqhS@$9)iBg4F1AJQ{cvAJG8aIit6;{lJuMV^Ms3$m;ZO=5AqJ~3Q`r9+eP z(C2^>S!3?myal{PQX;XgaaR|vIB>H1SK+H0i7m`FPLo=G%S#_G-v8b`VB$u7!Q(%E z-v01YKE}cOwpk%E6ur!z7f{w{a$Huv-o&n|H_2|0QzbWA;?RcH6t z>{BJH&G|^C2bGKr3$mV73oB1>+rY4{K3`(hvZfD8Z1=v$@sz!9op%4gr(05C##-N0 zZV5gJwfWy3UXcGkmZ9PPxtJrh@-{7BeMP0EBabL4-HMJ@WSM1Hn#p*1{eD*0a78Yq zlEV$FGBcD|Dt()my`Hd{DQa==L#9X0Bp=0pS~F_bw`GS4zkz2ywOuWK{9V@7T-izU$G2P|?%b*$fR=d%DE`|7`o} zy>vobvh8+Lmun|1Uo#%JPda};e(v_;oa@i;4GR4G;NTHgon@O}bhK@laW3i6g?6uX z{&&AB{W{j(^@_(n+M;LXM9(k1{8vraW!yMY8!UED_NKz>zkL}m?#|}9T3zu}ylqp~ z_e7!9yv%&1^Vt|uo~pJixqCxYdV^q0^xSRF7;Zc>FAo2h|1;_C%<|7)Yo2j=Y&d(& zM6_*^x1xY$fXnhHK@t0`Lhmtc`V>?e#Z|@>t-zrEn8Beb_kqWmn)6H7{B(H2(7`Rs zFu^OPA#2A)w$-I!yVo?V5QwnSnv=_TaOOnMGd(_Gd-vtnoQOIbYECMcMCT?J--A%+hz>1LO76h<-%l^E zzv)w+6LI8ImDpQdMV7AzHcgI_^Wy`cJGdF&nk^??EJepP2k9$kTaYw_ZnKc**l zt6lHaocz+4^|3np$F=PuE{CtWHi^99>*J03Zg*NkwCl6lhf?khJei)>#UTP`?aaE` z-rm|8bHFe@_|Ch7E5Z$)s0$RaI;vmV#TaDy;nSk{Io8?L<^TQ#ZDgLi*pfl|hsD{s zbZ^IXJ)_Ydz>GHnofxogYC8RePTU(_b{WZl=|H7J; z3X?qjl9f{z)fY$S$DX~RtFta8Ah_JEE{`+R=1**a;xeJH2biDvN17EL>9tf3sALRV zI_)sm)$H?C{ZH55=NE}8-WDj(@Zvk$itYN-g||Ij9AEY1*VL&V4f{X)bu%i@W))#Q z^?V;kAH$P7EL*0>ZCWeNbw-=NZjXSUxX`+joDS2vUo-mg{+xSzRbq-=}oE%x8|xn_fZs! zbSREq|2)y_?9Y$?v+lH~wspJ2{FPwXk+G$t%})B|7In4{Q(dZ~ONFOwW++qn+@Ey) z`@a-JH_80}$JS3gWB+PbU$>j%yjr%#_`b(IXW(#OWG<~h=WT;WWYNJl(b@ z`l*rMTj`TaGXG6VIozbgquHRAI)^pz#3ozmHD;2ZChxdnUG+v<-YNb|^0Vq+;i;QF z)?bMF;uZIbvFU5VJr8<*W zZ&-5I?22|Ne$$Zse1%Bu*|`gg7Kd>!cx#ZgYl`MJwg~U%9&5ffn12#W*zKHGaXsynr$PfCtOlkY;a_15#tK7f?Y;SPChwA9Mo z`W)-3Qpxq_0uTQ`?)hta!keql!@T0>SVwOw-eOUHZPDV!=)=(td#&8pT<}qxF=L~$ n!-bVEgAVu351PB~Kco2dUy3?5yjvL<7#KWV{an^LB{Ts5Xe@i@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/spectral_armour.png b/src/main/resources/assets/wizardry/textures/armour/spectral_armour.png new file mode 100644 index 0000000000000000000000000000000000000000..748577d3aeafd6b0d2bb85ad3e69fc4b061cde52 GIT binary patch literal 2024 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9;XlI}1}9?& z<7@^72F?PH$YKTtzJnmlxMO1WTLuOO_7YEDSN4ZYoB~FA)-5fI85r10JzX3_GVVQ{ z8Ql|lRrXl@>rMLU^NZUgX9&9bW=SbuS$42!D ze=d9SzN<4F-?&~;i+cNX<=2A^XHFdH6n9|W7I%QpfXC>}oZ@em)$dDR9+vA1-7@1w zBGcdfYv*pg9``!>|LyO&2P1R7o=EOpW9j{Nk@tyNz9kYu*RoR1s@=1`cjMD!cZ+`C z`MFMawzq_v-M=rretrdSw8)k4m}BnmWggU+|8-T*yRlt9ohQgMhjDJO`p0|!|1%`) zirur-f`8duLxoMa8LOA_vA|=?`_RqPgz><(&$qdw`}-?sK713EkP}wO(#F! zOA5-KW5}WC;qRAxNo1~y#!}ATzX~h+c$~Y+IOm+S-t+atd9khi7ZTUrTm4!3+gtVQ zt(=cI8eTHzKlV9zZuh?PZ`b!s4?Q4yq?T2QYo=vI!-nfOf+B&Ku;oHHsfDf;N_;1w$O@9bU%jkN}uT_4$Ir?Ont+HUh* z=U(-+H9L6JS&QA(G_7(EE$MqXEpAiZc?&1@7aB*>a(CU;dwFuQN9?-&WhFcdMQ$~2 z77H%%@b}ZVW7wtptImGJ0OMm?+EMkFV|T6&<_t@c4Gq5D~>GF072_B6F5=J46Ip_~-N5 z%4c=YViEtvyxLtZn?YyiBd!9u*{K!T8M3pTGGNB?kL%XHoTZ-{eNtMRs!-pICquIq9Y zAA~nnp4~RFEr3gurQ-ccy?8$}W9NHWiibb+tTOm>dRO1@FeY$Es1e# zS3DQ#V}3YIGU)ZB*;iJ%c>l`u_f>2;P+fm5Yw>;^hP%PbCH`MzULz~}+B76t+PpaT zbI9WocFR9Uz8%}79e!z!O^=^Y+@80)*VLCb?L6GR(e>buy|Z^{o|dY-<)YckqwHpW z@9hb5Gu$_OI*xCM?%fJMVpOfrwR~;G&X48+~U- zT3faG3H>WMn`QRqcK`QzIb~uEx8o(%JCx=aGThlvyX1}D?_ZVAF0j9`Fmerf@1AwG z?{Ir%+9wUCmBkDP{xr4*dB{G<)tt5F=GMszL&HCB&#zye(zx!x%tw#Eg`fB|*Wk@W zL&>8zbdt}$i+x~o@`2GT_x`D#{;VZw=?5+IZrB~VH{b3~@mqGgt;;zdMA!c;UTkz> z{|AN_OPp?855Lz_Y|E?2@%Y|ZPe!EO#MYnu1=;B;m-VyeyI!#qZjk=}!RN4L`}S?(#`mJ0_0@D-nYAFu zxm|JULdTqG6X*TlkZs$tyq__k#Oh0I)X|w7qAWA=PQ~Z%X)LWiwlVTr@Z_268H{)e zuL-J^E~=Vq%fE1)f0jq^(0>Bf0veV_4>r9$#V9` zUhJJ6;OOxAg^CrAW)yL7q#dEI6%Ed~T9XY?m%q-~O%q ziY!)r_6t>?trd&YYSFGgka9Noxr4yUkd4QbSS^ABV)r$D>wFx-uD_`6=hGBp;}ABs z=b`f$mK?BbKfUY8TCwWwb|r3WY9C*WH)jivyDJ?%+wk|l-}AkftgHU?omaH=^K0*% z<=rPg7c0%kk`1r2w`5x%bMnr``j3}n%Qw|MGJVFk$NPWyKCXKc(=}gqK2CWXB-{7e zyUP4W=Iz~I7rM8}-@mrO)iGeL($;_Lbv|7^`(0P+un4Fi5}9k}mAOcjx#E4b)3eN< v($AlzzL~Qk&fQh9a&_;OUwg#O{_zSdEZVgxWm^~n0|SGntDnm{r-UW|**Ueq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/spectral_armour_legs.png b/src/main/resources/assets/wizardry/textures/armour/spectral_armour_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..584f1e9c9c95936b4bdc9b3ba47c466817ebff9a GIT binary patch literal 990 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_earth.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..46ec5132632457348b85b1a2a742676b8aeb1a2d GIT binary patch literal 2803 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 ky=0fo`fjH}_fL8DFVdQ&MBb@005LV{{R30 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_earth_legs.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_earth_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..d6ef5a393d03b13ae8f01146b6fbd16e046965ad GIT binary patch literal 425 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_fire_legs.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_fire_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..369e2842af659d16a52bd8bcd6fb6a3e7a9b85c2 GIT binary patch literal 430 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9L5@L)fy4Y& z?gj=12F?PH$YKTtZeb8+WSBKaf`Ng7y~NYkmHh!DGmi=TO~DmD3=E9co-U3d8TZ~! z-SHc1wS))tw3F!~ze^~r$j8AwIu`TTdgZEUHR0g9NCr`{c;de_Q z>#3}!b4`5P?>{w98CVCUi@u4O5xlD_k*?tNh zYpI+ZXD0Libzt)5k1x`g9zEtvyuW`If0bNG)#a73=6)AvbkF6hlJl{;bmkRL!4=k< z1rsYL=fyG~$>Tb-uRi(AlIZ&kUwho!eP%PR%ByA8V7@hv@zr_0^T|*CuroZUQZ_Je z@SERj9%HiT6zi&-zt;;6%2l@Sn9cBv?SmoS?k_(thu& dzjp0l@GG4ArzG!K6axbTgQu&X%Q~loCIBX*tD^t_ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_healing.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..866fd4861571d99ccf8f40db825d3d52116fd21b GIT binary patch literal 2797 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_healing_legs.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_healing_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..6f68d17b89788761716da00b8b25ed6053b51e39 GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9L5@L)fy4Y& z?gj=12F?PH$YKTtZeb8+WSBKaf`Ng7y~NYkmHh!DGmnvu^7n6D3=E8Vo-U3d8TZ~! zH_U4`5NWGl91touVUgasW2bmuaITuCAnksVv#4uc+fDEAZB;9kDmN&lE)bqrIDwZ_ zbyLOtwEz7N|JMCWWoT01fT3$_w?#$k_U&IM?R$Ak*}>n>8*gUs{wDWoS6*#Z0RO8Xvg2*u23g;jQF@e{Z%-7uI_o&*1Ru7u&SFhnJU5$xS~ph5gEn zU;Te4{(b)VWg1h&uA|+TxA=eeZMnT*wg1}qBMmz*L>-ne{0e?9#&e7nBy RVqjok@O1TaS?83{1OU6(usr|( literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_ice.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_ice.png new file mode 100644 index 0000000000000000000000000000000000000000..3e25a69c53cb59df1927574deea7935e644c57c6 GIT binary patch literal 2781 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hETZf%`=Az^umC(qrCOrfZ4Wg(gDu`R1~S8v&xB`Dpzb%Uaq$}NANBrTsW z%quqV%PMiGt(Bd{c4^tN%d0N%PT|VT?cJo=swJB$n|-O%%Kg$2zoeY|_I7jbzpj41 zd-Gk3>|LKc0^i;HzSI2spL@^$S1Yz99_T-I{CKV8yxKLhf1H)KF>E^O6JskjQ~N_k z5689l$2uBjx4!ze%)aL9`)$AP>CWX~-|EWG&>lVKAO8U--8p{G^L6Df>|S~~HDtFb z!w$(gbHyi?SmoY1A?~3f^rVexLzSxl!-DAvI}D;21RK9y6IjB~U-R+SyS|>M2^t5c zZRMRYCv?FpsY8=GY63Su3)?#Lb)o7;i$3?jKmk6skJ~RsN^ljpcW12qd2i~Y-qI!} zeTVBl@h6I9IyfY_0yMHtJPl47s3yb^Uh@Idhs3mapIZ!06y#ODXOZRY*^<=4{W_=Jn~ z!=9FvZ$h`IK9Z2#%fRsCX{Ygp5ZSh*d0Cgv!iA|(>*8hCZ#iUaSetv2Mpu4-YHaXP3VSFwwKzx_={Pt66og6{WU zd)E98R~Lxg#`KV(y*B!K@^@R=fRGv4FSHzdE-z%7{p^6_Rg(^x?I%na7r{h{zgx0LQmlh#EZCfgl2Odfqb=*V#3-0$5V9^PR6qg^W+6yRc_@bJ|ck$(nX z6uVqmW!!ZbEc)0PR?Mp0-@=$;n8ENegV*_LNXMK8-uZt`%+_YLhRr#811N1PK)+T znZC7uC%xzPz4uk>*6(c(FJ9Z8`&hqs?QxIyg(Bs1x9>eK{_bz%+uDD%|Bgye=DI%n z8P}iVi=|S^>nnA>eAI1wo8OT5XKb2smT|+` z^H2332PN)!cc}l1oO|_sGll~nPBybKoY>TpVZy~QLFFWyo7rqv8@cw$`m@h2+Pryk z$d!f|#oF54Dq9)285q1b=`b@ax~QSz*`#y&MB3(SHrf`a!#8tYkd4bZ^3H1aZXE{^ zmTCR0&y~xYl=mJtyj1;X*ZlnVx6^F(Jtz5Acuv~zxP-ZEPF{nGXNTM338_1K`unaQ zG*ZG>TbTSn(1(UK}%!a{3SJO zXZ`z?^*2JkU+`lTz9}1?vRPDWPbiSE6?3ww6xyRqW z{eElDucH$uvx&}lx>)MdxxU{QN=mh)_##;Jdn+zcs<+3a#$ zU2p!U?~Ea_LY*w<=328eym(_0edo>JA3t`yW^%v(b{7l??wT6|+;7sCdoz=M0={nZfL_I_O|Q{T_Zr*Gw&f&wDW zCNzGEE&lm@U!>WM`W@G=>gU|Q{QPx5#B)}Li9gytz4~zX{>^uD>+kEAFDPy^N)^81 zd-vsytLxWn>XmlqtA5TH@*&0OtycQiL#|50<|Jj=QFrn2{DInQ2Y&KPE) ze^B${&wq#avau$*$$b);(D(b}6|Y5G)|_Dp5So{D?&scR%P#Ef+Uj6>$hz@`{hjO( z?Ff~93(wfBDy+*hJ@j+$as{u`Iftq(&sLhc=*8}8>6JETVhCC(lEt{<+M$(Ui&nim zqjQ&QRmG3U2?Ccpt3Eh>E?=1NYhs92=(gWy&%Rq)Xf;=ldF7%O86$zr5|P-_oFY zf(vH-u$%AFp(3O(vE%1tkC3zZ?>Deye`h?IvdQO#m*+Y6iCovY=9Qi;>A0EQ`0U%( zl;(3k&M(_DwQFG&hx1&;&ZB4Urq(#lOZ%VGeB3Ne4owRr;6ED`Y$A>c-UTBxy*{U z_0E2ilTVA*J+Aw6ME&N1*Yca(Kc5>f}Ji*+H z*8LF?*`CiKro&~>6wbUX&{rwscIIFjSg!+a|VXKGGF~YoL87;%@;12 z<)He>NV58h!FpBCCWG@9xmQk|erG0nXYG_SV@55O)&HKRU1(Sw`z?L%oM#T@|Bn5? z9S`~Cj7J9mYA!hdGv!)0;)Q%)){ QFfcH9y85}Sb4q9e0DuxMZvX%Q literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_ice_legs.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_ice_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..a62eef4e06307deb513531102ff39a1382064393 GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9L5@L)fy4Y& z?gj=12F?PH$YKTtZeb8+WSBKaf`Ng7y~NYkmHh!DGmnwd5&zr03=E8Vo-U3d8TZ~! zH_U4`5NWGl91touVUgasW2bmuaITuCAnksVv#4uc+fDEAZB;9kDmN&lE)bqrIDwZ_ zbyLOtwEz7N|JMCWWoT01fT3$_w?#$k_U&IM?R$Ak*}>n>8*gUs{wDWoS6*#Z0RO8Xvg2*u23g;jQF@e{Z%-7uI_o&*1Ru7u&SFhnJU5$xS~ph5gEn zU;Te4{(b)VWg1h&uA|+TxA=eeZMnT*wg1}qBMmz*L>-ne{0e?9#&e7nBy RVqjok@O1TaS?83{1OSK0uoM6Q literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_legs.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..5cb7de5b5100130bc4aab301f909ba9a983b8a94 GIT binary patch literal 406 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 TH8quifq}u()z4*}Q$iB}59Big literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_lightning_legs.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_lightning_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..2232d8171600a028562fd8ef9e2470899d8e856c GIT binary patch literal 429 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9L5@L)fy4Y& z?gj=12F?PH$YKTtZeb8+WSBKaf`Ng7y~NYkmHh!DGmoaY^{Fc+3=E7`o-U3d8TZ~! z--NZfmEG?OafSR literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_necromancy.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..1efbdf7bfa4e22958f101cfae8f678bf6e41b3fe GIT binary patch literal 2800 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hETFpUyQm-J-4c5Ub2WkH~0PHr~RL+Yv0${ z-R`}-OS@m>>E7?P?`qD!|5+D5JHSiOh5v}1z=;nZ&&hB`-7hW?*y`hCDrdC3)8m-R z^Lit-hh+;_?R{C!H?Ju6drpnO#SM|488~(ve)*q4=UTJ7+ZAhVwl6s~7t*ioF=p5y z+Z1c4r2YE(h3KD5>1lowqO%!48nZC0vEg~Hm#JX1p{kO_%cEu1?saz$F4S4Um-EIW zAt|gqab|~>(Umzb*KA$Oar>aE{xpS-6ECe6Jv8`Nmnjy){w{xFwmOH`B9_xzk{4=l zC>S}EI-H()Vig<11NZp5UGv}EVqC@S!nSXFvh=*aU(&8zZ=Ddzn_+o5QkeC3n_ge zdUKf>{(N~6pD3kPa+!s(RmDp|WQX28Zj)(gl?-Wd0c!@p?tLIeQ%3I@9w{)dQmUZcTSjoWYjjcxc!6yWQuuJvAuaEO9=?z%n@@(yDbr!h`Mg|D@$I>p2)c zv>z0{@#i6*&w0ribI&SCPM+YUqR{rL@XZ|owtuC9yHXv5R3oMwGVr}}(x_+|=jBZc zQe9OZZGFgeY4Yo6MuwFxOpj;stXO);z{jIVVv59$id2zlsf-ML^JE${Za3zZ-D_I* z+<{Z!Wa5cUJePw$F8r={wC(ro1WC4I#*z#Np7boN9&)hCw|7*|dUmw44#>_mGlxfqX9ULk1?uW+%ZeN=(Qeofo z4yI4v|8~~@rx&7lzI{nPynXuad+Dp5{$2OI^7$A2JYUV2+*y~8l)Ias$ga<{`SdQg zZI$oQU))zug_*OJYc~7jw4_`gWn9kdfUF#=%tbVI-sCeCm|CG#u7e;1ssCn5?XWJopM^H`!D^xW0I_rs;eQRXeh7NFYl-na+s})Fe}0{LcZbZin83Y}+`(!F=a1_=iJtj2 zC2;$ZA3T6#88dj2`4;KLQ~DptRqR~x(S;ai)GA9lrQIR{i1Jm&L`>R9LJ z5ccN5v16SR6Q}d=EJ@S#@y^}p8TUm?b@Sis4);`_vo9I`Y_Gm&`BkffXU~TtRa@5O zlruhLcUqG<_pwzlgXEi+$5++P?K`k5>$kOZysrxfGb_WZ&kthOI-mUO);ZHV$n)W& zIeSkR=WppXwLAB9iPgK`4eQ+(yUNeY>PV>JI%jtKbo>{t16dS6Y}bNqW|?%CMi8MCwJ{ri)C z^fiN8h1HceznK>QEY%nADOi8t=reIAN412#_*uz#;+H--8GmK z({dK9XvneaSROQK>M>+XPS=_e-B+tekOF7r~?_>biREChu$03@A!QaEC)$xV~e>tuon5X_~ zb3S2seflNP4HrM%lDZv*Fso=Wwr0)`}HCxbJyJl7}-#_)sR4-TEdF3L>1#|xFo8Z*39P_1x&o-Hy6Sp*9EV53-CjHKpC)U#4c>r$%A>0tbsNb+R zO`Ksz-+89whD*C<{!rvs$Y9qF*F>=(oD`_Alqf3|dI-wBEJuVD7hD zpFRB~oZlMmxIxRD<5FwZ{QrlVon9HF#(XZ9f2r5LJf?1wdRS|5-h?yvKg?3NHKmM@{dg z@$QYWcj6D6U!#!h=dkp1z{@?^eo-Br({@b%mCAYV_{`O;J11RVq8Rqh=!{X-6J~~n zxZ2l`b~~spU}bac=bo};9V$2@-X7bD|<}jb%dqgXq dH|ad9H=kC@a_(=GI|Bm)gQu&X%Q~loCIE3@F>U|= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_necromancy_legs.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_necromancy_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..e6624704479f9b0ad4ad259ca736f936c4672e44 GIT binary patch literal 431 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 VGYNZ<6ATOt44$rjF6*2UngCdOBqaa< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/armour/wizard_armour_sorcery_legs.png b/src/main/resources/assets/wizardry/textures/armour/wizard_armour_sorcery_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..2b381f5c58ebcf8e7421307568e403dd358c74fd GIT binary patch literal 416 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9L5@L)fy4Y& z?gj=12F?PH$YKTtZeb8+WSBKaf`Ng7y~NYkmHh!DGmnz>t7nNa3=E9Ao-U3d8TZ~! zKiGB1K*Tk_i_3Ylpt$2NM#qAyXaDrdo6BEW8y}#;J#k_Smr`k{r}5k+=dO6Yu-^S- zpWeOGXH{7_niODYhE&epn-4equgZB+8F!ntJ?nH-_Udo?DUo5nziiUEIfL0_*}H}( z`_-lXGN{dGd^eY!A(@9k!T0jH{+zuUTx<-l&z_qtsQ5Sb%#@(DyoxTXKTgPNPrjTY zuJ|{XZ$i*EnFU+h1RhwVK<}toI?^kR4u*#B&VPC%XhMz)qv0lOE%@xlWuWtW0r)E>Q z-Ml)BhO^TnEPQ`|`SQ5jeFyKZs`xwd!x>CIoA3)z3HoXn*hU&+M4 Pz`)??>gTe~DWM4ft7oK? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/blocks/Thumbs.db b/src/main/resources/assets/wizardry/textures/blocks/Thumbs.db new file mode 100644 index 0000000000000000000000000000000000000000..412f690c1a2ebb0f79cfc8ee2fccbfcbb1515463 GIT binary patch literal 7680 zcmca`Uhu)fjZzO8(10BSGsD0CoD6J8;*1Oo3?K{^5@29pg7W|U|NkE>#=yYve-sR< z5cvE5|9=h!1_n?ZvM?|(ure@!X|3>FMY49N`13Y7ewPwh9SHZRCqBk zFu?3jWH4ti2is}DV9sE|kjh}fV8CF)V98*{V8D=sp&uro#lQsjKe6_M@|8B4{izJ* z48{z}3@Hq$;1Dqfy9^{|$Y2Vy3=6Hnz{ChDlR^2GSo?)R`57Dukn$Yl6c85_h9Gl5 zWj-kXgUSUV1_lQ7{Ljb0z`)PIz#zcDz#s@M4-^;}7(h`f%D})N#=yWJ&cMJR!N9;E z$-uxM#lXNI&A`AQ!@$5G%fP@O$H2fK57h@Mca#_y7?c?p7*rS-7*rV;7}OXT7}OaU z7&I6d7&I9e7_^{jbr={JbQu^J^cWZz^cff!3>X*~48d{8z+lY4z+eJZXU4$5V9vk* zPC1qg3=CEb3=Gx`3=B353=Fmm3=DP*3=H-R3=9qo3=ED83=B>T3=GZ;3=A#|3=FOe z3=D1z3=HlJ3=AF&3=EzO3=Ccj3=G~33=BRD3=F;u3=Dn@3=IBIyFg(+lrbodKyly8 z1gX2ro!Yki4$S%38Q|y6%OwShdR|Wtmmp|#3vhrEhy3UNiJ-c_ILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*nR~i8hFJK&owz&iii1S!{*A}8->c?Kx@*d*p&=ls#KP<3 z;o-7HVdH7U*Kb zUBG6;PZL{ z%Zw$*KX_C`9I^_{4Dd)_F->MoqnfYMoQ*9X+fI9BPYS!e{7I#Z+wzZB%;w1@J$&r% zv7aTZHYxPpp+gR5*acWME>B-8p}sD#C@bZL$eOn?1w2bd`pl+C$8TKZ@p#w$g*q=M z=^i?4_ptF0Pfq3}CBI8CQ-U07IxdT>Wj1;$aJ*>yVq=-@9*(?)U2Ib=XEZCR6&($9 z)0jUkOX#?oPt2C=#G8ig)iYfLn@u_m(;S3ui@5V_Qw^NbE@$sll&n4}?Z)A0vvh=y zCr|VWjM{MkmVSgmg$M%!L$+ybR*mJU7nG(S#=VgAvvkr~ZI?iaWAm%ik6kdeYu{mf zDC3hTx0;TJrjnPZ;3*Yt>;H{YgEnnQSeSDo!t*C{8>_S;=W4@GhHS}cGYpSC*zvq* z`QtLrpI2Y*S^m9p{^vRGo~rHM<sbLil^bL)-8#tt!-MNG?L^Cr0O*V!^P{Pgaoq(d_|8D6{4 zy~B{r{{>e}@_h-xAl99p?N^(#RtTCdbU7sWVatO2wEJsC=dO+1o8z#M>1o-n&7N0m zujwQnaANK1kiF(~xxx3tZ3EZK4Tp}U2(R>%*pPp@Ywet?d+Y1n@=7!3b%Yr!?ew29 z%kt0Vev=@3j!z%@vgeEM+T``QW${|}o0*X-)^a2k+w(#Qr`6<*b#g@GO#e12C zy(aug^BQ`;+J0a^>NX|nw7}Fm^M9)R6yuUjnC@g?+apow9J;up-9$6+_m;^^QiN6> zUA%OIkT&-_|EK&V{9BWLzYtnhEgSc~`3FNn+Qn_h-Kq|NYAjDzKbLh*2~8k227bkV zI^`kXvZ~G%B{PfmYWuUFzqR;QhNn8$jb!CZr5xXu7Y9mpZwzB`zq}%ve_pD#?_~Li zsg^$Ld-QakXS;v>3`>8Xq2*V=C7*?EaZhhhn*NyPLeigWuy>KLp-4{cv*(h>HwsVQ zzI63NbOdmKV%O?0dJ`|Im#!F;Zx0uWRvH5hp1_S0Z4Kwc@&2RRa$S3=*&Aa3Jd%O07S24pe@NrOA)&iv>@S6y1D{TiFuXC*f6;UE504r0 zRk;3(U*bO@&N7>&?YC%SNlKB#rw=pQ~au@bzZ^g zp?YwpTj_+w&t<1OYO*GatZePzT5qVhSmStZy7nuDjaGYIL+>86n`e+MeEvjX&y`0T zLCoi-qduk_Wli4a3@RBl|9rG_*Kyp+bn0BBvGCWnL#!MsDM|~EwB(bJ7)ITr#q{t@I zCJ^FbJ>_-&glkzTH_I2Kq%Y(3+1*~b0;rX__|*Is2BJWBX7Pj!R#mA0}4{3Q;P zL_Ll+w7eBwbJJF=V4B^6e6`6JI={F&t@n{Eal3f6qs;yMhToU`m%OUdS`%>QC8MX7 zQhQwK#nP^>-HF^st=WB(1ZovbuFDkJPucP@e#cSn8#lG5JpVpt|HRX>Vz1>t-VZo! z`Q!7#mFtrx$a9|QGr22zowG;efHgWbysREC_mxNUmyke@XeIaH!IXXeqJh~RR463zz^1hTQBZQx;QQbX(Ga8 zSpJKJ=09hH4QZa+wOuLBf9#O_R~mFMOE^%(_UsfDt3sdLSqmoXZ8G!~*JFw8xc1`E z1dgDI98D4CN?j4VCO%U8DSf@^L6AT!tLjz-7jIK#$K~B+uTng+Og27WmM@WA^}y); z+1=mw6`!k3p6ZqQpi-{sLaFS>ikNG?Zp=4x#QGj5gv5F1`dt3vEGoP)!e`%~;B|1o5Hp&ck$IM&oeRSeq^(C|4?N<_UMz1*Yoop!DfP-Z_YWhn)xgZs)*5euyuRW zui5hdFRK5`boj8W*+K2MW4+UxH5yvE{N3C;3ja2$6#CyiT5W7mzUzT^vSDP_)1sYO z5^THf>gCz(Z3#Z6SR;4)P}rHaN~6Z!t-gjux4t~6lU>k#KcP-(qQmB!GF}r_ml=Ag zJF;a-aizFr{H)nm_5GZw#IEjN?A$Yb*w(%Fa{>VIawPsz}#h4p_-!99;u21^D@hE#?$24e;@a8D$SA(>GB zgXI2?A_D_MDYU%+vp)k|5*Z8`%o$7>Ou_E3WH17yMyyzifr$}h6sTDW zYKLQ0geIuXz`&3T(gf~1K>D9448{zm3`Pto3@Hp|3}y_;43-RO;69)MLmId@fo2Gl zOHTg})SsIVaxl~kN-2=PVVG32KC2c8nLIyK!})rvsOO`&i~N3y7Dc+#PlwKQ5caIh z{i^)y@4o&1%P%|4bUhlKZYVgbWwZ9gFPV=l+&9KM73}};!fee6tG-IXoEx$)ZpRxe z&#Xv`JZyOBNQ#l>vDjLpcID>7KX%@nc)NP9Tvq=5#Bb+07yRQrAAdE$a{q-FB?qML zAK81FuV!6K)!HeGK2@mc2eLX|&X8~x71mj@@?a9f5AOFGLW}PS{Yn6N3`=^ z@!4smknsOt1Eu8;<9|r`(;DQPEgUFf`_{u~hQ$(-vmTROSq)t@V?7p#Tx8LS*jgfb z#K~OD@s_V(?6fE6U$}|C+x603qs^n!EO+T#*CQFn)y}dn=A8WP&aYz;!8QfP@1M@C zzQ6PNzQ!E0+qq`5U$`m=IB1AWDqR`kWFzOkHOkfg-hwEX#ew=EMuI$SPf!1^xRznk zaz4RPGhk&%fZlY~W0#g~Pc!I@*GjOd+|d;M_;Sz`*CniB&lfUr&sx@b^ry+a`X4P$ zA79&l>fFyIu;-;sz{$u9^Bu#&ghKPTzqdJj=CQleqj|OWcN;dJd>tH@?X%2Fck;<6 zJck<|Tg>oScW8b8A=z__*VP}sAS%3dud|`iuVj&JX^R(cb*!_HX-kb{l#^4 zN7gJUt`N7F2j>s{G5PkLtK#=MCFA8Tt~Y_AJxl!#`jh)E$?+wjOM zuk+rpZHp>wCQo0{v>?-@XW=AHwM$p-r7&2qX>|(koyjJA97nnX34<^!{k22$^C`QD zHdpuhJ;0LwK*J3R;QsTXxpgfB`p;~Jp!ApF{5B#wLnc(>-?KAk-kpitl=2)p1){ic9l51d(B?Y1;^EU2gyZEE_q@M=`k zvTbMA9`iN3nNn`N+xq)s`^~#I+-*~sIc3uge!pjLX8vsd`R{Z5K4C`2j|Uez+vuJ? z5zW7#`0?H!IlqqontSx)h131XHnW%Bv{?1|@(F%h&h1g3-p_m_)uP0ccGR_}|7UiX z2IB{ggcltito6R)&KxgAeO_i4e7(K6(W2w)>rEez?5jO~-=dgp;oo2VBgG>A?#fAdWZ5&CB3s(!W$>r z>)$nydZDJY(n-R;pSQVKa9Yj*G0|TF(z`M*$KQ%gWm&iOu&G3dIsda)0Yah$?hST# zS=BthZfA9WAoAncV)IJ>a{gzl1LsJ{Fvg$w{aX6{?Pu}Q85WKm>Vi#^Ktnyh>UFZ8>-kkZQIsWN=JUs>k7b3)>jWhFj;|K%z0 zHOg*y{lQSK*Y)pC_kB|OA8VH~&z9uMDQQa%@NvvxlKXY->yO2aN1gUp)*b%5>TUZr{>!Z8x*e-n z*|mC2Y8P~NtZ1Cgx71sxPrHFL@9j^~16>ven%y^S{C#h$rBKv+Q|rUc5n>9n3Qtvb zEn4NcwJ|v3RGn1^(^b(&+5&}f>&_<2THeoGwD#Kl4K-_KFwc4@m@^?qZNEfBXQO7w zFVU=4u8qlxtCq4!=wHZdKgcR6s?Nr}`r!@F9WftI&TgIB*%bY#;TcCnR}FK}iPs83 zZ*5x5RaSH{dUH<}R_U0d)TmjfD57$!G(^$U>`>OOJXxOYM;PU19o}Q9B-R{xD&T;A zL#XPGKF&(f(1t!E%Oj1i+cJ*xPC0uupe0gclAo(VU&iyVyGji}PAjh7xFP>f-rng^ z#zDWi)(dAWsq*1%3SFWq9p<^@k$dwu+aqb&Y%GooxD+Ehmg!#)pVlv0c;LnT$^SAI zIBxiQ%i;6qWttP&b}$8~m(G!tc&gOH+Bii)aQT!CbEDSnR+(UPH*2@vQif92RlM8Y z-sfsLVD;ejX8F(WN;Rh#i`G;Wy|Cw87+$uAA+E^KbnembJMT|8A9#DS#u-ydv6Gn- zPZUnPwLmfWUa`hTu9fn#N?T8CST2(*ZqoWr%;3{y_3h#8F?(wGI;*!WFyAZse(%0} z>MtgK=P>8bKfC+;orBLW?yfa8dmqu;sU3N$lB;yJmuOszlsfML4G|XBAn}QOfznI5 z@?U-ycqzGFts?r_O9sb9Ke-e(FzbD7y|_QGAk0 zW{p>Y1TJ!{`3tkW!t9D`TF|ftChhLa(_gf z#Z4=o_vtdv&hp=$knux5XKK~QGmY&Vt94`jviNCv7JLz^_AB!hbR=AYV%lv~nNp*3Dmo?6ckd*aTlHI)G{W6cW85`zQ zt~zC6t`xA#W6hS0dpG<&5V=m&Bc-KlgQe~%HIYxN_C8n?u`1|%sX*Y~#hEODGlhBr z%pR4f=qj4eb9}ar=hn@6x=W9yTGhEdc`_+#&)v6?0lN3zee+RUtJ@yh!XmpV%W=Wy z?OPWdGV&~)aO=w#i(*xaO&o_gCrczIEb1+4Ji_lep=^7)K{U8PFQ5zxQZ! s#z)`T&zUlR-p;LOFE3#KpU&`~X=Uus=gbn$FF@6jC%!QkkOCM608E6CRR910 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/blocks/arcane_workbench_bottom.png b/src/main/resources/assets/wizardry/textures/blocks/arcane_workbench_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..0271489e1ba007b050489d976ba6dd76bb3b8927 GIT binary patch literal 754 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`&N| z?e4A%wKhqg@J*o z$kW9!#Nu@5o>Lw+Ecu7CHzu^CIc!jv zsZz2$I5zbAbsesb52vQRQT}~7{qx=L_E~fL7+k8G<2ei0)B^@KmL?C z_2E2Qty_1bRkCaLp>Lf|{tu-TH*I2;;$B(lx{}TC>wondlMfy<&SIF$w5n@iqgF&Q zzo?Jti_DYe&*xuE+OYHZ$-oKk9CE`HwscsnF;kF@{xA5LXBy{oqulzxOdZFso7gB%UOdgCIP%4L{}p0c zUo$x8Jd(Eh?C?Cz@37?SZhNr<@19+5;$%*pp};reOUndL_infDq>rCI%r7`5AvHZB zzW%_`7a6zXPo%lde0OqrQ-|Yb*Q*n}k6Nv$*dS~fI!8L-@&sd#$5WQQ{g}4wrLddy zrDFdsT@j6ij;j`%ObdvL(e5}qhmVVG$uu7?Vb$ngn_H%u&fqIIZ4%EhTvFNZE4(UI z(n$32sYM4b?{Pb0YyRxtE&MzrSsQ#-h*}vB&SuW9HUu@4T*4I3Te~5j4 z_m}_I$LCuvnBAZ7Eql&?&W2+)y83IQbM8F8CH{Nvqv;HPco~2DtvlK6n!v!oz~JfX K=d#Wzp$PzdT~yZq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/blocks/arcane_workbench_side.png b/src/main/resources/assets/wizardry/textures/blocks/arcane_workbench_side.png new file mode 100644 index 0000000000000000000000000000000000000000..49ddaf0a44773ca13e094e3f9a08c745ec3c0a34 GIT binary patch literal 694 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 GGywqW0wOp7 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/blocks/meteor.png b/src/main/resources/assets/wizardry/textures/blocks/meteor.png new file mode 100644 index 0000000000000000000000000000000000000000..53b1f199bcf318ce279465a8b2bae272e1288e27 GIT binary patch literal 937 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^RB~ux9yca|Q+m z&H|6fVg?3oVGw3ym^DX&fq{X&#M9T6{Q(!7fGFe3`^{?^7?{mGT^vI!PODzH>php1 z;rPe*pR4A5{xs+LoO7$KU$NYs$+}JLs#DjMpxX;(L{FTl>Y9<%(Q~RRmqS-Pr}#;P ze#u5p6Ny0a(!l0judQAz(pWT`*DLw#^s~kD=FWY*zT2+;P`d)h6RUOKL~L@;Ev(IS zkIjs?>Z~f>wrh5`)R~=^EJOT`U!A;dN%AzevZYt=Pnymda6-J}@uPf(8EZ~Gn7Enm zzW=qGXG_=ZiF>?JSWv1{r1W%KNb|E(QuaN6nj>$n3b=hs;Wo#?#zpTpZQJLWYJKQ~ zx}aX~wVU-)by4dd-`VA8xrtY7PL&{=K11sD3k$b7%yL~nO(&CaZ?MxW=f{;xSWQAr zw(P$-{hpImcigS1LD!s~&ee6|_Aq{N*3bF7c#xEy>(cKRBMwgJTco_!X{h+AbzB=T7~*+Y|KnyBf#4&(bXyEew^Pe7aq3QE}-(e?ZQo4Vf+$e@dt7t2-~# zx11x-yRb@HdAe8DdcmU9U2L4(t9WlT9G)NjN3(lHW>U4B{rWt?BR0SO&eqwV_VG{V z?ESLhza0V|C)M{(xA)zU6{h(^&ik)o`BGWE{?;3k53)`)%OB?R*70}#-*j?)oBIQC zhx7|Br~d~!Yx?V+T=DBt+m?=b+BaYMM9g}_v&3~t{{@GO0ZNZfY?Mhgj+|NTZ}BJM zywQh+2g}`^K5VGF>(cEdhhN{=AF4BHo2S|{ z;d?ipY!;VVGn;qWImc$LYw_VXCznK4RdJU&EGe3OujOF)XSFpZ8*HyTZ`C?`QQ&+d z^J%%CQ_dc3-oD^B-x`LvrkO`|SKT(dzbCLg+u)zxnw^$A%pboz*`#}Rv3illbM-C8 zud}t9x3s90MN8>OUXuJ$p}CO#Q{mpA9_- v(tTob@15uIfap6xcGJVZ+sbAYU96Y>R?7a3Yo`#J{OCKp6W)Y*lY#{2HDJzh!W@g+}zZ>60m;f zqSVBa)D(sC%#sWRcTeAd6une-1_s7Co-U3d7N_S1d3!S@irCKgle)QEX6~j>>{~Pz zomjT<;+9OMDuEuw8Am+6ERSK$kmP;FMKT=+qab(wO{&$w& zYrfw({K5OIMBOUuoy`gs6ZD0+WKARDPa7KF@_RYA_?u|C8oqAmpL?_OZ=a!iLL2yl0%=d{aO(K~YRGQue-G7m*!p5+%!DVacdyn+> z5)3S%`l-g#->6$&d%sYkJ@F+m#? NgPyK_F6*2UngC?X>frzY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/blocks/spectral_block.png b/src/main/resources/assets/wizardry/textures/blocks/spectral_block.png new file mode 100644 index 0000000000000000000000000000000000000000..e9abbcfacd5ee92d365e68ccf831a6b4e2271df0 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^KHd;Bw||9~l@J zI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_6JN7!W z1r9u1AAHO9#)6C^zL#994z2#mI>)k7@cbiwz*zc zk(_Z$M7?iPR* zOZ?V*J1$Pzx$<4t#8{JD&Y4qZZtSboO?GxR`8qf1l`{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/blocks/transportation_stone.png b/src/main/resources/assets/wizardry/textures/blocks/transportation_stone.png new file mode 100644 index 0000000000000000000000000000000000000000..f3a1aa7593df8792cdf703eb8e0b9d651c557f6f GIT binary patch literal 756 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^PI=7BDDqinZA@ zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL-|xr9a7R247IdCtJV)adEr7-DfcbyB3i zaH2%(e82Qv7g@Oi7YI&0vf)^ZTT;G9eQWtY=0L;1Kr=^g&UzMc=1a<<(2u_c5OMe=Snh_DJXKAD1Ng_KQpD z*hplmm{qel9II^HV>(MM*2=xmyXBa*hx%oQhE01t{y+aF_3_3VLH>-x&o(oC_;OiU zWo1IL!ll-;uUHN|{>bpa#OBEKa~)^p1iNJz0xpCy6s?pFTUK`TX6kCbhM=8G7EEOb zIBj0CZ;yAulHR0q0*~zGzkHKd#M!8IAjys6ri{^Q;olyWtuLO)F+^FOzU9MoPUN!X z)E!I?c{_qPUOO6l@L~J2vmaYU7#_|%zFmR)utRdg)9=wIUTtNw*zok#kFUR&)>yTL zEPHZk!xPa(!MmSqWh$HQld-4yO{!SK>qDjw*WW#{ti)R`ce980g4WX|zxK13iTg7a zm~))Cs*Abp1W6g4JH;RL<^1$CJAvswXdb68KU+E4}#Rln1w?CSSeie5ly=zd}`w zT~(avZ02lZ&R@q_PMn#~bHS&i>UhqYlM8-1gocKxeKVY*wD2R}CpSNiv$9FsZ@Mtm zneWwSGM#;*wMpaHWUt0)?q)1&+#aSd9PIz@`fVzoi~9EuS-ues`xiWByjYtOxR8N? Ofx*+&&t;ucLK6VLrc-SI literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/Thumbs.db b/src/main/resources/assets/wizardry/textures/entity/Thumbs.db new file mode 100644 index 0000000000000000000000000000000000000000..40dce7916ba82093f981519094b2ada6086a6e5f GIT binary patch literal 71168 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 z%0A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

    w^PXOMwWc=f-JZICoLBU1`i`wij<%idb6K(C zWiwOj^}oe0#bPh#M0z_lUZ3Uac>MiBp1FEFH|u1|{_lEvYk%MC^>@1p{#zaElRgl6 z*zQ-|_Y0id*{&QZvOUZl*IvH&+rV?<8%uW+4?~rp%M;632eyen?>lVxbKRZgbmLyv z4K_EJ7MzUvbAc%{-}wBxW1GTQFGI z?cGfIJB%9p_ht$UDBjwycWAQlJ9p7>3Q!YriuUJ&)0aIv zCtvYUl40B5yBl4+U*7wEhTCDogy&0^|6@Fm*4(DZ!u|T*-y7KqPrj{ZezE=Xi3=Ls z-_|=ft$(ckS6pCMZVj{0w1U%f-?NLl{=Tj$5_U&iYfiyq-TB3Lw=zrCovUvA)PHwR z?9=x>K@qPP2HWO|)J1!o{ucL9FX&H=<)VA`j;H;cTYqj^W7^%+cmHzwi_Zr;o}T+V zJ7aUb?04Cn6PCV-KmItq=1kDH^^boFuHQW6@9T=UzcO`F|6ASL_d9Odrg~Z9<-Mtz zzpoqq{^}iZ>R+kOpD+9%X(=&z=h=T>Gkn<8TzE%wb-ux#JU1pW#=Vi;(^#Ul&DeX- z{O_zz=ls6@@e4Runp(uX$gnwH!izumeJTry(_(!5FXG6A)34v2bFepBvzR47!s^eWxsBV@Z%D4F_F#DX zlW9wHVU0WAzSO6^asN%*`1bodu_vsa+j!^Z=T{PCTc3#-1s&M-`t#Q1Gj`|Ax-#jI zSZn_|>r=PmDtG5eefi_8w|@Jrq>qaq?K5kiU;f1U<*jGAua8V#I^}lYy=|ps5_LJ% zxAokf6n6^zjI;8JzqNPn$=h+Zv4&rwkGC_-Zr}TVn?rrm%L702nN{-F%#&Ym`Q};2 z+waWg_%mcK;F=-&i{aj(cYJ%Q1bKJ<`s(vkWK*t1S@kKq>NwfrRi@h;yh~6!ty$8k zJGCs9oL#t3$j!dP`L%5A!qmI}zHR%HmtXw>+(l9CVqL-g{^GVzkxUW162|)!-&9IZ zpR{_Tu&UWQ54qS^Ts~sZPnH!dun)x%2g(C zF6b`&=*+!j@y43)!}|&&Q&}ePR=-^Fd_7n7^9~uMyQjA^NLjzQdV4d&t<7Rww;~vB znmPA93+Q8Am=k$mJ4-_1#w?Bn6BQViYlc|0iyfEAtznqSckF8?Uk$@q*&hr^xit(E zSrsb7JZtBDO=xF`?KRE)%bLx)CT5Bl&!t(%GADkw?K;w3_3+R2!q|^u3j61s_|>t7 zdHsyD|p9-V7a@(rQ?)=8U1M63y9Ns!LEKHe$&NS#^fnzoY9LTDLOj>=G#BNJ!*7z{mJT;J_iF z1H0IyxpFqT2{!PCytKNJo|~x4z|Gxl%9eMv)PC?$kWg<&1b5 zFZ%!Ytt;!MxnGl?JWt|w!0xc0*N+Ay++KH$i8~?kS#N9Zm+V`gH{_Ox3N+*%5G$+L z_)cJ7Eq6lVM!v&B4&sN|nEqO{Gi1LmI3m>03U(1!_Njdh3F0gpH?VAo+OTX7+m;O* zf)9l;pOcT`SnxBtWP9j|UC+KvEz1ivGoP$)^SI6*)VB^MFvpQ7ayAhBA(XjWu0L zvL-RFIkwm_beA&xWJ#EMk7+|bDUhTbmmtdsR z3zf`OS({{^h6|pI;7(X-`+4gHrWuc?JW}iG^w#{Lc_$)pYWc^_jg2$D^H&DE>$}T; zK68OW82?8pF*Du7*>SxF%DhwUa#qAHS+k36LhHI?ze+8qIN$on*rDp*eT_xn`!A&_ zp(l^(yZWw)TYMSff78JilZoIbvc;hRtj3>XCKd*mbo9#UF?bGe2@;}xxtuUJYM|{B@>7DA2OdcPp*|I>yGlYY$ zgK=}6l;-(qmd1R?zsqj1jC(BmS%quqz1QszOmr0@<9(xMcbHdR(7NGbebHn3)bi9R z8`som@9z1wFI)WD^0xwwvTl(rb`6#L?+CYNB?Y;f-Rp^ta@e*Y-gLQ5e45;U<7Fy= zulaXvQTcar<&i3V7w%0SwLNbZ3H{j>l3TXAP<5k!d(tnRBX6U5@6IlGYOqb71U#K)GZnpFWUY1`Aof$5sU0JzwWd&zz z;rx>qg+LvL+F$;CEg3E>A6eSv28Vm)+sex8fTkUUM8+&a>FgZ*H@do!jp4 z--qXG6vtalyK#VL*%ke=eS3H4eV)8J=-s3418Z6DFX+|0qQCBRUR_;b&b1l4a{j*# z-t?p9PKu0uB)6+%&ujg~je7pdaZ!uES+5kBs~K&*B0covp`t6|vX{=8M*0bD+;HME z;|}Hd3>wcjIeR{SxWt>mfc5N*QznzTl0P^&WLHnj)pEajCH2=l-n$-0_x+R(x;CTh z?Cw2!m$Q9NU75qKDQ|w0q2j@>xgj%_Y6jeX{fvFeZAsNBPXp4HPv*LP@%y&_;s0*j zjqftn-!GRr`P#PY+xZ;3FEBBjDt#iq`pKkr#t$t;J98y=`O2&{exMe3-goExJ7M$h zec`{@tNDDdXX(AL;|eRQmTVDQsm(Df(wXa()Q8|qpM~?U&zOGg#8P42kPO*9m%?^h z1+Uw3a`yU!G|BJJw8P!GZd^2d>mYXP#O5v4)~B))FLJ6sI211*bM$Ec6ysMuA(ujn zKCV^bOWpXq?eRD71g)SIlUJS3sWEey`1>TwhdaOCG(7H3ijQxGfhZCs~~eIn$9@5gs;Dt&ct>rKuK z=Ekrt)(Kw^EuYEuId-R{xrFZPxXHGui+&io#JI==ZCrm$k<~Y2V)wP_ZGZdtj~zc! z^QXx~h>^UMl;+H)C%u3qhs=39IP3_IeSwb1HLYMr)OWCq3DzjG! z-Bvuj%a0-S-3ia9|5Vjmr)3zvn#!>3nEi`QLeF~zkG^Y9ezhrjPM1Q4v!aP8i*uuY z{`${#Rc^7n-ULMibn0oi&lXq~e4GkIy5eKz~EY>`#|?Bt-2Kc_#+`D6O-m+9&Ro_(i|A6p%8?deDH zH78ylPL0jKem;S@@!H*w^)HwoWN(_uWD>_1aJ15Vs&S#lyZ=`o-Tv z@@5>n)p&Jd+5h0|8%+w?i$xO}_U+jCRX~X0>7TdXukuLxZ(GLlezn)0ovA-cT}yAy zpCh@4iRHwx3$Cd@?uS0o*IRq~%Mb6^vdzK48)t4`Hs`-DSI(job- z&8|uBUaty!Q(h3U=CDDi)u;I>d*+AD6r6ne@991Vq4;T*llj-4d}ky1el_pM^zUoE z!~49BK9B9xoE`q8&T^aH=7aJdo|Ui9*4w*9@9y72AxQ^cgd}}b^|)E%lf|ep<4{#c z>TQ#4HLBmOE%M*by67Py-M9)uV(%3_fSoXZ~C@cby|+V#N)@_FXZYnv~!+U9DURCyG+RHW1NRLkNoI( zoVe)ohmL)Ze@J{hRMTY`C(!ob$@A|9ef&aquD{wPymafj!!6f8z3$m3EqujYFFs;_ zM#Q@Bd#in?sNI@$zvYvao!g?KElX>bKaJ^WH{=TZ>2~=1i^vKI_vYV4-2Z)aqy3nE zT~snUc$<&+mho9@DLWnidws7WwRIU{*0O6{pSWD9j>jmq;_K3@{}jU;`d1yF^k!Q6 z1KpC3;yYeU$~je8JZBaEq_qb{&K#bicff-;F4pbi!R2h7;hj@#jq3QXF1+m8=4Wp7 z#4=p%-Rx`E_=Q6jmp4fLoBG}~viDzCi~d;=*QVdm|7{#AA9}lHma6J3DlH57bSnSy zLbpvGv#nGnIiB#GH#zi>(``<5p|gK8S9-~-Oo{Qxot{$IZb2NxoLNVvf zPv4MFP7j%FFUV9rS>3C!g3U`K_qy%0zWrHpnispKC>_n4=%}1^p=MUcl$b!_nxv>H zTT2c0ZwtB9DCHHB8Lf7?!zB9do3#fv97vk`ow4Af@>8o%{h=|RzH9A#5*Bdk>-y!7 z(w{w0zvnFc{(*T-;GyRFFne#`wCCJeM!WxPZ1D`gwq*Oht~0+c{ONQ5WxIb_<$?R& zbDsCPN$)@S-1_RVe>$=Mo8%&HZwXsC_0m=iXBWOkBUT&5O5?;R5hbOLIiEaUSATka zZoS3wD@wU09?>T>;sX>_q@%Q}T#|0xy4C4&=Icw#unT6}sx;PXG_{@AIJJIf^ydk@ zo(lgzd_JeEb89oh0x!LtyXFM8voOc*-*9SwO3=(IK zNakJOx3&CE>;%^L#^Qgq8q-{E^6fcVd?Bt_({SsBH@tJ>6fPPh9J)7eRn-i$F1<>x zb&Dj2{_RqS320slM>e%h6AaoW2mSA&Vlai7_~SMJ@lW#^KK zh6{u$`J3Ww=QFFs@89~@Vp*Am^DW7P*&YUK*R^h%`F^68K}d#e&jf?y6m5=0b=mPw z+Cm%Gf6;+~Fzcr8{|)N+pXz1;%8_m(Td-rFuwn{M~>1nbVv?EUi>^UwX! zYiILhbO%H zwch!;`nv7f|9k3I{VTpRCFYj&cAH7o^~I0=T0K7Z`^($i@6RsXTm1jXou9w^?=F(J ztD9W+<4Nz%E&cO%nw9_i*_~W+?R5ByHQ{=vm!7TrJL%5PIotoQDgIx+ukQD|%AH$& z8n-_`Cw~6dUcG;xOxDh-_0r2dS+4%%oV1wy+TN?~nZa)b*Url}t6fkv^WZ@S$M0MB zF?26=+SSCOB!A#Yt#Q^Trn0_jCDre8L5rWT{$_DBb5uC@u>9-9_VzQ^VixqaG@2zY zIM4XlZ2IzZwc)*6SYDk?Tk;6D7GMj@tsieJi_$9-zpR#;n%*PM_M9d4ZPB@XpVk)! zn~48Vc09nV#_{Rqzaz>|-|l{Y)#IK9gXW~-)6IU9`RD)HEw$Wrn*$%~JiJw># zu6KP~qwmFw>9@6?-Y!3XS;0b+i{(;`<H~f{J-*?=eGv)JnS%bV{#vA`S4 z0=%*%yXS0P&+x`3r(oSbS%2#YrRRUYsmp0H+?FfPdH3s@`@AWu>rXfP2{)YO|KS{B zGy6@kpMaCXhKujSIUN4q)jMG`oIp|lvg|7XYDIh@as0+@chKwr>%kOv(|k-*ZPBP z@0)e$>|zYLPJN5#*==BWckzHy1}9_Rr@X>~6h;jtUB%rkPxH6@{`u*s_Vm?TvKcjM zx9v@uDdtd`!MMfBNn33L1K;%*a)x#rC$QAiPmnS`JE`HQ)C1-lm#=qLr$+a>zqbPA zmW-1|H4O3FzcJ4Fm-(*dRHXc?DVy(KUMc&7VczZ^@m94@vO#$wx`rWn+4dg{>uRIo zrL9B%Uv17vH=gbu*9~f)CJh@+-IseIThPYi`>3<({{e3j`^z>KE zKi=K7-};(4LgW|2s?W6y_n-Y_5R(O^^Q_>v5AT0xOi`9UpzxY`13GviCA0PBSFVC9 z4X?kfV7$Jy$Vb-v!}_W_X5lXjZ^umawy)bQcKl|iz5G(=GO4A`br&BwSZ7Y}E_%NF z&nx|^Q|r%P4=&%YFum;7yywr()$c!FV4Hjagg3<8n%R8*#9aRWZ(mlO%lE%r%%4@b z?eEJAiaS4Z^ZlRu@9Br+FNc)-PA!eCd9!fmXYckuVeWHF8v3k$HpJXYP2Xa1f1O3P z{@y=pY`=DG{(fRRN|9b26 z-1*+S|E|Jqg<{bI+)+1dxbJ~rEY&Y`E=ACAAioXAL5)e>175RLx^5b=~D-Ir-(zWB% z%)@pQ8aUWq%sgzjX+5*&-nAua_48y_y0T@-u=7Jx^v6!G?s(Lbu0cb z2*>XaF^PGRb|`y#>*l(tx8wPkvhr#_u2MLAK=*w7WbN0-mai9X*zYf^eR0ZxLjQlZ zGh#GOmHOY&VYqHnmi=ztemfgSo&EQx%2hn_q8hG0wphx9A|wn>0@xw zb^TqHvm`i|J&!FpT+CGPu=M=%b@TskpI-F5e%B{a#vhkc*FR-yI=A=B{Y6SE*iP{m zoO8|hH2GTjgEjxT*k{Yvd&*f7Zdkr=6P8z9{)Zv#r|vZi?gul@t`GfmZS(9e_bM&9 z9b7&hzIWen!H=~%3`5zh~;(4YW${QGZq$5Ne7x>*c-Cgu>NBYyQ&EGG~xw@fA z%psw+<#O-gA|>tzzp~j@wRCHAEatI(UCX$m?hS)%-85CkZqp;|1!taJ-zL>BXAH_W z*OI5bVzww;?mhh_v&C9w`2#N(@;~7JJ$I_NbeTgp|ARNo{?|A2Tlt>1eQ~9%mZ9G6 zP5H0shx_y1GXJ>yy_R9IzucWi%oeui*$rxb)-Z&ZKVaVRY?JKt)9eL*O=W*G9J_09 z;1>g|Zl*OIX1Ocp{Eoo(()_P~AGM3=nAT=~FH_5}{(5F!`0*d%Qg7GiCvq;(=6tZ? zpxxx_S^cY+qb(k^8fKSm8B&i_uf>NuD#@}v_U#O zDuU?+7gLAGhZP6yl8>2RSfAdttxH<*e^j*6i(s)1*}3IYwlDsac7FBaKMPxVcJG?E z{C@5xmV`vk1>Efnx56yL#qH)T-}7suDg(DSL#!v$toyUeO_g3hd|c^xcN&AvwbUK4 zu@B!=mQJ$gn;$)ubwT+~@A*cF_t($*`D?Yv=H#s*>0C~VwLBA4PMhuj^y5ir$8@K+ zN$s2d$=%eM@};GO_eib8jKehYI zQ#PM}77)KJKnAwZP0n9f|Jo0z^^_KpVoVYQHpx()%UIQTnZ@;LK={N(h4UG|{4SHLdz-UwCg< z{DAg>$n?whmye`HId4Cf_UoI+rYGro8*^lNYr8LUiEq0v`0bY^L+|H(ije^>hxN-- z9_-=yTP?ovV$;nXuYYIoD_%VA%*WQ%==zO)`-X_k91oHocs-aifo0u(zAEO!RS!zS zgTDHH(R+Qet=qWdzpLo3WXU7n+V1^ca8lx_{Y&q_t4>0n_obfPCav(gTs>B%-D1Xk zEgr^iO!Jtwy=aM1y7g+qh7EQNqVDdE4!zt5-m;#nKUi^K#oPqDfD7{5cJbFQepmAQ zd5q8ENB5-=;?1b39 zIV=xP-1be8*=N5X+p>q+j#;)(t}Do2QQ{VP##rBRa3i}@s(-`<{&oBK|FPT)*4?y3 zXv6I^)?4e8140EZ3jVzRxnrSj;1ive7dH0w)h~Zuzol*e-;TRm{aj|#8_S*-G6W`xftduL+Eh5KeC({`@Vd1ne% zw-sI~-}>YHQqKrFxw}mKelzap;?L_!m&I{+o6cjnHM?i?4ev$sQ*UUjtqDz6;Pq*H zrq!6;82g^<-d*+fgNxJ`)(M8x@mwuGSXL;(e5Bf8V&go%Dc>CaSIdh0oFMdtEn+B5?>1_iqakAR8(idUaZe)CM= z{oXmw4JTsy`#cmwQ(da}HJnr0KSw@lTI*4Mhv}A#`gIwOd7%r!Hh$&5eEY9vzoR%@;@x*_hqQ&G*I6h`I`EA_7 zckd3b**#gird|K;X8M&bPdnaNvolVxJ9d66t7?c&=7C6q{+V($X8bQ$^UQxYM}y`T zFJyba*eG~KuPL&-$PDF{f^e7SsxioT5ifaxoV1t zIejgkP`1G3!GYP|9`Ae@yi(vov)M8I_XqcE5_!5(?NNVE)A@$PfSPAIkLF9+-QC<{ z73uWwVf2QIPwZ#%8)gPKd|i0_+k}5iS^KwuO;&8^b838?df^I#FZaR=jk#rwy=8ZL z-0SS8hVX2=$+&9!e^yobz5Wj;9X(>VzD?F~yU-rvB%QeR(x2~|wDRv|Q=PDmL*(CP z@r8~HA9~ODttyhoAv*h({GCHdTlpAot>cW?dmtd3e;@O2dFH#j4j;aLW{K2|3~LX* z7yh45|5q@4T(9D5x`w~1y-}UDe6tDbd%XpkcU?-2MZPt*@_x8xeIfa|!V(3meZMay zzB{h_KTm`!XEtauHca`_k1zLl%5IC@`!AEWm(P=Z+f6ws9-TRs-M1KbKRP?RU-PuW zZ|0Y>3p^e)UDs4|ekd;2&Gle%y<-vkhsy@9onLI@tubSs)u1Ein|bPJuycIH)c0Mor^J{hH|F1KI4b1Bv#LdPDQn8= zS1V6D-8H}P!1-F^`)3X})eOE1x2sL*=?^~e~ZN)r9RR+=G^1IW`n1T&7T|}{@vNOm5;uh|7hdhD;!h)_-xbS1&e;iZeD8h z`?;jT3JLkbnx4m<9qkfVq7zy7Mn6M zF7wq*c$kwBwBiQOzG#l$@{-T5n!n172=QGd^XPr`nW#sX=CHhF-_cdZUUQ?sQJ7n6 zp}_Q8>ksNSwQ?suWLmMVt-`*)uc<-(4X3)TzKwmgOgYb~qU--MlURKxE?*3GOjfK6_yP(u%+K33iS1L!AD%>3lrz zP}O*i;XcFX1#wdyzXt4Tbf3e*y}#{H+=Q1@S z-m0m{*m+0(gj&I6-}yy{cj#Ia-(c^Ud5ZTjn?cPDpVh6a1!MPFX598Turu`LooxvW zs@+mAuQEUSI^olT57IZR_+~Sm^LMCS@p-`wX0hh$G8=A)8#=olOaFA8GwtEy@U)DK zwtK&~U6Hm@jCN&W6LU~_JhypM$B&MWCr#A9EP3vtCL82!Ha9?c*3m~5N4RIJ%r5+V z$>h%$!$%KQX1QKnA#v2@*`ALlpZ2F7b;$5yzkcMS;lj+mK+ZNMxnrE~4egF;JgQis z|LBOZmfye9qZ0f*{qsvz!){2-`johHVb8ITCrwmUCa$`?z)xO=f1-z&>g521lb58X zZm<(RB|i1)o+S}nTB}U<-&=M|Nbqs+jogW5p;J38>{y?EzqIEG$D)M|67wTIZ9HK0 zi9PX*$?C?}LX0k_?uRMvzQM#8WyW5cnzq>IhPUCP;zyhLj^`E1?tfRi?HJeVquG9| zB<4@ww>K=QlS%aJkI?&*i@1K?dA?m~(HrXrF7tk-Fm;^&7cDnEc-qSM_d5+wJ;?1( zJ7xV{=~3~6Z|*H#uRkA&=2v)B{NWt?=Nt8MZbzP9h~+yYcu0A@ZKK5e!}Ycu?Q!#( zI*N|WtA5_`K;HkYM;+I-n@O7i#rseK{u=KeBzP<-g%|Kqm)d$`;zKW>=c z&h@hJ`QiMAA9G61Z1dUk-?v9Y{eRx;n7`Zaf3`oOv7GnjoZIiJ#9938D=*8eylYdZ z*7AAgIh)1y$13g=+`V3OZT_{($5sV(&O5BT{XEYb=|qm*Eb>!Ghl=dQ8&{4%%UV(0&TAxBOsNr-+t$e}gQ=Iee>g%`S)|EqQM zOI+z_3KW^>{{OE=(uG3*dm0)N$HRN%cd#4v*?hTUJi%rCyqfkIJqtYjnY~>Nc~3C+ z?`c?eVf8V4g^g+bIgF0)a~1BrIsJq^&XM~b({tj-Z95m?7eB@K>iLCTa0wHX7rgLnM#qmMTyjr;Wp59fv?^)YsU3yP zA+sL~@fw}C`o8zU=Q-bZB;FD0k=|{obXlVOFhkqipA)Yhk>AZ~P_n)0&ZGp$0z<{? z-0oa6`@f~VS}OFUjc4Nj1&bqVy|wkHHWb$DB%OHrwX8h>H2BcDaJT4-Iay~lQ!jgJ-w(C&p=V`fXC)}j_)z(z-tFbq zty|yhZaSYFJNs>_eQfbslSWba7He*eg2Ud{~~+NuV!s_4|JUL$Z7hoT_%R^25z0Zoz4i# zxEJ&U#7$hVN~>2P=g(!XNvu;VUaGyCc4fj>5qS-L?~gAJSsBT_*_oNM^U03)x{jg6 zy?4Ji7d-5fs&(<$_g-1)N9B3tUF(-DX<2@M?NN!t6Jmw5{rM)oKP`C1?Ol{**vHQs zBCNtPtP0*2P5+(l;rEj_p+;W(=!*W;U9YtbLmypi6bha{9b(Rfwf!^Xm+ai< z@3bH~(@?MAdUmh3>HDhbyM6xa_}vkWS$rhMIoDVC?ru?m@&y{2Q^c&Mh+2w>OPvbl zOVw8T{KH3tcphlEWLC~kRfe=YTtVP)G%(;~ru zrig!kj?J%svi#}yo{Qx?KUh+yPMfx9l~2vuoxw#er>1C&AIdy_uyMu#DdC^@9zNI1 z47uhtIoWmIaV}8e&}pzsy>#o$_u4rLf4O?J_yXdBdIaW3FW9GNaIr=tzBYt8So-*a z9}>K6OnhBhDXrJKE4Ext{-P;tx4LPD_7T~GhF!@#_s^|NoW1t?e3#Pc z4>z}+aMW%M44vTc^7JY1!}sh1zNmUn+hWR5w6}0cLvHoM)Z9-SO)M8F2R%x)?LQ&Z z(Z)1);^8FGNCy5h0xB}^yS4bbgrgWZ7ep6!wfqwKVaNH^W0iYmUr(>p&{*!j-l%J`Q{=>emI5Pyvqm(Q^0*B?2$`2Ue-)?XGbspe6a)3_@8-$&n>FZXV9+o^tu zQ>RWl@My8guoudl($dmcy~1IR#IeGO26Hc{3rBKH6mmOtJ=5}2)wfBLCcTejP*qi( zGG)q^>UcXV<@TdmN(`L&CJR3uZM&C=pvpb+ zd@FCv()o`!Z+%>tW^>q1&AWe*)3hHf`&#>2#1)@OO)7Lg)7aD!Fr`F8x9Gzx+g;() z0wRT$=l3U7g{r&=lv=##$ihWBN8M^qOV(Ui_vQ8?^{Fc@QZ=U^YH`-e)ac=6Hq%~Q zojR$hLecQLK=HJDw=LE!+;C^Z%Wr!tN?);mxwl}_=KMRef4)!K`DRmK$hY3fIz~qx zJveq?hg~1H=v}W))s`kD=kL6edUj^<6sIlu`B?Y&#nt(&`gZ^9&F*buf1Ml9_xMzh zY{t(n!LPrBwCXb>B_-Hp*dOnbFmLNTDrnx;d0g{-SZC)^!#tkCJ2H|2QA`~VjtGZ* zd2ur-RA;?R<$Yz<{OniN^RBlT{**KP z>e+TgAlN|d#`8<2d@Cg+m^}l7)_pqe)gLWx`DIeV)K&kEJx`85srPuh?-ADPjfF)teOZ>>)TgdGaa#l)n*_&ATJ*eu*E45}^qIQW zWvZVw{dex@bI;v-eA?~Y6L)r+)@T{iZ8-mLckzqB-@&oFXGA!8 zh>A}9D(yL~I%nHe|BB*^K1RJ=(&8-5(?ey{4Ssv?I(nn#fxqUOFDHKRil}fE3b(zw zrPcQLp^RL0f)xL~zbd_3>z<#uC2@qsYrUeR#C6x6W(&6Cg+hwUqUeP6 z?uZQ;aw{*1NatPP_qbqEt``?9Dtc6}Px;M{*>5ZIPR+hzuGu+5@txMj84q-yRvr=J zTe?@~+r4c0d4ImY{ZlmCx!}msyu@jb&);r#{%+sr(kP(M(WZ5BisJ0HlIDXFE7s^N z+mJrZWuZdc9Od@6O-Dq;r_T_6zViC<&DZ7BKfL*T`NOQur`P{bYP=-P{&>d&i$>7| z9zPp{pU;b~JHXZg^gd2FqQLaj_R*D)(8tGOjCgr}%rp^|{x`+t&FFkyA#LW+n#><-eUHlNZ~W_SDcmhiZ1jiiZxtyv|$sM0LKzV1KyK=TJQSw z^nL!bdG^lF$I^E`SgZcwi~s$WPomdje#zzSf4=-q(c`=B%7qgbxYg}ROuAuqi7Rox zG>gPXmSwrgQP)yp-JTn2bDG(<$7>2#$bIzbEB^oE@D}yQIlr#$-&B3SF6-*4Zm~MS zkEs%DL0&S)XV%!wF4*4kS9KLbiprm`DUZB89j{$bxg%xCT*dRk&%rILNKA#t_l}TE zKI@w4;n9lhzqHRYE>&Md#?g>d9=hhs(6~3qM)D1JUIYlz( z^X)u#nl(Lc*~+|4GozwdWW9>azF#+`cYX|yUlvvH^XA_B4?lfg_vB5t|D$}nZ=80& z^XEUBXV#{R}@O`^xkHf*l9kNT&p9DF zJ?`N7_kYcv?m5l>?jKkD@8j~DA53GJFza)pv9C`30oWwwR%6(wA*=oNza01tn02V{BpiE-?N|3wK4`uwdtee1t}07FnxMk|lVHboCk z$L);X$s0@dyW=G{56&vy66xm?>cH~2DN50P*$s0=>IQ~ztH_RkmA`;J(K%b(W&|Jn22hj-x< zer+Mk%zD*kEOYrp5uq~AR_`+lFy<(8kHFJGBs#o_2Hy7Tq#{-Uq#eoyw+fAGw+ zuTVd^&4PFTp1tJVAz~-{n{2&YJSGXzu?Ejtuh}~+nDz3t<>J#5yBC-`A6B;ca>2rS z+l)1__s(X=mx`?np3Y=;f%oL<^q*6tHgNOx83#%(PQIvBb*(gT<_0IPPu|7UBOUhr?-1|Ij|ARlP{Sr@Z z`neGRzx&&y4lw|Cy{dAH6iU-z^2-v6twSMu=&X^TnR-^nY>vQS{P^5HMb68uH~r4^pP z@}f5Q#&Y)`%lBOi64DQ3Raol4mf+Q?D#Gc!;l`C4Qw^*nV)P9C!d@JIv_d#c`5TYY zdAY`V_Im3Xu>q?NuWw^)!AUb0&d-}Aq{+HXQPW4{=TrT< zlZ%eOPmbH|d*AcQ3az^xJbb(Fz{aWtiWY@ULmsQ`szJJ>N|8;cC-*wzOzgm|k-sHUZYx?>J zUEKFtqwSrPeW!TkvR&gj+!55sba>OmWd~Ot|MIc(`rPv!TowB)9KEK^*lu$C-$tn? zyMF%P_p{co>h#u{$BQl(oKBs=cE7(w&-Wp}(o(~{vkG<<_=ie3adaJh6sXxaP3ecO zW<$_Q7x!Jddv*pS9ylp-CwErNh2D&ldRju(}6EP#I(oghHtoid%`6LfqMd8-7C&SEC{)=R6-)#;Lh>`aaO0* z_j0`!U7vVZ``gBa-x$u{t>gcG=eLbh$cpQ)1aHll+y80B>81IWbNl~&oL+IeUH{NZ zmNij3JIZT+a9w&S(b@9s$mDB_&N9vZcK7J(^S_Mube&xJdfuYd>9Xc`f2vyTva;Bk zEZFxxNKd@tado_Jcpl^RJu-@8mNc$_)qzA-{+^4XT1Uo@BnxI&+7 zlN8z>^K8}R>l==?#U8a$y`LJOHHp3brkU2w+VgWwx`f~C`&~9gz9FproC8N!>m|YS zOCxk9oouNwX_e=j`eUC$f+Z`f$>sWBdED)B?V2A65Dqa=wjd^cRmYlQhi~W7P z^3BS#Hedhfac%t=`LiIqtMjAMRkz0eJ>QN0+?{TJ=+sl~%F}J-g}?X4r(WL1Zkc$v zYFBmGCXHIFzsk->UMzWbe))v_f`gIy2?aUQOA8Nvz5kOh?!ia#_y1YG+g0%YZT=hc z{oeV&b>b^RW2Hpv*S(Qn8Z`4;-!}~o4SsRCr51m?PXAc?Fn~Y7+-_#k%o(X0D_=8M z%T>y(k6UVF;!&H#Bm1L0GPib$z#h#LH*>xj+^^5tmA^}MzUPnSS{*l=+H`;Ych}Fe zTp_@rsWDA^$|+MO-GVI-*6ut1tjYDQnDE0sr+Qg4{sruA0{y>P^p+$k#7g8G=+Kt@ zzF?i|Jh2~AAturaIcsM|bG8^VcMpRND*#y+C@P39N*8%MjYxb}#C-@NO$(X{f|bE_(+ z2b6a8^w=IxK7aS{+VcN1R_p(-t^0F!_l}R^@ySOGvn!rFxBl_%{C*Few2Kqp&Dw0> z8YiU~{}HtCR{0wH;A+BmJ&83A`;{d)SyWXsG71DU4m&7nOglAMlA)I6 z@6s*D!UZxMw}w4m@I0Zb;j(_M>Raw-2d~XHv@`H{cB4E=^}AD<;04ad@$KiXGxkr8 zski)V{zqBMbpAJ0?VHsFGiKM7*)J9roibBt;=6Ww|K-;|&&&UpUOultj=B0+#lM-lKh{}2+UX(r?yIh7x5wo}J;z^e zNRIjauKZHGu3^aPB+=C;HZoOwIP*9Jzg^pWG<-bKk)s6)ts*jw(=#G z-|(mj`R;!Cm;c)@*=3AoiGO@N63oOCwn;d4*Im|QNSqg$-Me12G~rG&bE!v<$&H;N zVL9!MI~=d~Gpz}9tz_7C&H0A?B>|q_lRi2GTx?H#@lx~cgg1|{zC6W_Rl`pUgvnei2Y^%!9{jq z^Ga3A@BXP*3`?n4bLQ9O@XeK<>*iIKO}Nx(!yA5i`?*WpNipgzRS6JCzl*QULeCAK2<`?&OKetZISKa>HEG4 z>h1h6_s71Y4=!lTOc8&cvt!2J>b4)V|9{o|GpUoSPo{>OUC4#|_*N%&yOl0I=l{RG zfAQPV`iDDC>!qEx<)4(BuWnZ_*!s`5gI)f>>d+6;yiIPhPj?Ei2(0+v_1a+Gr86cn zyi68nYCGonhq7I6typ#XlE}B0=hL|qw!JW4!!W^Uk7A2jzypTVrIJOao0#nH@b2Y2 z7#emU)|p8}=ex=6(@lZ?0UuahRW-65c|BztyAQCcc|ETv)LQ}XZa*p4fQ~zl9P5TOQvAH|`#aUfG{_y#{g!hyGF5ubrwsMXw`?inU z-|ugoKimGP^!;D_^Xf{ZulVk1oAtTPK4(`@aKObE3J)CW?b}j=b*EN5S~frFmZ6$d z>5~&4EA*Qfp8nRj?_8;O>T|$8`F}PX8e&`z179dRzh7DR|H`s?HWS@q_h0`zpB#uf=2aP{7kOG*@1I7{@rtkVb2`JnYV>QqVr`ASo>7`|`u3Nrvo#d9 z+~RusJ45mC>s6*KjHgT&FH=-oZq2$+eBZO*5355o{=CR|_Be3KgJoRLLk`Y=X>0uR z+vc+@b8abIabno-%W`4Mg(zW;35O0`oi&R=R>OwZRn>#TiM4^RHIzF>_rsP0f)lS! z7h*r?vb0P4kWWL_q5o=g=C}fBJwy{uP{1kmek=30h|_3*L?l+Xqk27=5_u5 zVyz=>-q)1f`N{FOdAFqgPYqtTji>(Hsrkm|6R^U<=Hr{%HMW_&-|y}1yy(Qc#BuAp zz*Q_4vd@+|3b=S2xf;UF7$vFl*5dk}zhCEUOO#ZfTO{WFe6HJr&>J>Y>ebucq&@$4 zcFyOn@JXA)i_hJ9d~<8LaQObeMtf$ZCC&HFJal+vR*n9e3ZbM|D?-z@E^8OPEx?-^ zx=?$8+T!J0y1mZ5&I`qyvs=F{E_<--!)k@9{&|z4Y^>~-asMk3F$iY7;N$AFnUyn| z>%sOXOeXE_S}a};3>IFDLh+edR&N9iL{4a$=QgMaFvWA!u*fxa7K!Q${Y&WjAb*jy zL!e>(fq)Ai4i-4wFTdHP$0sAPG$8cGOp&8qj%Uqp?n$1(%+9Vko#~H*vB5s>?9&W) z_uAU*{#u!}?$OTl?;CTzGRakMneV`EG4Ig)%isA}gSBO^ac6W!GvD4+*xl9s{{HdF z{_mc@F}}8;K1IIMWzxEBeACWZPksOQ`C5yw^EcKVHR6+76C^#chevFssA!{jRPEYB z4e2wyW=mJePs{HYY2ag;AoaGr+5Yejhladu-_6#RihOMsu#{2zW1y^JuVvS#@MrT; z#x!q!IbC_(U->}{izFX(wp_Vxb`sz?>9VqB#s_we zlHeap=NNMfXmpCVynUIb;E<8!XJUD5ip{?tb<=cDfBZ7}_l)~{XEZKUTI||i%l>M` ziWeFjCfwGKO=_kG*)DjP<;LxLOZMoa)VFVL%sU>=RNnVe<*d-nWgoOz@75ZYr{-u1e7y7qi zwlA~%-jZ+6rklv;Z zqV;e~?9zoH>mDsw5hB{%KlAuwe;F6e7w`2i-kiH6yKYkL?^S;u&iuBfX3pj_j~n-v z3A;}A;9@JcoU!b{%B+A{soF(f-s^rmBV1|YUwC1ikjb|IDgF<(zKZeB4%|~JbGl?` zf9}FPw~U&pGh7%LM*S+zt_i(@riqJnyrHjhKsIMsvZh^^7c!E*S7OE(p~PwUbknBB-ff$5-*cZ0#pRr*J%YcR_SA085+Ci#HXspW%Uc(v~nkT%ycib^-9?+xkThjH`8UI z6$*cT`$lj2`I4#3MexEQr3 zXr+tV_#LSgwDeomKegmXbU5qVk)MGR)e_SbUXri@<^WNJg16 zzxRCJ!*YMedK*hQABLSdX+;ewpEEu!y_ER0&8mo1Z8OK&OOrA;#Cx19oxbFTeayo3 z%X7o*)>++rv`pPQ<#OSqj}o`b{U)4F+rX1?MRaMGclq+9gp4_Rf47}{{&_O1o6;+* zD-DzEzBUSd7F%*-`*x=V2fmtK4eT$Umn%Q9Kl{A*hpoT8JeYmF6J|8^os;?T;P(UT z1vS2Q@eHaOQ(15Jv6P)riZ2Ohbko%6XIEG-E8Ii4#{5n0grK6kswWpeOV;w$-Ip1( zF<_3|b>8^-W_#0@b^NKDLtE!Yr8d^1iw+nZ`dP0e z)%VIwVP4P;Pfvl+yIHDE`|TSJT%Y_u|InTI>HX{Tb9|y6ifJh{^ZW1H8%I`XGp`6t zVEItEV)9bq+>DfjqDQ})^}G7>?Gs&ccLvUNE}k1!y!6_Xi?3vhuX#SLLW} z!P6uE-2Yu9apT980E-_M4h@GMc-FNZTGlILsX8NFXW9MRo^B;V;$57&o|7DmotmwL zd4#!zj<|ODp4W3r`nc-zHyKg+`;~_{vZc51Mdv$fI&)h_zA=epS3I;|Lh!9U$9kDV zCKm#E_qk0zm-h4MG9jU}*5|kNb@jh|-gM=}3bkm7hbzhyS)AM~D>WUupUq%rky6$? z%(#}T}T*ftTxf3 z(M;gbp(C?u^p^6@@JO6|woGZm&v(i*Efdr7cc1+J?(~CT^#whw985A@79k%rl|Ona zeq6a}>e)N7`?{ic0U+LV4jKoDtCF|NIB+N)DvfLt2 z^O*7diR;O?b}Ag|a!PF2av+QU|IsTP(mc^E>t{=4I<5(x6p^qAc~34`XY0iLaNE7CtztK8 zdb^&z^E7eN-ts9hW61+5XX+q+EyC7vBgGU$Uopt16a!*uaUHXyh z5Z`n)PR6oh3iG-iii>DnSg^=VPc%16?AP^P+3hdNc^OUCp1E@TiiCsO9N*x~4<+v{1EZ_M6EO88Xd6dZuj`uB^Q1kl}dj&63OW{C#FE zVVrGd!xF01!@|sB@}cnO&)U~%Pap60k4zNL6@GVm*;Dh2X+0&?;{Fh%x28i#@Z&jh(U1O*K1Pi>NPA@6$`R)2rpSVQBA@u<&xx< z3n{;aW)wQEy1l44u&vVj*2dc^WwTlQA5XP4FlkdY$mukhS)zQXjPdMO{vEn6D=m*R zq<#82`_TOm4yPF%854JeFrD7AVmH_A4LctEDc|)}q@$d>%(8a*Est?n{wDRn?ZXzr77`L$ zf&&)o7=;BcZ%Y3av2RI_lDj!y=@g#XpIA4ae{3&uMK~j|K`<##*Y{S@Tg5ZepDhV^ zt?@&1se-6?pzibur`)yW1%E7vDS5E4i6OJ$8sp5EzM@1W7Z!JgL>H^WA`9>5XBpk( zxx{3wb|5^$(@`lmF_l$KEhxS7ys^g-;V=1eiuV#9h?<^VKRNJnNOgJNp$g3`^}LIx zg&5B);aC=w@pty+92Sj6AvMFqOL7ZQ^00 z%^b?zQ*vjx6@7c}`uOprL_0P!p=L7^Pa}yLbEf{Y<(azZa>N0y&nl0s9M{{l`Bj}T zc4}Dmy#JXRAORW`qHkxJ6sGS^||#|tU5)g&f<6;Jd@G@5KMU9angW1HO`6V|kt zgd+|ft%--af~yOq`C|9xmgsm)%rJiuZOVVz#2{JdvRH&>XJY&O^a!TR&KH}b58ZcS zXun&M)K=)v=ES*$=WqCyC98NQxy@nyn78lm+~^-4&&EG5oxX>^UgPM#i$YN?wy(JO z4P1Sj?5hj&EJql9xy3y$&)Bu9+w#u&j5QSVUooPNUJIgku3| zJc;gyWP2Z9%6RnA?A21HL)i`C?2^YsTI7|wH?(fk{PTBm$r zU6U~Tu_Hq4jJ?|FNy$|nM;^cF<9`rtTNAmsx>EXa^(u~~hPMw$24}=ynE5)Pri3Z8 zqd>o=JBlM=*}}fI#H5*qcN`{8W8;2gD9|*cC-{>Jt9!wNn@W!#SJqX%{{PTn<%wCY zuRU(;UGi2=&-yPDm!Ht>oZ}{G?{&H_HfwI;czZGTYmw)3`J^Nxi8qHrdE4$Xhx}1$ zK4+Yo@q&Rt_!j7n0ENHj{CtFDvge+RdTdf7wZ(Y8%-ku>TD!TUGae))U!IeeFj>iW zn(&jKM?BB3Wmv*^$;HJ$UR$Wly4`1sa**tgk2-amn2qjEh-TRN^TivR6K9;4>|VH* zd6K0^nqa5Nkx2`c4EYoppGhVoHu;tVU_OaGrIf9E6rpC^6(pMKic zwtXy`cy33+4uy?p{T_u)oO*g!T6)|Jl?xKnj&6AMeBB>@jx9+i?t9T)zW$_I{_ml^HmCNk zslP92(!^%FSM9s~p1J4N@dcGhFHM@d_xHEf&OYU8CEZ`K;S9cw`F!;u!Qmd>or;U@ z<{xt4XkNAYgq7XQZG6{sZKrJvoGxqa^KRE)L%lsOLeBmEt9xbN-Ch%wX640eVy7lu z)qK9`<<7U8KTR-W*=AyCR>l@}_}Q;yk(molSiCKnys(+)?w8HY3`di$U4FLR_!xs6 zYuw@4g)29A=N_5TsV{TOLuq4x2}b}2%iBfWR#zm<^8nz4}Z+kJ|A)9(Z0z)A3d*kN}S*Fbo0;Mvlx!XrE9CH zIc2|^(m8p7*Hn|eC7U`@a~?2MS58uwOqXWkWRjWpob%X<&26a_S0Z!g9w>gtJVjGT z*=?@T+fB2-t}MP0RL^t6_V?EbLb|MnIG7t7%_^QHOiT{{vFGU%*BxGlA>JD|*&d6x zy}01QiccSfgZF&yOXT`#b97^3-H&IbbN>IFf8a!2$%BQh4pKr*X_6oB?1+{U%6xG` zSWIyWXg(#q?R?&D8>IOp|?^E9c#^J|z2{@51f{b6@{|oX$}5r~Z-PzQWth ze~vHyeSzcGCBrVgJ+;1*_}84@xKd~5-&b+hblxgnymxTw{hBHDe-Cpjh`G<$XwaSD zX2_t(_gZm=?9|rlwsW3I>xCKWbV{19n3C;Yd+cS7&}}oP`uQie8t|R1oSkj&*j;yA z&>{FnvqA+U6NAzX{gWxhGW*}D^hNKUS9#a_#mhLS_kTiDZtaS=z}x-2c?NsIo5cD5 z55KoPB$+<%_`lWk~5no5f2`Bu-AY7fvbZTACzlTV-he`MpEk zE%qmsUGW7>;uE=i!sr}h(W1$z-?Y9}S{D>P`@oZ zVaLL`V)ri_UekT`>`QCruj~zG>~jqd-s(vxmyFxFhj~fL?hlps`OQB+?%z9iwcTgm zEt!t0Z94r<4}7n^Ip252MP$ik3AYH#j2S|jtjiP)pIm(WZQs7io*uD}C35%IJ~ro* z7rW)fvad(fVPizf(^FF;rnP3yI`X*i)~#C}OM{jKX&SxcE4rzdv{7X1D()zsvIU{5 zMW3bb>X7t(*j}{L$7=4pPd{0?oHgaDQp~r#OFz6SaudT>v#^xD=NEq+wyd8+UNQ9{s{5nfH-kbZ@4s+shD5XV=_iDmz_0cU5oR@cqMg z9-eEF7m^Jv-pJM^vlN!xU10WR;oO1`y9FLjxLUBJh?{ZG8o>j7ves&^|1RIo$eozj zArW*#qOEs|;jOnilCp<8N`t-xsjSgapSyDkf8CR!O*_r@ee&Nv*(dGC1NXSY?En98 z#g#rXe{u4Nq?FA3sr+jfURm*A;fkOIy*g}~w^HTby79^Wcv8aeIXC^Y4wu8?neOV9 zWz2Fy)AgopIuYS^PbPK2Hg;W+gEFEOOujo~)GkZ%v-&rPNv&j_zg#{q@#p+z-!Eu!=hOcGecbDJ zib=Va9G-c#SU4&`Z+hnYGj7&VEIV0qOZ3l85)gC#&8;&>=|^y;qyLWY8&-0h^6Pxq zSjZHgeAH*nj0J++6TTMQKNwRQs9Pm@gki}Pk?x}>_vZTkx9|Dm-|6PQ`XC#3<+l)R znKfb?lX(4ZPI&fR&vst@-$S{7E?(VU_-bXk!k;+1zn#*IKfZ+fB?td6i!rQzTiweP zJ?D8r!A8#uM{71Ixy~=-*;k^`!DJfyu(HmPzq{d0iU0JUI?4L|L5VW`T(TvXRCm7! z*eh{}qg)}Y*Zz8tpVLD9sa_%8sx4tBUMSXxznrqr!sqLQIm^W-*zU%g-39JTlv5b#T!-8MkQmLtZk8kzEcEO|#ZKP?tJlr1tZl zR`oo|MfJxG@?s4QBI+AI_=mG_SLw8|ccmCyw9c2sI^h6>wDjlyOXPRk;!sy1;v~zfm%9u zIBh=2W*seTdAvxLe_~nSPnKliS`oIgiJh}~-sXMSmd>>A?>6Jg*Y@@D!5n&L_jPSd zmtSJEgZ++F$|pPWx=VA3r!0c=PlG&Vf58)?yTVC4-Yif*Bs7X zQNh|)FS3ladc9@yj;zNI-RCW|2wQIT@Zl7uJ#Fp*mpdZ1EZ%VQ{=#Uf2dS@_WZ1qh zx8chzVr+2|c=l43X~`9xp6qSB{f1%dgkMJd11RhtK<5 zX7pCl&m#Y8PJ($%QRk7atRJUDG#+n?e}81*L8dB+#FnLN4jz3NX}0L&hYLAR^n|9J z}wqFCAxV0WloAW!y=)FI8q z+K)xpzkj%He&B5t|I!4ot6pslwUG(JV)w1YO{3zhSbdqc5q)8`&1=uqK6g883 z3LCnDm$>ozYp=?XImY?n*$$;&1^ewk2=0@%+rxHfrP3TOx4j*DeG88L{(0zo-qQmo zB&Hk}d@88HGihpRN#>OD+E?)b>%7+*^nHj8*?K}hf469?zT&eGhISqMD4#Ha*A4;} z0#^>^7@v4%rNL*uQ!x6QYt zF^lv3>07KbxPGVKbM}`P%Tcn@<`77_#)kHlUr_XC&UTgItbq?dLmj{n8_L*Ck zZoT-JMy`=t}1rtB|f=E=!eIB zM{CiLy$9ykJkx%7Enquiqw~rqic{LxJ>U6(_r25APY=u$K1kl!E4#Ah*{K8O+>Kk9 z1oPrqMaw+3_-htU+;?``?{Ax5?8sAN)3zuz*LijE;qRs?$JVlB*z5e&ede7ZKjpmQ z!Ru>-4ot5V5a?*DJG1X!BnK;t0#8doMvcHlv4pjm8q&%We5Ra=SjnQr@qyX((6*IU zrCZ(?|3B6qQUC8u4T}=T^`6C^6Bap1x;9Hm1xxEpTrHW-kmw=CcDi!jZ^;z)+%xG- zHvRzzxO7w|ZBuaUG-7gO?w3-Q&=88Kun2knVQ;F+1Fa*+A3C$XIKayq_B!M7a`t_# zCO##LWxfe4nCPgH==8JWz~Yz_&7TDJiF57!WVnT^KAn%%pi<9q#h;9GNgte7ERX4x z*Z4Eb?Z|&HN8q z!|G?{Ylyfs`7dE{Y81?PxG8x{$NGhr3O-CZ9km;%eNAKe^eWtb#7j`OpCM-5s zSv+Cyk(Vm#o?lFR@?xX-$C6rQ!_#Sd%k``)nzXD93^X4mOgg0EIhRF_k4^2tM7737 z&v}V4GP|B|EikM8Vk`BS_o2^z0|6t~h}ld!ho8-Rwv}7dr9~#hVdn&Q4gC-{tsd1A z9xFRM3gxcu)VT0(;UP!f8?j=ov86377h_Xj3Cmf{ShS|}M6peB;GOBqIa4~!#DqCQ zE(rabzL&`&edclI>bK%OEVFZ8wyQA+y8LBW$g4fwD>1)ef`{TtcCP*cwY{&i1sJ`w z?f%@lS$u7ESbp;FX~LW~vscYfST}jfiDcpQIgE0}a?c{_bx(aT@N8m@t&o$3@L&pQmZ_pE-4Wr?=Fd`}18E^Y^|93N$e3C`y~i zlyQ!4!Z8uWAjYXhl1h!@S~E&iQ-UpBc5dIlN2Tz}^F_?PeOyfj2fK@Ybh3&att}N$ zy2I!Y9N)_7Yr4LzXt`er*MB)#mqs_fwJ-86o(^DinDOp(ic#?{hIZ}N3tD1bOE-i& zc&P+#UtmyBYVcA{}tSe6L> zJgX(ssMmYJ#NAln@RpT*EOsJaoVgrK!@C>8+(kFm9^9#Mq0wz8(|!KgRW zayc$)<-Fy<-FrzWV4>=zhp$=hyL5NPg8X4EYRFO{8vL4m>3#WAGf*4w?+Ju1g*pa1MVv1V1> zSrbcJ{%=0td7htq_-dJF-w%nbBMVE-o_?Ll!V@JVw)=H#^f$en4BoerH*D`PZQsUU zz03Cg!G;Bw-$s=Sm57O5xH(BjJ~Kin^|MEoicCLH3Zq2ElAAjwB{&xNINSviFr}oQy2YI>XYZ6Qgt$M=$RrgJ~ z6r~uj>0c|O!OXu=%Nas_H!WOxZN8M?j(>_yiVK+!oDkm6?N!oXT#&Y?^i%x?{QmmK=)=9!(aQTLwAt9sUK{r0xAfMi7xxdJd%61h z#w>|>_gk-&%9_T0uG^leW;Q{TFC*i@#P{Yt!nM2Pe*LfVZNIo_fB58e?#e7;&*x!&xImfs=3RpIpHUHymq z4F|t1mkyuzoL_$1L1qSP*?l};SoeQ9`~K}G3GU=Gp>|Gt87{~?-5}AvF7S#*BP$c{ z9n+SEYIn{ZdFJ!fw0V;k^cfkQ-oo1+6mZOeqi}t5(5roH492W2M|SHzpJgKTx8%AB zuat!kU&gHMlWn&hVmKXWrc^7JdS+kV^WPfA2Q$}R_$kK0@mx-ssbSW##%!q-{u4Wr zmxys#JYRA0)T`fdX@)f$Hg%;Q7bp$Lk$sO-g9^1qu?j!Mct!*D5$m^`Tsk6R`Qa#7eYzW zTmQN&TNlL4Fn#{HDZ6IrYRAs|>|Eb3a5#z4b#>#ZY69 z%FpUli_;P zZxmR1#g?H#SpR?o!(5fy9Y5@!+azQ^Dt`L<;hbjSq}!{L?U!XXWkdz^3n{1^e(~z8 zLQ9DO_h0#WJVzhTZGCY6UTvW?12eDt$63DG51t7o*$Y0J$2HNP`}C&!cVc^yWNg|V`Nb4vuBRluN|(e z@#D*`>xU0mGH;%hAt@F%E$l+f*5$FYwO2<(#vMF$NAzkyc0iv^5zp~?R*n8OzgEUP zzx*q9hQ&V~hKd;=^B4}C*f#eE$n)=R{_3~&`MCKQ>x2&tZyJ|A5RaQvBknF|`K<2Z zlb4r4dVG@YuJcNCPZzDJin(#Bbi>ux5p(x5P0lp%ea7cyd@M1NWtr=Nv#D1jvL&1< z_sBCC^j7-F)U!=q?!Q~W>eC5BaVNRz=`)lzA2V*x6$&L~P!o z)EN`h0vx}xNi0^Vs$aM!W6{^8`<5;FymbGvSDS6#`mdO`>1^_Ydr=;R@mpiwX0E-r z<_z0ng_37aiY@*eV4g8|r$oj1-DW zZb|XYtmdG{`mX=YzFydtBs9a~^S0`c=%BUp9%p8p&$xIi;Q(Kk!}0$Mo?Y|e;?P^V?V`qR ze(5^PPbUl|&X(E7Rb~snlZ`EqeEjpAfw||rw^6gA`@Yuw379o^=Zl}SE6zrFzf=4_ z_ZnN_(@VGKo&WGZZdyi^{Fh(L4mfh2<&(cC7-s!@iq|RUt+Q%h{9W)%VZ}8DMJbMp zP7fYdh_IgTmp}i|kj;nb`RlK~3R}|Tm$V%_!0@F?_6XyIi!rRpJiY%KBVKeUpDmwO zTK8qI+jh~VTg!fD@$NqRwQjropGeB^)6^5NgR?%NkkbakXp_EtZAqY|SsAEL^Zj!!7Mc%M!(a|H3^PhqNwPhO(a5S5vv7yy~SD zhx&q+29LKc&O(v>dy_RneYuhm8Le&yG?%6`y z%!=QczPVL?g_$>TcAa4T=i9%gb}!$MegEQ(>?kuHo>!)OekU3DpI}~KzR$j=QDXh2 z_kTOMZ|?kEuz}I(fbq8Pj1histgVX$cYl-RJ#d_V(FV4@=74qT9-bdKKQ7o6GYOg zol>kP#}}XeV8IuaE1ae`x9_iy)9V{Me;cfen^$sv^6{oN_eIBp@BjE`@J(hmH&e!| ztq*Uw?XawtmH&GrJ?4kO*O$Mu<5_hxS=D&DUvkcSW`$o2$N1kJ__8zH zuz-xCHgx;50)=&54gj8Z8uM|s*}gIoin@FC;oZx_*}u` zP1%dfI&PNaMr_Nzd5@Jl8|D*R89}vFwVV*kwd!Mwj zMc(;O^nWvfB{+%Z(=XzdW)J{`z z%4u$`hYKaIxW1Cy^uc@1*^?hO%CqtID=T(0Tv}J_?kI4MW2Wq;J8`kBYSIj|E<|gy zykOt<1Mpm!V1xFPInd28poc9sj*o za^1A9DZ=v#B+jb!TvhW)SIk)(*Pgm9Alt-&gSSU!tKuYnIoI>?;X)6WZl2@4@KH|R z3+8!y^!D@q&i#ApXfP<2vzWghFnMOX`H^}0`p44of44o4IXL6?>eU%*C%pK=Yu|H3 z;=-M?--Tmdu&s-m_hmxJof#ZEix#QHAMae8d}>kY_di7!lh^m8@hrR8a@FX-9M+y` zsW-V@llQQtnR3@wU;JFXF5i0D?wq z_*`O4t6V=nNVn2v^@YO|m&@oso~fYHo^q(}@SE9@zHjc-O1Q{3WS&V*dCsyfX4a_^ zcB_U98|QC%B%i?7t^TxdzK~l&m*WZHSrhXvF4+A%-7v*z;Y-tuD&C&YWos3VF*q%_ zzDW4F#?|2MhTJCu&K1?&iI_I0;>CR1Cv#Z$EwVlH%vM~|JIf%=Q$UGx!-Ja@&bJzp z&v@NrdwDc}Ka-+O><=Dq{Tao&Ebzi)#VaobrUfn(+A}{y&x)}#=-8s?(_j4k(R;7oY`*Iqub1Yh9uR3g@AX>y z{?Fj__(N}=vcB1=ul~j3lWL&X9g`LtITyox-T7K);^G)Sa2?~f4UD*d?7Mx>OYZg6 zZ*0ySYqmPfywmw~TVpPB^V1&2)QKDS@=tldIFW1qx)ThFai_jcKC^4i-o6&^lawA+HY}a#~mP;4-h~<*V=9PK3tpVqAJfR{!IL zfF90BHjjB%A2RuJKKGwnE4kh#zuM;c`8h#LJSS{Y3^}sTdv2Tmt`kLx6OI{dnY4c~ z5646SizD@{iXwMp&zvr=GgT0k_nfPnc+1+g!8qdFJE^*gfLXpVDOY`4Utam4Iw8rrQs-0c{vYap9$w$_UNN`e zNVQ(%d3|o1d*?5f$o_Sn9kAM5CU!&mku}oM!)ljpneB|{xBpf;>~g#NA-nQq^w)s6*NPnxJWeK$6k?nF8^0HE zH)cjZPrnhO|8c#nR@FXsxg{n)IQrdJUkzA&HI~8fSi&jm9HCj3nFb8q;pWQ!g3U?~A$Gzw-F`4F|4==@9GW32_oGP>M0ktrny^ry? z<%so2zSNTN@N&hL1&O!aKYq}Ni+ERi-s9l*=eG0H+q`alH#~MBYwMk>AM$>8d|I;Q zM!_Pk-BtWfg~1jZ7N(4Vet)?qmnJoC+{@pP zQTwfGJ#&Ah-mPNhyc=QvLJF-ozDB$Vz4`Mg_j8%mr@bR$qq6v|tdkw0BuxusKKRY8 zm3-W8=l8AuzH8enU!#!xNzv2e6a+W!unLmfuD92LEz8#^AbZl@bS~3c* z?%weDBXfV^vrCx*YtJ*w&)d+W(WSZY*5dRVdDAm$XW0E0?vbz1dD$Clq8P+?Md&)? z#ir>IAO4&YTUj(?tys^qO}oWRx zEGBgi41MPR_dHVO@lfdKlnX~!ByRe-?yW`fr=1QmGq~(xr}~9nzU;+2w`hJmYs;L{ z_$gUIYFmuC!war)Gb~g4Z{H*TXGW91zk|lzD0fE1{}LBwPClRbIrg^j`Tp3Rtf;rk z|HuD(zMh#QFG20j#(UEjc~;sS{{H2ZuDjT_ld8)y7jE6fb#6v_uf_8_ajN_chQ_xY zwy?~%{XSRWU!el){8b8Hn$!(1HVVkwmneO9%D(w;XL`IT^ZLCXjN+;vrt$}y#CG>d zKG|yf>C(^qnyYnD-{*O5Mlc{V|)IlN?Xp`qaj8^^I<2*4A&AyDb=m z_;s&k$pCN~eR;|>_p>*T z=UPmYb4X(q&?^4ZDjraF$@#lr;aba{$w5ig4xjv1v^WXJ1wJrdyxo_twg2z-M;~6E zU}JH8W%+sCs~Rm1*@_;YxwWdMHGh_tES69-KFZTA`{Zka(b`qgvtGLTcRUZ6A;-7h z>yv=S(gnNT-DGU;*l!t7RK8mEBJ;)I^!P?g13?*ft3TXkB}dNh`LNRJ0^b+jwI0iN zJ>j%eTxw~+cvD!*Ic3?2HJVd6V^45vee?|IyZGtN#!~;>g~1CCcDXLPw5(%F(2FWw zm8Ul*HJtC0wQl+_vHqJz&8Z8Fm9nvx1}aaTIf9OrbP9BxZTYso&Hq%(J5>(V!^>OL z{g!OscFg?j>4Y6JN$i}z=b6T~$E~hxd|P3E#^~S@(`30HCl=0-w`;Fg{Oc2SzUTV{ zF58;8ncHQ!6ge$Yoll&f;)jIsCs z!b1|LS>}JMd?wZC9~HYo?~PUxvtA9K&9#4#LM@ACG;VRs39-CptUkXv?*1G}yO7np z+rMibw7T%&<+i?)`+wEiI&`$kT#Dw{I6bjLpeLZ(cE*Yc9?hxd%g@i{iH(qAm)CEJ z__EP0eb=S-#68RcNfP!ycI=*|m=o$O(z0VKSKiuPeI0T4Wg;{u9uX3EDE!^@m7nL~ zvp1zNR@R*tH`e}?j*|*4PjoqYKyAH%-8==Q-ZVj6ST{?^_Vy?YVdl>LWw)4&6Gl>$N7mxpW81d_HcJnu$C)yKFuP%FY zqcMD5{mL(&PQOzqiFx|V;N(`7=4%IL%&c9ok@>NWwAr6i4Dw2;pN!HD8t@3*|F!-l zw|#N>`i@B}H?Ma&q<*&KUzGUzbsyz+stG@Cx0`2iPnd1t8Xbuh*C(?t{OfS5dj4Mh zh<7P2_t{$aGA~>+O=92m@~zB|Y#Xx9*>b=2z3j4j=PSku4d)v>7jK-u_4z*aYbDVv zzh^D^(o`kdksB>z|K;P2?_IUW57{UlWINcUF^$D$!4_us&Bo&1js1T_MBVi(9K9wf zsw}y-qFLb4xhCKEAChVM`VTsn&(~r6^zib}*Be}SbIkp-?fa3-{z>0HIcc;Uk`OfK zSli9GaE;=O+b!3!Y7!USSUdCfZgYcU*Y=8Ue0GS%iD`c~>(r3TZ-v(S1^)W@w?E-e zL)**G>!&76U#89yyz64M;sa&>x;+9;-m)!X%8wf_ehm42sQ7#O`ToN>6Fz9~ky6?I zovHZO>8z~@Yt|hyT3cp6Z9GVbjD7H|46QrRydA`&J|O zeMRk(Hw)$kZn==H#<_pJ>+TIgxA$JW-v95Q;)_0`$Z4FXzvNvG-jiFK7%@lit4m!N zSL}<4Hk*vDFFbnk&)do~=VFeW*fuvJGLEOV|IDm2GcUA?+KPD8^xD0>##j@y&3vKM zulBZEJ00dU2XO^gIJo%Rmd?vPsQHB2^*!&}=X3hy+WehPFf*Lll;Cyw z-O4#r_FNY-oh-uY@su+)BYX2D_BtuIB~r{@r?`!Je|F_9ls@HRHbZDr3jfjNOOmvo z-B?@K^@d-6ohFan9j~~*`<^LW;hnpBS?{C>f#Z|T>Fw||^|*O@_1u%U*u$cnzaDHU zem3pi2Q$u<|88As>Mh^w)4t-BLsdw+Y<=^W8;{}+ME5CYabI1#`1Z!k&#{tw_df0U z!1?RTw=fOajb~!Grc|?9rypGW;%8>xowJ7zI{!L!j(^pK-zQ#$mTrjM^xf7mQu}`J zPwO?GzpgOP-KTAoACTsqqqZex_u>DE#oNVhot>#P?a8yEV^hznY*Adz9@uWXevyCH zrQWOwHVpDXsbV|W?e>)aUUdA6&aJprf8%EI)|LHu&8XVPIQ80{DER|DJadKD=7c(E zd`;iw>5O82r`(x)f(X~?`cXfa!NVbMIFw$KNz`@4k}S?O%m4arw; zVr}9LRJx($e_Gv+?a84_dMC9`Ge$)Vy!tA2E>&{d#h9a~E-6KY=11&gdw4ll_Jvu^ zqZtCn`i=J}$nmm@w`wn+?`wyx`zLI4^}6PK)N_+xuIe1tX!q@lQ&rmEth$hw z<$806ud7Dmy4MR58MJ zpKvm-&hK^W_GfHuX5{%Zckj(yQe)3;`sAL(guaW6fyc_$x^S(zlQ<)4 zuV4cA=gQ5Dy-6)@%Y3JEDXQAC&Hu5H&B^1XXZytabBhdS7f$WEs5@IFD*jKNgo>+t$T-Im4k&IirA-saEB zSrT}Cf|S!5>)d;j7fV~_E@o+WSfB5f{gavDz@a~~Jvp~KUvi5l-xRv#rE6?+@WZVy zJPZl{{C-_plP%{ox8P&7j9o5+>ea_5=g-(xr`W=GZb2EpofC^Ri}s}rt!#6#w z;1A#Jzj!SBVNg2f#HW-SpY$|*I`8jfvzcF#7|DKU~e{|QpzOD1|`5R|7ZQmL(FL&W6t+#YJ_x}A#))hBJX9PtRg!Po)d*PLT z`rWH}Yk%Ku?@u^*$duoUEy^BvXtYiDP z&h*{7v_P%wTPHI(Lq%4%^LG{s{gi6=E4-Lhnm#=w?wx6&cD2!>`s#)A82MXcIp&4% zEj(iTMe7c)bM_tCAGg;^hs%~#xE4GUX!xE`z{QX}+dO$eT>qLl`%Ss&rqaT0W?_HC zZ0~-onNl&u@3MobY|Oly3$}jxWqTKBq+>zk*qPfodg?!tf0b3M8D?$qr$ z-F#JHv&7J+wE|bqwcB? z&O|dboZRlWbX`Zpt>6HYl=596nWZfz;nOb0#AU5Nu`Y@C`mP%V8@#PlZu_|QF@Jyi zZddkuIiG!{rw;dMEMtjMUnO%qTYt}^pSGFn_6sR0O-sw#|3gmboP^HC&|*=3&Zn%Y zLbuK4EPk}@v0}9M@0${X}=bbOmP`=~Pfom7vTGW2>t$C^?ekByP7Qj2czsCPn?ZLVqpQnGAdH=UA zgTvzW_M)8D7w&l7EbbS6G4t@8X^AaUQl2K9(fVfap>}(9?v`oqIOR(J9V>RdI9K;< zvy#L|kj6hBp6j<7sTMa>y*?J&(VeUS!G^X8g+$oazSaioH zhZE}`_(=zOEqrOU;>!A#pch}Oie~oNBnEpaM^`7?v2JtsyQ*el#iLxcqi*^hrG5DZ z(eqpORR^qpcUh0@pkuv!#NBq5un-UXl zA4sqzf3e-ss#GSTMQE=(41-dD&w2lI#4s zlP;fD*UUBCy(HCn+1x<)^8VfH#h>TzUhkW1_n#re(_AOgjSCBHmUvYB3tHS0 zDXo&DywE#=L-B&iUZe7T-xZI@%ARF&_`$QO=NFaC z6g09nV(X3T^m2MqS;X(v;Qyw|U}y89c>)WMo(VmacuigX`JPW(D_>t0R?;jD>bbAt zynIUCiG&S@@RS0b#2kM~&`>!cL#gHsxk; zO#H#FzQaFVdrL2qnb%jv0NWkkf4{h4cjjEomkr9s4Nuk_-JE{!(1m5YizaUa2taba+cws+(?yl3D6-kZaf|0b9;@;|9+s6-EUWb&Q<`n<^Zq3iSo#BU%bDB^0ZV>R~?E3m>Z^XHaYd@bh zEeK+5NMhT(x;dcq?X92fTDn)iooWh@$aY#Ea;5d#={ILwdHQp@zP4;?%xFH?zP*O) z{=?7Lr)Xb0`F7Tt4znh06^5>xwn_A<+RdG6j2w#uMqdP%O4 z%ND&k@l3(1@5s%Re7Zbm3Qs}4?X!Da`-84_eS2B*s!seR`y6qu!?t27+x$$|PKo~Z ziaA@(Zm;O9se(>xjL)wK@z0pMEwI1RDN$+0qxeIU9dIrB=7cXt z!)sTmr+<6v$u*rN#+TOh_3sg9R6chgQu}(Z(X{0ZwvqN+ca+&2G`?P83KDpw*0HH^ zdC`w06D+2+9CO~~*2r_+IcUm79*2$-&DVQx982q2UXuIxT1DxPm$6%%cW)4vx+d%-b1VY1)!w_7H4NI9+ZHG3MbwRg5prNh6>A4glQ zMN6`FC(Kx`$RJSv#&?T|z^h5mAHTHN_H4mq7R9tkgJ`xD%fiEcFJJyp_?CG{8UOAl zoF7?!Ce^v2uZ$tl;3HMSCuKA#7X=OQe zv9|1M=M?AXJzrf;E?#$NdBObfh1Dv;HH&grTkYMOUK6hH$7?FPO3F=xfYsr5J_a#Q z*b&+8!EupC)+fMfO;YUVMRAfZcO4Y=vflMz%l8M)Mc-=UR-{}^oh4 zFZY=LS*B`+Tw3OX$Bh9qKX5*D3*nTvPu{ck#gQLH*B-rjn#oYsy7}bg<%WfSW^zs0 z(|6_ew1U;n(Py7E2)yqt5E-yV8u^nkFn) z)l5%lNeWo+y3CKc;pUvxH(q#lwOv!5$5Uywdr9P`MFLu!NlPWAT&_CLiYQag`L;&f zWqm#ym(vcZ{OMDw;r>|wR>fPq$rjcEOwU=k`t0;ysFY?>{ zM>TcsH;$H5BEHubUavM0dG&I`YM&1!Hx~O(aJVV!WOMYT@_FSr{uRG0kK9@CDE8HZ zJ%yE>UAK~xy+SU(+3I(T&DTxmin{8H;KaM{?(%#KVOXR%PcZvz>4Q(ZSQo}sBz^5G zICuE4!MTM?u7BMy%WhE=b4WI5!cu2}=I6yhd$T{EC`g!TyY@b7-r6;m*9&t?>)uOP zTs4XJV%uKaa?QT(`iJJ##=o3j-;-Q_abxWb8>2a|?s)7s%K8_#KL6X1sxvV>cjqnM z)pll*`bAe}wW^J!F0SYGMebWOpNg9QywhzZ+p8Rx6PE0&4={I0pLus{O3iiWq)WvY z62pSC<}ps^4b@_N55XY*C3#bMl6UQ67y?VI}4b-Ub_%rosy8XGy6uKc`Wt&P&` zEB3J-D@tDS%#}EG%GAR*i&Zh?wMEMzh68gq&ED!JU!uNwsxjN?tn+((;wxk~PZu}X zRUN$a`n5uiRK1fIJ#yRe#84C-(!AxO zKi^D@s(ku$dd!a#qJj1QHcvOokDGNPN%!!(4-3ymuj1ZtkCvtY77)bB~hCRlEFHrRb&4zq%<^J4oN9e;-xx3*?y-xq$>rI*s)pCeo- zP?X#AYG%%tTU)c^&b!NZ#R!QW<5HATe5s|h>``5Aa3RM}DJ34Kmk$>&;kvlu8K0H$ z#d=O}<740Ld1`<9D78$PqV6fcbz|E7Z%Gdp>(4)UV_&=D*M&jpdsq4_v&j6y`|!=o z?FIjx`j==H^%6H$C{*E_d{%asI-K;`|yjO}FeQy7u;^-J(?G#pi34qvn5aFuv_t((ppH z%1&#u<$BOMh;v0ePFq8MAJX<;@p+f$*S2i)Lw$d~iKcgFJ`8Sq!LVWJdi|@jU)MTU zd_Oy%$sr}O&w_*XQ|p{RlN_2E9{BC?Zs^_1wldt!a>sUynd_G8Uo_nJKM|B_udnk> zINm3_%FtS{FH>qp>drEent$JK#s#_3~GPy$<&oFKMo_)7+PY`W8KZ{__lvK$4iw z<+zpWK{MsQZZ3LP>2x=D^QOJ>3!i7cVSJ$YO~qZmmapfR?Y5c6KMVQ@^mv?}5~6tH z+QkR$%Ob1h%d~#wEv{|4^PWl!boIY-060>%N!V>pyQTI=}b9-;}Ba#}26Xu00!5GdJAwnK0La+pF&h z7X3f8abm9ZMvHpk?$73{GwWtun;L&uKr5X)ql>}r%nCq*RrU)ZF}33+Lh4vnz1$ar1Fz% zy{jYkY`&BF<4J=+dP3N0CyuqI`m1thRA#vrpYDoaoPX}Y(<29Mzsnw<>Ye|2&-F)~ zk~YuFZ+%|rS3l$GsU@!?g_TlopML#Qz*gdr?!Cxk;DM+|>Auedaw<}S#UDP-{;C4P z)BQjB#bxizJs;`{k?znrN%`9{E}^N!@!n^~1ytS2`{ORj!+ zecFT>%+f-3XQ!ranRWJv(HbTvCcOuDESnOUCo7n2`_AYyx3;p^S)=#em$sHe%UL)$ z1+S5n6+h(h%`|#zNgA&Y3 zb2)tDE9TB-)-+zmyC!($IWw0@i5fLe7R`6@?hBH!Ep1N;I^nSQo#yvBx1DU`XIxD< z5#=k;z0?1@=lRd}AG_wo3)Y;O);RSjYjuuN@F&ITd}4J5&rT-D-~QbYWqpnJ#}fHP zUFnW)C%1?!mRX-N_u%nXw^;$}GBj??HIz?_+%SXnT;!_I4-Xl-s%MugyRj}jcd-5Q zwCW1$+NxMfiv2n3cH5LMTgpWOguLF$8kX2@6o@R_sN}fRt8$Gj zsHBilldCqGB01A}gIDf4ZEh(H zux4j?OVEq0QD=VmPn@&vg`v_pOAf_6+lBAzUaGoI<@t2vvVWP3opt&B{?*g(_x|~R zW{++4zk6Mc{Na`tUz^{1^8ah!+I zpNnwq-m>r8j=Uo(+{V-Iq&$hO{{G<66YCr0Ka}Tv*O6vpdsRAHv*GoFo?Nzn|8DuN zL{ z_;0auBwv+va%%^9tH`$OVw4wqd-JPJOHfR_l*G?TR-9MoOj={}WOu~Qx95BrtSplC zT0k>RH-h)ydKh4~yZn7s@zRo|n#XLN_DmH0^W}Yg!r|u!9)GKL4vOpQ+kGyk#fU5bJTwBJ1aGft+uTf;rQ9PciUmTxPY71JQj?LTmJC* zUSIff*XHzyt8cHzT{|dwc;0V6h6>A~J0AZeP1jBNa`~G5`}23o4*4)#*=^%mSJ8Q2 zbwTP*wr4#D``+D4IlMgO#fcA+vbUe#vUc2mx?#^F#tBC&AAPfV*ZK9Vfh-5(fj4Jd zLCd|Y%jL^7DlJNGU%O)`z38(HKx4kOKdT%`6MxM-Rlb`d!6MJzDul4 zm6EXkVHgp1dMCf&x{V1Of=q?)8s=5kJ%4aS&-nD*qRn#z(j%EV`Su?D@8Yy7W>wf8 zwIg}K{3T9$69pP>xBhoN_`>?A(Yp$}jO+K<53DJ>yKci-xlPs$ENiwlte&oZ*OzmB z+`J<%ZrF+2MH(&q+a2g^yCBVN>8!asJ3ymX-CJyp@&%29PVZYdGrie#e)n-7;Vmb+ z{_t|mkKkB(Cg`h!Q8c98u{WR3Nv*&1cU_lY>p|DPzObp;*;q|e_At^Es>HH z{@v91!P{qMXXM6c^L4vs_HM1RcPsN_dG(=-`%|@}U6cxwmrSN~aHSpVdlU8=hJ?~o z&SS5-^jVZeBUjh^N^<|Sc3xGQp55dlc8j~rx#OvJ>7ig3ox*KXkGZi{q(tZ2_dGM) zRLrz>*ISMp*}LzirHJwf`Uv(2o+-TB<<_Wk{pQQ!lOH@e7j9q^X5T#R;7u)y=+F-@ zm1^F2wBJnD|MY`n>56qzTqH_TeynkS$k(I8u8H(##ERo3P=hjnd|0 zcSW7`gr3NE?5lYf^yBL`u^6RgoCh~KX>9SH(xafM?OW8Ft%=QOX)S3kY$npl?oY)jGCPfNT{ zX(?_o3)?nHZ~lBnyFE*IWxe%x9#TGJ*w?GQ=B;Say?Kml80=QQv0TjYEaee!TL@c#H?e~a(=6{by3Gv2cNh?!Y+-1x7Y*wc>8ii2%y_DTq7AKNf%_1g*V=RR}J zZtHLDzr*lIqwJ!8KAfzuY40bCzZ0^Y zW*@UTFn7*@jkOXIQaykBZfs4c`zS8HtMaLB&fU@ze{J(zV)zaVIUDV4ToLDZeC_w; zYMh~GjBMncG=H_5d3rO?x%$eGUtv*Z*`Woq7o1Q!^X&WW9@lS&hep8l9H ztxEQkTj9-4cgN3ZR_u0D1-A5T>t35FW#a2C)1f?N+uRgC0lNm7>E13*@4Y$QUlneU zndmy>xpL0!{r{znpBY%&wpPV|X`A>d>&KCUA`?xvgo$R(^F>|MC(SJ;}fge z%eOadv+bgm^QDIkosth7-B7zF!=+Kg>{10@6|Jd z6s!5~Z+*Jd^~|}L1D`G}s@}NxF}tm&chbaFHfkXvPKSQKlB=mW#F#Q)Pp_&@gfZ*w zVvYu$!*`w9Bh^+!Oqlhkn6s2?M&Q|*%fyqNO;}6{KPWGX#%Lxgp?l!eMV;e$CZ;abIr)t21?< z@3Z;0y5jfM{frD}?q>O)Jb%}!^)SC&sp6B!1+VTTsP&%^?<We@4S=S{dR7x;Tn=c=6oOb`m z+xX+l>%W^D);?Th!ePqFaAV_h4Uj80=m^h>YtKB>_)+TIzK`V-3sXYoXsTPaHl552 zSoQt5SX$KX=8jmVN%DRZ1-d-GpWmaoRJ_6Ea?R#Um7b_gueEzq17A8iZ~Qn(_^4J@ zwI>fFYyZkTO?SD>aNQGTRrlTN1*dFTaJ@ZoX4~7pOgp~)lhzY%srgl2FU;`aZN5!7 zk3*tSc{ShS$9;kVcV%NPWzYWjZT0!&l;eHhJSsiv0xrD|T>QRa?_2$arU7d=^0AAa zwwfQpve1B4_g(ExRW%nT<<6qHx1Ja0wHNuc2~4z!+$k)8<+c4)XCp7>M5_Q z;@W&Uc!$~7Wxnyxm-+AgGF{^4M&@NZdoF%#&O0=zVS>#J(Q5+#8egC2UKZQ;-!hun zpqP(cZBFz&*Kyb0L18Q=EwQvDqds z-zVBXKDOvjyIA2qJ=wy?F|G$6?@lY{l@od>oSOXU$;3H18gFixOgG$=%7Qy}0P0 zG3}U!`*Hpz0o{VfMarG?6GPY-*4kZ>(^fELogd9E%Bv{)YO8!^Y>)G+;@_WJ7zxr>~mHwTRQ83^%_>}(2j$ikc z)RXxv_Hvg96nV+!9VZ-wqGJ5q7q?wa=EWSMPol{*o z`}ec>|Gnu<@*g(F|5E+)quu_9yPR#8bh!P2ZF9f>U|S$DP5k+7Dw zF(0=-J#E>O#Vb5zSr?lm%{-}Ud+Az;pn?|D!al2#eZNnIxzA{vu*2uYzB_Mc{QL7` zL)+%5lcIa93^ICdlxo5zwJc3+3li8)A(Cm0+Z8n|9zd+|1Q3J*D7^PRzp)`?YD$Qb{mZA=5!hh6l}N_^C(?( z@3gJzsdgS!3EM^7{pQzPzS(!O?fg#T_q!Olgl8&#uYbhGW6blM;fc=6-}Z&d-<0_N zg>SoER`959j`e4~yqK+jSGN0s#uY!W-?+t~{pr%ByqWvIF1#CSyFYoJaQcI3f{_!v zzUHo6+naaIF)A+V(4|8%`~IKZf6Q53?%RRq503nmQ*-G&BQn!eui@3cfS*6s>pbX= z|6!aXd$-Tp+@7cA!9;g?$Gz+2h^L>Qo2xYJ`}6)^X!v>k z;4@EGf7|$pam}+_>pu_w-8Jicb-Pq=`uX|CzwiHfU9Y0<&tCD^^ULpD?^o`(6S8=I z?kxYt(h}=^KU(b%e~kZVwCskl3~v$ z^ZUoO>p%bHy&n1hX?A^UzfG0M`#)bo!q4dk|6*@qe)QF?;K0BCe-6!G^SkcviN)?8 zl!uY8_fmOJ^s$XvIxGQ#-&Ev2*b6V?B{eWD2*0m#!BuI|46(_ICGS`8E|_@u zY>0r=it87jOK6-<+!%F-fr0l7=v;uA`j^93dvm>)UHDulw%s6(Z`&;g-iv)3WQuqd z<}iGn)8*GaH-4*$;{guV#=X(%%mMc~1S8hgPM-6jB8x*H)3a)Z>>ZQTXyN#1D*bTwFH&&D;G{&aNjw-=o5bq2Q_RZB_Xzhl{m!(n77w6l_{{ z-P=}oILE&4$^PzGJB#NpCW{?e+h!6Mf1=5F43ybU0&owu7 zshe?X&H4YQvN_Q+%4XNfg^3eXs;3uzn^ht^^E`j%albFIm+l|lw%6;@(a^&M>jUlV zy`CSvzj});!v&>H>!$nMPAjwBA;2Xs>9F4VXMak;9}PBf|Bvl+9p7kha0&*0$#(Q{ z*Ziudf7d|u@rh#H%Jb&6)~YY2r2W$Q|MPUu!)J?v@4K>>@qTNc7J1^w67^oWV=s%Q{9C^F*oN<| zH#27yc%PV;T)gqlhr{d)Cl0J*KQNQE_Cem4`*lZKC-5vXILWlo&r_zwY*k9;oK0`S=n;^AKz|?om(FC30%0v(BbB|l8-NIedXmhrz%>m zIdU>)>n*w(#rm);lF5m~Vl#u6<5nq$R~NFZ&P=t8IP1FGK=h)+7pac0_G|Vmc@hh% z?)sg+z;NiT)v>CziQ=vXz6EJFA1u8S*P0vo;0#l_kZng8^UCjz@1@xiWfoX@_%d(S z5lCwcknPD*2;*iE>6!8EuMxMwY=ha}50)jySFDDWzz ziiKTWWNVasMlwfFaY5RRZKE59+dAi~1JYo{}dSvwZWR+g$vIyD(95=f_JR}4FSJ@naH|GGhAS5Dg_{L( z=PFmt|GQu_Pr>Dmo%~6+Cj}q7vd>Q2g?;I#Et}phxyXA-?|-8G7D)?Z#}#Z=8$@R< zI~=o*HBV|okLsGZ*>76qwxt&QS)9jlOqcnN(QSXlk1l1CCURUoY#ktQKe)`HNvv?6 z(S-R)(=Vt@sgkyT*2%ldnk#MkbCKs=ug~2RDtaC$t#D>iPw}TjY8rl{nXgd+gs?JL{FA)a9UAYk$wN{N*U)VPqVcE^E8l zR!T02rEkmo$V_5xC z`ycyn_W%Eh_58niu5R+0lH=pKSNquS^nHil&#jpDquy`t-|aK1e&@^T7r55FZF+jI zGu`t>x=QWy*5${Q|8M{QGxKV-*OWDdCq@38eo*oMO!<$g-It%-P`7{jum0B`{|f84 zx9Zh>f4p8)Ca(Wml*PZ{aq)cKy?s}w#|JP3ElQE~c=Teyhl~_|w>|f^=Fj1N;WPg~ zr@Z|K3BmUJ%t8yN@yNfvUu!4S;J&;eJO1CSSBk1$W?Bt?b>F)sZreX}I${5;`2CU1 zPwsW5cQ){6>sp2W%H==tKd$f}$OrlMpLJeZe+)iaf^Ssl3({2ln z*orEdTJ?ENb=hKK&o}IlS|7G3#kNz9f4(KVUh%vMXY6n6DgK`LNT2cePp=n0`Xp{= z-kHV7kg+|jLD>HxQyfQ(`~A-4cfNDJJZ7}#|5yJ1Cu;xZ|NGHD<(fudkZMEU|69)s zKkYtnALj%?dg+OIhWTJ(-N2bTiwCKzLRUUU+vFq2|J^{ zhxHq-^R3UD$L?n%T9N;FS?rCvch9FAeE(+B*59-E{gD~3OjW(E88_S#_@%_KL%?YE zc1DKHm!JQ5@xxKv0K@>r){phIa_{H= z*4zI-U$O_g+#^^;*R=f!~RRq3o^nb7S#)hj09Ip3tbmwv6+oy5|Sa zrVAe?7M_32?SAWj@K1ZMDLD!ZKljf5e!hmC!C+hcq5oz{)%NK|u?_cUTW&orSHmZ4 zsJh;zbJADEiJc9>`TuoY)Hbuomut43XcDt@c>CeC&jXwNF%?xd*CuzKYFcN-{Hy+- z{Qn)YWq;Ft|6Xr*o$db5o8N5i@UPo`eC@w4+VzXJcy>3JH%I3~_S#~O)#n8&)JlyOa3nB`Yqg56|@2ushBq~+-CmN?9!6JWW!{3y#DQHP_{MPR?oEl z?}KQIZzug9J}DQR*f3k2CGGS8`##mF(ns^THwFNyl4eMf0=VQ*X~Gi}=RODi2P)EQ zk0V;&Z@w&E$Q_tkur#*iReZuM71sxgT{4xm8Z&|;0PuZs#_-JBC^|O87n)8ny zQqMXYA+>Xw!D7+vX+E7os;>ncK0UfLlRI7Lq4BnQCeMd61u6?)zB;Y1a%lPcBf%D1 z-AktksY)xcFh6*gqp0t}tG)5!ImRfDGk*n@%C=1qU(z=9#su*t(wiof!e*V7ymy~YkNj-=lc5JoB!Xc{rl?k+x`2CKIwkn zYWBtLxAFc@_L{xHi&QurivF#Om>?yVc9J{jvWfyzgWB4B|J}-M%Y+1`YTUG7m^F9a zClv)R?jYMq>Wqc&=9b%Xc6f3JF@h5G$tuzFM|xsA-b_$u42+YMSIvA-oaJx*`{#?0 z-{lioWjWV0adsqrTL1s-^E=o1?LIB|UG@Chw}$U`YIZ;SddSxN?sev8tA1B)jVq4- z|Drm7`@_nowco!^|Nn;D>+}>2&&Q0dstU^_W5PH)yryVqs05`xwYK{!57eHmu)dO|vnAX3n*EJu`^=`_FOB~%AOGk6 zlr+u2Nlq)Wm{h%{XfS97E^=v2khYfj{r*( zz#zrIz#z@Qz#zlGz#zxKz@W&$z#z}Sz@Wguz@Wsyz@Wy!z@W^)z@Wmwz@W;&z@W~+ zz@W{*z@Wjvz@W*%z@Wvzz@Wpxz+lM0z@P_BZ~6=j3W= z3}#Sya|Q+m3n+U?MF^c88^n;$kk3%UpuphDkjGHMP{dFP%gRL2VhpVCJP%4o_%tQV zxn(HReSr~FW;6ssR2nguGMF*MGng?LFeEdWGFULAF{Ck=GMF+LGng_YGFUQLFjz2v zViTesoz!ArVgv;lC_RE`ba`C-NN7O@vpV8B!V2 zz^NO%6F~NZ@)IcE5^FywFSkSe528R$0mTU{|AWeNP#FNr|Ddt}R0e?j2+RKwmq50V4r ze^7YY#10AY#A6B z0vH$=>=_ss92giF92poGoER7woEaDxT%hHJ8v_G_I|BoQ2Ll6xCj$e67Xt%>H&o7- zfq}t~fq}sv$_Kdtgo7Cv7(y5r7(y8s7{VAB7{a0QkqitBQ49F$@e0u~6}N z1_p)%1_p*i1_p*C1_p*?sCX&^149}E14B9k149M_14AZMJez@mA%}s1A(w%HA&-H9 zAs;GU$iTo*#K6E%%)r1|8mL?y0|P@n0|P?? z0|NsnjzDqm2ucVH3=DA>lA4~%zUJ=?@N?(ok^)6NucwDg5VXh_-~c6F`Op7B?q)0w za(7}_cTVOdsPag6^mSxl*x1kgClQnwUwgVZhFJI~OIRr=G(5EDaNb#PfMe-KrWD@S z*NdB99yqX`N7_u`OQJ->%9q>%-y41kTxdw*m~mhoC(8s=CFT~z9)+{DwLCmsT_^4x zUbk`YUXfEx4Y{`^BqAJmCOrH7U9z#nJc3D5A-k)i!DsoNPR~7SF$dJ;j;JbFay+b7rk9!{j zv)~a1)|7GqmxrnIw)0e}2jqHNd=op>l+k2#kl|dTB$H7?@n(iL-vBi>hlvc5pPuoy z^!i^;VB+CnU|AKFB4vB+Cj%(Kxca%Qb4q9ev5CO2@c#h~|ENX(L_f~pZ=*E)85cpq z|L(-Q-jf4mj@zf7pJ$uv;c<4(vpqr!ci&~X*Bbth`L5_peaC=jJg*kbK7OceCP$K( z>;H!BT>@nje>9cHuIXMR=Cj0h>#a3wUzYG&pF6yHWBb+GFP1X<=G^~TyMK=Ozg)T5 zk3U5uKkJG5&)L7&bk*6(%QW5B^BAVu1t``#TdZ0!t99D+#o_Fpx_i|UZ?0J)%yQf5 z(Y?R7v-ZoaU#!<6@Z^!a=jEgM`@;KvI$nLfK8QDaN0U>=jf||6*-@4seueJjxm31H zD`W+$O_#5SZNP-M|NFjFX#HM3>x5vM^~_}kXXy>jg%2{1smw+9XO7u|j0Y|nASwaad9 zZ}@wIeJV5S<%%m~x|8$z?o6$k?)WaHVbc}EPiFhp>)xn-Uuk81_rm=T-2Ts&xo8%4 z2%axe`p5hBvYyiCnSIZ`v3;&*lwr*L)OR)Q;6YF}W$+{|*}zj4EdAs|)6dex_3MP& zt$8R;Ka!C2le|F0z$tT*Lw@b&|N9-*n&;h3PiX2AWVJc#^8Y)t>Fv(nh8DLY3~Z`@ zHdHV>%*wUZmMl5)NODTDp5dO#qMnEH!pfO?KhFQ@Z#?~i^YBdeeu-aUG6^@frt>QY zCO&xd=+J>*FCWzxK6PkIfB%lz`JMgY#o5Ot^K5>3-C&rJ#_p`x_Vf092Up1hvm8z0 zm=k6_Rke`hi>ctg-ojJR#<=P14wGhvFvp~vHpVr23dhnU91Iymt}F0tk`zg(6usNC zY}vAa$Ttjm4h{^5>&sSN=P{V=IBQ{03!{fIOTqu`8xw!5S3Le#KE+t^wqt|f3Q3lK z#gBe3IgC&C@Lkfc>xFux7kjRk4kOpp-fgOv50JT3r?G6~mq69+-)IU&w z`WI$@DuXeDB|{>E5ra8{Awv>FB0~xTs7(ZFlO=;|NDO1Z0wDWA?Fvx)1LOv00|ql_D1h8%0d4_;YG>?*g6s$NkwA4QvG#-dJPXk52ictp zZuNoMy-DC0NMR`nbJG72n=ShKLC-*uk(wGR@e-IAn$e!=*bj*Zqrk?vtM5;_K^s za7G5hC63EJ?gtJqFf5EtJyLP#5~z7dba@ENKV?w=Fl5+NP71D0p)~(6DnRoOxcr;r z;5+NF{gjghuV3=>e6`?h$lPN7fc>-Mg9oks5^V_*4eLIBy1Sld*Qq-RW*iHonbH$B z3$i${9bh=4km4+{G1Fzc=zPTl<}VFRO?z|_I3*m+S!5fYyx;rd^RGjL9X{j+X03%VI{rm?f$g6D9>PLJ<%p(S0karR;0zTAiIT8 zgpcC@Ph%zHbT^3uS{z0!r;eaCdYeCkwtW6<15~|G%a<{(O<+k0$Mp$8(Jm+x}be@MvwcZ}8e@U|^KQ*4^FB&HQ?K z_y40)nI-4#-ObOl^FL4jI@$CcA75yTUCm&4Q6lj5{=tBb#DCw^6AT3yGTAOx@G{&y zQ~K{ueW;&b+ghLZ4`)qaJZI35`AtYD>BhHrvK}0(QzKX>=CWn(`}bDbZ+cQGqsD;* zv&WZtm^9cL9!a%;+B9l^YK~2~efe-kRut&r~;Cjm}e$VJhXvyQP zlA;Wz%?#h$|NocN$@!OkqVPZaO`j8G1{@p=LJrI=`Rjk_*KB9ZVQ^`)IKW|)aF|=g zSG{k-gAz72h8E|h`3)CNyJAEwsEz}TzgRFBFo5b{bA}XfeGeLcNn`Q2hsrdQja1!k8*BML^?rH$j?^#y;_?w7$FQAP5OprKWOv?)baqe0xTJfz^+LGw@Hi`jKL#|*i8l54;q&M zjj0f8za0Yu!v-|_L2Vy11|tRw1~UdwTf~IHn8A!8k->z)kO34o*lkDD|DZaZSo=Y# z0M`D1<==x)_e{KTp0D?Q-Z_f%Z#GK)J#ggJvH$fmW=O8PUvuODi>NY}hIQrt`9W8I z+;7(IJb3lejE6T@TOW~TxHKo{<-rB#q7E(y*xLH=`0Ben`z8Min=vdAJeBg}_^0;9 z(~orypA0vbcojA$`NrOQdu7aQyoina1cU3c`90tNZ~VVqcw&0RpNDJ)PyQLtsroSO z;pMa58LKuj%-|03)sgJWjbRmIW}J|wA#7eySeW=hSnOZE)XabL{bTvxiKaAM7MYN? z?(_5i)tsD$J~h9lJY2bkD}?Q8*&4P3Caa5zjB={K_dWczJ>Nq2kQDa<2IiYS9>yFC zBpA311jK}{;{P_jv4<9Iay;_%f_Ahm|QoFJZcV1pz?kJKcAi!YgaO26h`iDPu|F@LL+2AJb z$6&;;gtKkoAz1v~gT~)uwbvKRzDK819Dg0i@wX?TOxE5x>$1B>e`8`&>Er+QK4*BY z=i4PEG<7{>Q8@c-+N1xDZ@h0`{pY_j>(BdxQ;$5z$~^Po%~jb$Yz-!_EAJ(-WZo-M zneI4uYm?)`Ebhbo;kza4jQ^?UF!0Q=`8VmI{AqbMz5dNS>hX6IRzw%}C4T?+w@0V^ zREy-l*9HbFj{IZL`hDoYi4G|pgFS$g5zu_q-o00*~ zfq(v=FH()UpnuAX(Pjl2Zxv2E!rv0dB6k~ zu?MfblMZQXJa~;qX6=sHhMdpa%HK<@tN-10S!vBifxJ?w9Am|^3JpmNC*l=&daB!! zPi>bhs;-jo_4Qr2=?3GS1_rja|Iv*nMMZAe3g;U}{O~=TZOqdk+Gw)=KYx#|oE+Qj z_3@HZY$PPs?KfpTJ=d;Q%H<&&qXR7dW&3Jb2-_``FBkpB_90zz0EEi-ckUYfk z_<%_x!=_`84kc)CEAc%(yocG$p)!(ZJ`?sh6!=d%| z=NIbuG^~+aBG|Hg?Yi_2yv2haJY$WKN@Q5Aa6&*sc)6PvBO4n-*v~cb zfvWr3KxHqk7A`FQVC~n#^UsAoi*#B-as0vCua*{jeO}meeD2iv)6TV!!A+x=F+oa2 z4s_)dx&E`rirdVEkdy#GvOqBSGrB->;V7Y#3~$E&$8$N!!n6j$5*VA90kQJfQ{I)nET4^vOE z%gzHmbKb{jKzk$h`}QzK^QrBskd!!Ow|Li+4-XG3Xl@90WQbMfSy14>kj8O_dxyy( zhA_toiUDeVy&<4s*oK?SWBtBXgQgrv?mu1tMKS{e!}Vh;!XFtFOr|vc7^4@_D( zy&kjvPvdCLT%edROM{`1_0Tu#)I$-x2VOV*{w}!fd0bk`jeUQ4XY}%Pd}6xE@PxPK zoH`c+uVVb?00tf&hBs4f?{gNcybkgbu5=5M17TSEFO>l_+5>8Dq%jyWBr}*Zq%l~6 z$9~KiEQy$Z1GPOs7-S|P?8Cso0PZ#-wf{gPFGk>&rzL|ig9Sq>c=jumA(g=#Jim*} zObrGm`1~WW_Jbxf>KP#>!u$_vd4bx#2GCi*6mY8()b<0l!tjs(fb0d$M}cUFsrbnV z&|D0f{h)cjWQIg=n-4St3L1qnU@&JeX8^eY)MCYMrWOMecpe=zcTTMRaY**xRbbBJ zX8*HaJLdC!wi9h$f~*pbYA=CRCI1zEeYshjV0ZDr zWuGth9-pWC7yjRW|Lc$WIV--*=hSi+XfO%4_-Qobdm=^IiFdjSo zUh>APexsB#DG4*G|H&bbT&LG%w!O}`YdqSwul8iYk*bbOjOK=&Ux&Mzv>lDK^ zo<$#}7%uDRA3Ry`;864qwUh>9o(Z|fmP)d0;1WtU=1C}JG&DQR(8ai52V3HVvkMqb zuYQpRZ!a=2N&MUFy*I7lCeJ0FsY*N!vlJVC@9*V3T+eIy?!Urp&YOHpJq~9TKJ2&l zn9=x=i`n_m#_c@reFF1O9$?#3d6?l`tb#*V8XFrM8^g5Rx;HIxKS48|h=_!Re+o4G z%MUA*)F`H(r#SriP{QBg>^j^3j$b-on@h|%pya~jZ+!8;!r56lvv`VPqIr{K zKK_6IqH4ot#|NKpN%EM>)vD$&_-t-oC~)}CTmJ=%coNPkNUdiyIQvOx4iCHDp4Mz9 zHjBdyH`8KfIWnwP0EK#(xInTo&jJaCu51Cen><___H^aB1qTPO&?#du2hUsXzLL#0 z@f0iFr$1^GD5|8ez0?c-;d+_E8km?_p{mBfV z8K`6iL-0Brklm@^xfl}$(3lWtB?mU!A>$vQ1|Minhgkcwu-Fe;X9HSo1HzycKNjG1 zIH1ud(E20%^*?Bl1ZceqvGx}*Ffi0Y%UhWLLF>Jfl=)2BgtQeRi42!`81MYg&5=M1JqjeSWU)2=zw3C2rzc!OLa1+Vszp)D4<9zO z2WO?(3f?g>2ALQe7#J`xY;vx3>AR2*Zpgrz2p~V9=f9iD%k?kHcKT2||J8lC1FHXL z1|#LaG;=#uw#W8dJm>G-QvuaKrZ@T69{LyYys!VCTJiaTJUIUyc-;SA^4gsLrwv}_ zX&-LZXP4;YVip${XS?Pv{=dFPlBLXyqkv;>8fb(#5j3UB(<<>Szn)1nl_486INXpq zZTf>0i-L!`F~UX%B-u`wJ-)=l6v5iLQIc)Lt_DyxJjxId(`;}eEui6PXo>NxS+kr{ zH!|;FWMt&|e{*S^@qrw+%r-AUHifeS2mana*7k6Jo6Pt631?e!*csgxqzU}EFROCq zKt*e#;=>!!ZOZN)=Tj1x@9jxsc&;a);A+gw%*@OXpwN(;Xnzi6i3(_q3M~9nq3Pif zLvUN@*QL!Ahd)0`{eR%K_RRl|Ca15PB8R_VZW)_kr#er${9jP`KXd);B;m5!aBWC&1&W;IY%xDt^c^4xi1_CkPzgR{q|>DMI(KR!5Gp$LFv4_X~E3tmcle zk8Qc#;}0HH?aCGa<)s-PK1(|1`SU|dDhG)NvLEVquP|lS*uo!Eae6}d#op^_Aq-b| znC{3oa2`DL43S@&8yFNAO&orFTlN1?x%2@xhm;QH9tCEzJr0*j9&vE`r6({jxR+K> zjj`FW1XMgB7gZoW28PAobZGpkYWYRXy*&9n#qsBe5`PZVEWae*PvJEFb3HL3pz|-R z{z(J(JV9$wlNnOM>u^DALk2VO3Ix!M4Tjgj0-*XIRPVqrSdaiw%fP^}9vWUS`%@WA zz^h(Cz3n7$-D|>N!H@{H-3b5sTax?#Em-U~WH1D;IZ1@hxqw#Ug66pT=89*Ztppg*JS{%^4k1+!%UQ!r9t3pxDfbqx)|4B&p zH!?6Vfa-x}=-SX$1_lPufM+`c149P`14AbR149>7u7`nvp%=7vhJk^hpMim40s{lX zM5x?k1_p*H3=9lY85kI*F)%PpXJBBM0hOD@z`y`1_vSD#FwA9OV3^0iz%U;ww~&E> zVG#oZ!(s*o22hS$%D}*|4Aee>%CBT#U|7Y#z_6Nufnf~;1H)Pd28MMY_e143GB7ZJ z#vL{@FfeRkU|`tFz`(E#Dz}4yfng^D1H&!`28P`X3=Df17#Q|4Ffiy3=Cfw7#NN-Ffg28U|=}Oz`$^dfq~&P0|Ubu1_p++P`&3F z7#Kifh8Gza7%nj|FkEI}V7LO61FZ}L4ZhuAU|_h(z`$^efq~&R0|UbysQf(!28R0# z3=9t#7#KhsZyqr)Fg#{pV0Z$Rf5yPT@Ekfu23lGRnvj3Zz`*bZD*ujwf#E#^1H%Uf z28NFe3=E$b7#Kc73P$iToj zf2@Ydt|A?DPgMrQ1B0YX06fpQCs56;nXN!JK2uC0QV?&C}im zMm|4&_9$*&-hT1Q6%nm&Sp}XCd_VTbUYW%xa*JJWPwI))FOFp!YcXW8F}~yf|KB*` z2BPDgARxe?(!j=XKkjS%k38lZ3>`d$4T32L+QdC(`N=3Ae96PZARpS;?U=0yYVD(R zxj{aMWAyS{u*>Ge{_kx))GoiN+5h|KH`Cy7y(}Bs)En{+FZFqPdS)Da1Y1hE&ma>t zB64-zbWo4{=prdz2DF-3;VfuaL}B*MbMybNKXvlthN&-YAx%?*vvE#NJh$)dW#&xW z%ClNw(^-YH*Z0>Rei^hzkAYRM~0)I#_9&p;;@$a=OvKlzz#9IZ}@-Pb*-es z!rBLiqTBX#X zqeojCzg|B2pP!ZI;5jzNZ{gP^@@#%}xtdBbSjoElEjJKJnz8>cX9N$6!z|EJSO>G> zx%U6#r%s-nsC~H_GOm~~Yi~=7#J0WF>_UgKB*Pq2W;@PWU;n%9^3sS{1}=jcXMdP9 zLq{4xV*;G^^9`ST`(gm?aI`SqWBk9pJIc7h>Gy%w?VweB6}fJ#4rdh({C)Vpo{f9< zf2pE7{~gVQH_7raF*UGUV0d_Y^*`?WxeU?_6BYRkns{z}VDh}&sjOl#w~>+I(9(KO z4t;4*=}toYed(0gZZlJ!%JJv$_S)6|j$c-4Pe&eql)4kfv+2(?p7-zVl|cQ!$-gpr zlB$;B8h_M#m0)3-tcbee06qTxHyIx|$JXe7`iZ7zwStbl6Rvo|ICukfosQ)dz zL4u>fq&Z^`TSLw>tNMTYwba!Qhb{YF;Cq50T>>&4om2gtPo?Fm(VC_cX3Zw?|G)7r z_ujaRK_tOo_Qy;%MiFL*Lf%85F-_q*yJV!*1su$KnE&OAZ%t!p{np5xFZoGp*T-8u zTn)1v8-5@D|DQ+9?7!)g9siqi)KaV^SXdZ17cd^$9{yK+-)#mn1|?^i1Qy8+4_PNI z6L$9~uwrIrxPHIxrs4GSpxTRY{LO;4=dM{8#Wm9sMP0T@F8K*sAQIbkm309_^G))*GXMUkZ`kk?zFz&Hf&zmF z1Fyioy|4CvxXZSIQ9$w$gYt<6Ui}Fsb1j^jE=x)>}ydpap zyfY5PQX~$j{SDe*2HGnI>VqIj;bblVwWToZ2d#gD?DhkVw^=ZxfLDKkb|ix4L2(%d zvLCcy8Ptv-*8UZsb|jkpDd7GOWCYL<+yeuxNCT}r1C0iPMoh800AxRCKOATeAF=jt zU|?X_549iUZqVBGD^R}2#pDw{d9A-G&cAi2`4?&Zm&+{1i;+A3>$18?#O$0bQ709b zxZ=gDw1lQpf-DMWZ#8A{yjmm5!xb7WQMc#T*$=Zn+9xtQNGdKAM^iZM$NIwu76|=jUh#yRSy_46`k0uQ17GgG-Y&@}bDsyagfoAi z!oq^pJhiP5+1= z^`D>2{Lj1Q?ZY@nHVa?IOmJ}x8mBn2++XqrukS)59*u3urVPs>L3Qx$-Q_%>rc$Qh zwFrivk}06oLI-%39%K+nty=bsS8A3OPxpKKgcDktNi|qO{(*#BZUjrUdH6hS=Yd~es=cMy}pl%0_oDWG)u=w8!jsN3&Z!Zh;2%x@rs}M^XqUPOU3OHGZqxFF#2qkJg>{vmb_mgqKr9HK_P>| zLwO1(ThH|S#v886r=FN`@_@njKelemtWyv1Y!~M={`3Dl?-7lxhX;-xW%X(PGpF{o zwevImur_s`HwlJnQ`c?hSyh-XDIvL^$?%(kq0rOc^1@G!Z}@%Ie}kLAy~=-94?i&9 ze50=Or{2^1Xnnb}@0xRmGr2s#r8=l3rDj)qN@2Mk|I|c>jk2p54bFnrklntwH+ctW zA#eAFV@xN`E6nE11Xs#|Y=^3DW%0bOj6iM_-(kpWYxo~L{eLn;>$gW+r6vCa7k|9P z!<^u%a5nzm`t%FW6BBlPy*lmSy$`yFt;OVUuK8Q87Q>Lj;33T8+}g>)!^5yNrQXu? z${JAL5N`xSq8TR%i+|XBz)BIe{l&#O<`n1uK$Q4LYkxH@=-KpN;VgRlD>puv&CoWu z?e&{@$ui?wwr*h)(85oa=E?Kl8^%1{edt3$Ap7B!lH8J!?+`;+$X(b3sVC3B&z5hz zIbVMt!(|p`!DmeSFG#eVn-#P{f+NO$-{b<8h8(eLAOFW+-2Y_%vZdBt;Ry`OH5JZ2 zk1zNye(6(EMOB7U^PWXIutlE5U8{`t?B3V=@OF1Lc#&s~mRkZW${E=XWxcB6(doZ# z_~pt|SUY+LBPdUopWDI8_qKPnnDLWizp!TMMXKh^=jWFv?7Y0(zggpsf&xQQ!-kV@ z{~!8T{=eAZMnbRN9F!QJv#M&hpk^^>R0R>^u=qOw&A*H5*zX;DyDE#=_=DBIpw&O1 zxuz8GzAMn)b4v!uek9PC6nNSOYZ?O8|Df|A0`!_%3#0%X$ycx1C1F{pr;Z* zt;3)|{s--;2c5w|to`Re<7rU;`us#2tk%yP3@tvA~ z6CSdEHs4_32(GyeE`&@=v#9*6a=6{yT;kn)%d;m+mix?j_)RIX?f?IsjS{Z9GCOwc zXvmx}U)*Q@;eyvsRN46K6gNmr_PQR;c6G;go}QlgMv3YfpCl#ze(&x|{PDkCaE)Ng z`uDdzEtnk4K1W9USwCaTR3t_?Zu{UB8W|%kK`4&HVd~PyLwp zHj1;bIPeIV?fe^W@$X$dADi@>m7L-Xk_?wv4hJMEF)}kVb%3 zE&$8_+o18O%hDV$EqzZsvH2fo{3oEqKVtr2iKKvR$hY{Gz_|x|{W~AN-CfU9T0L75 zT7Q2~w`}{q|G&|m$`AZHeis-fxM>LU$kqQjzv0=R_%_e-Xi2#m%L6!LzdSxWdB=wh za~)l#$?60l0BGBAs=}JZ%Z?v7v8iw2Vs+S{(3f6gt1)u^YnieTdf>hTXcM`WQoa6Nr}pPjZgisx6o`&A2KO0JIqRu(DG3M zZ6hu{)F_o%1B*Xc`>P`1dj)sXR|AUU54HV;SbwraazcdIm-y4s6CN&HrFb~{7(0)D z_H{!8$EO@jGoF>NS}!T_KR)fpkqQoY{IN*b8LTjzoAe{*bKAoUbE;7n=6lsACZrts zGPS##dj{LjpFbb@Cw#kp{7u3v&!w+*o3rjjFF3Y7!nCQ(g>+cpc&H_|w9$~jdcAm?}% zgU{v#TIz@Q=DwG>7YA9G&+y6kM4A(1P;yG+hE?;V4&N@-;W=w*3*Y(8VD5b2e`xG~ z35SJy%RaibrTmZCV|JJ!LeS&$^#89Vzf?*{UWWxX_2xrEdD1$^Y8ulmo~?SXI-Z_{%uk6 zFWUV3!AFrF|2xid-EvdXMP;7Bo!T#xLA&>D*X%%>e}}Zd8NV+xG`N$VU{Rf?-t758 z9jyVrA}bNv0Oz?>@$H~v+fVkV2a`aJucjGSMB3)u(b*uu;WM{rCaCe%_xcB3Z_zG$yuw&H_&w_EN78U8bk+8v{{h1Z|eU|1r_ z@@2>W|IZUPFt%HqNORiO?C8L7gduVA?fIG_ly|Dx><&$H$l=Ck@ zX3fK(J-6y7q&;3`&y%+Dyu`ZwKV5DxOi0_?x?RF?)_w0=2B^zgo7fHj|^`>hIv4bQQ5(j1K2!FI@F2esVXramYmmFOw#drVTsW zEDmoxza7h_EB`u{_OkQmqItwhFL#uic^FF+6#w7OxaqNq#6Rd@H$!PN&kkLg5C7K{ z@ZMlpArc6hE1b>C;p^Vv5yJt>@N@r9xSEu61~fH}Kf|LYCHVPCu>8-=ew_c)9IY+1 z%l`|@UcdUU@axJ{Z_rXI8-^v3hf>)i4nK1~{=eBIyCB-|#HVPZJ^TN6Y+zJ4yRU3o zkHXpIcJ_$^myJ_*oclL5(fo4y1{+7_ga<#}JH-9!_8l*n`kw3XVOLq6yeEFobq|Mtu2a;Hr3$LYh{NE}fB2gB(!U)l;D=4KOpbLUy> z*(3DBm=k7Mx`s;Li@ksB!`q{#ht9dODLh}+37&FhhZZ zqd`I;r|9?of3DvumWOd4BvY}k0<(K5rXbuC8^9u#mF zw`;h6U}^Ve&O{{vvtE~8R}bF_T|t5^CvI9tT~ug2a{t2gZ+GACEx&%aUeRsKlP?)u z)yLN#lisjzuXkikP}hc!`eFt@y>35r(h*zibB{l7L8z?rX4$M| zf`KBL`{JG_8!xk-f8uG;k!N;+8}}@Im9*F2EOFEQ_s1)i9&!y%vpl_DfP z{H2lYbc2QQ<%$oQcVBK(;INr~aeJbt#uEE4Oy6c3XYKF4e9}~Z|M$gC5slqJ{;N_i zEBD@G{lOHpWaY2_5`v($CCCW`R{zh1#{Y~Dhva`cEn=iN{@o$*4>^Acx&BwQuXqQl z|IcVb>;F3z{o-pJ-Q1qpdu*1TFVy@|p0zDKKVQgl2Kh+BfXypW>lmAZlw*XuJNvTEin9u{m$v-sSp7i16`PVzV^a~g^F`i6& z#He$?p^)#%zxiglQq3z@YPtxqH!Nocjh*`3zbiRq>Qu=F&UVHXGb_@YO`03zzW@I( z!(*0k8#WoOz{WBA&Od#bdhs-dk0_&NC(S!7zRVN@?T}+c0Dz`9U(GAk$WaH!I6BLOHSiDuv z#C)5nOZ_n!sVB3zr%#jS)_iQBc;{3Xhs>o#8jD^|e_yE{`K*7M-3M#A{l}kI_m{WV zCzhK&2+@_(YFqHR1lImCWk>|CK(k~3&A=rxBr$+SqCn>mf##s_uYZTNy+Aa9-~vm3 z#WMb94z>~0?n(o%f-?i3LjhWU4;mQ+o$?6Qia~(Jzd-iFFopsw0)Ij4rl9#1=6}#` z1JFDlZ0rrR_YSlI(U`%20Tc>Yi~$S5><68F333BikO0BT$iM(Qe+g#41%ojIXx!5R zyaynW0kj_wbowdi6f97T;4%`_{so=W2|BNnSo?Vx85m&ae~O98J%1POAvbp$%hjVv z6ORUzFerYNySkg-gW1DRMTqO<;X2`kFPJW@U^?G?XFA)CD_L8^3imSKVOUzs{rIzf z*YhmZj?;S;T0WTa``=>hTp7~!df)b1G4Ji}8(zPzS^i-&`_Gzr!O0sXbWT6AK4ieN z@^pUO9L|odPdA)M+bsJyupn*KaTXQ#J=dM3NKkPh{%DX`ap6?SnNpb#f##R0={GITrUZD2bmq=*&zb9OadyQg} z+f%e1MK>5GJQJ0C+oN#y*sS#u_g3ypOZZbi^P%u#MM(L7aO&%XC`LvG1|~)Z24+SE z1{OxhS>9}n3=Hgy3=E(%={Ok~7`PZ27`UNwyo?MCe2feX{EQ3?0*nj{f{Y9dLQpvo zMg|5^Mg|5kMg|6PMg|56Mg|5+Mg|5csJsj#1A{Ch1A`nR1A{zNOp%d+L5Y!pL79<( zL4}clK@}>l&d9)^!N|a%$;iN<#mK;*4HegAWMI%^WMI%|WMD90WMD94WMD9Y%9$`S zFqkqjFqkniFqktkFjz1$Fjzw6tQi>?Y#13BY#A9C>=+ps?4jb0j0_A;j0_CUj0_Ae zj0_B}P;pRR8VR`JA#=0TWzDwpruh{Chy#JrL_(2Ptc5kC}>M#5HW>4M!1%OX#DcRYM^WI2z_qApN3Fful@O*q)>K^fzwv){Mv zO|GbZD-9l-*Erx{CVUBePSPLNLtIv~c*3V|G&FgRv}TPl=)b>>B`e?C!>7#+L)z0p zQ*8=e4YU5QuRnF*u)ygLSIgL&O*UIJUoqDMPp%&HDrjn85K#OY|6|*c`qR4){g=#f zIq=a>2fY4?chWND{Ei|k7SJU64EBj96?WNy&OOG}M1bZ0(etl{=J{8!_{)d32S(3N z9h&E-j-G!+-uXwc_9tkUEojCWbnX~vEg)z#6f`CZIt2uDHVB^fCnMJBnIk^e@a8!0U$TQ{0}fy4Luvb);XJhcoua_} z;pXhW?M9yL3TKb4_y2$0Zr?NejRb&bE7r|C_2Kb3XEr|3$`u+D8E&Qt_)ao^ zv3RC)DEQ3#1cymy70xa?xv;?5;}Q?E!r7wOrwPs-S9^@55(7)ERc1fDd@%Tkxo-+ZnG8iu1F-+xZZt3McymW81bqElh}khg7)nzXzsYk!}KBJ&(B|955~X0Z=G@Vno-TJy1NU@PYN~7a%4z15n3$C zV!$N$gmr@UI#cuJpC=NVco!^jd3oSKRU$Wc+wbCM1`RxkPoJkVRB}JDT_ME7V9u~a zQlfx|UtE{zHWyd>`R#d)%wqEudo~12XUVGDSE}7Md84a77lY=8h>eTnmQ4s@=wpp& zn8+s~!Qjz7ZI{1&2k8C-Tn$E0_#5rSsv>@9z@~J^lRJR6|2~&gA6q*sNN`W4?RW zfi}UnOwVsc8Pq;LCE9lT?_Zwz>*83Y5AcW`W!iUVU#)=T{_5Y?4qm!Cwb9w5<2MCNeNEq0T2-`c5kgFGD7qR$9frQtcZzt7p%C_>hUIg16yj z&ztm;hRX~kvlkvpVCWK*IFQAlIJ@-6j|Dn93`=fSoSRc+mz&$u!oqwauxAoqf?0C0 znI6M;COiAb%mvIGt!BLp%*+gbLW|TIn1w(~u!szGLNV${1_Z}GA9vovKYISF)BR5YQLT+ zUQm5{J9jJh;qMbKN~%3Y)IXqewm@|sXeA(M{0}t$3K|tN1+PIvgcvFdH2wst_h1-R z7CTRek%6HR8s0GbLHiDjz~_H~*1x4NfX2hp7(i!&fJVhYH>6-UiyZrn85tNRqS+6s z_aPXx`VZt1kl!KuZ%wGY|JI6;fdTXUF;L3~RNGsE?*Rgx2Lft$fzCexosELs_u%tC zNS^-%l{KI-50IG;140j7sN5;=dQwtVs=_%lsVg$Q7I`ABzmD{$G6+;#&M%Icq0niU zWaoDLe8>9j5|Zp&C1W=Toe-Y+V-m+S#(Ae$eflnIS}taeuW7ik?uAp#`g1?-aT`}i z&G0y$pY&l5^UU~N|CF{Boc%Am$a??THo5Syp1SdR z;i>&cD9*piko>!Jl5O502Z7e(Z9*DNElrn}aEeSZ>1bni5In~q{(wb0d}789h5}Zt zK1cQlGv8Snwo6ziZ=Y$no11UqC)3~0zkfSh@p6BK&83eeL6-OVD`uVy-oL)WOTOE6 zg4CYYg;~>2Us)NVBOJ^iw>$P%SF+ZXtSz&B^f(<>UJTG*EV#DqutUo-1_zZl=Ci$- z9DQugFLoBW_`K+(y1hfo$4Y~M_nRXpT;I*++Q&9IX|LbKia*)$HFBmMv2VY=D7Cw; z<~iv@XYZZ9ouHW99rt>LL8jmGFk$0^Z+}SGKG5a8wv03H`O0Hn4SBoocqd7oSYKr5 zyQJ*lD)va5Em6N}KU`8}=PZXG%PH`Ri-12HTeS{c-uKI%g8})vj?|)_C~#?1!hfv%Dco!Z&zl*#xE&UD^L^OK!V5fY$qC7nIshXSv1%h4l~U7lpwV+^8ojS#S;ub3l57v z7A^knH1{7U*kQS@2^RjKF; zoQnEl3&Hi99T`$~f1G3awdU3>70cP2Ud@a;T@x4;X9w~yxQZGnyvUI_@T{ihoEuw# zxPtZkjMlyq;?DmKlaH?LUhSuwEP_Hse~uIfGazwayG!~9R;(k`aZYns;Qn?HKhX39paH#=hD+ntlr zxN6Pis;vhf-n(i$W5x>&#Q+wuPLIei*9#fu!j)z9mG#GLB)lhSy)Mc3c3-+>caTa~ zrzOJ-9k&n8=5j=Nq5`_~_^eh2b2sTdS`=b#{`lI1OBWV4ZDHYR zRq{CStDv%Zfs%wkk70|RsYD=;%F2tc72ZFaX;L;}-pf1H@9NLh|10LdbNR@AxgRlk zPv1Y^lv=n}=tB^n_w&j%nZ7qX&BC5DR{VTcYst(Wz>xay+4(ZY2bHf>3njFTKJ2{n zCiVBy#cPf1WjwqM=6YUyBNu;NQnZwV{Sw2b@)D=Ju1=0Of9>(kV0deKwdT)V-MJx$ z8%+JTLf*_8sYs>=TLKcYKF;krzG(Lv z7y0g0Y`)KDzW1v7o4e8?uicVB#P{ERY#k=ybhOChdXqW`TfJ!`+;5*xvw(|7nb>kp&r%HAud)h*Hb7kC zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_z{$dGrD`R$@HPVj<10@W#}JFtYbQB+ zh!lz(tKTf4;;nR==gAWz(?hYQX8|33WN|Gt)AE@#o2l}6V- zJ1|_EY&2UhdzDXO=!Kw{0g3OA+V>dME;D)ct*3pOSMlS^MGW@52}>n83jPQ2ztqk@ z$@~7<*J=sPbIcdY)RxzDtasF&(!O?uyH#Dx*AS81^r$)h;Nw?{N$c&3YgZq9u%$8l^T#Z^$?8=zU#wv&cvazU zvM*WMsFp!+BCqh>WRG(^lWeTJXYA4{UAOdN%A3`Uzsnw7tzo!xQA=AjqKfnP_U7#m zKG!l`_;1jwt-%m?HvQc?e>JI(J<9QsEOj)%tG7Y`1Cp z-@B8gH(6ZLU$)Mxj{nm}TPgb@k0>qQ{`e!Se=tXv4x$;oUS8SYPiu`lc z-|tvI-@U(BFXZBt_A9+tIvGl|-Y}lYwrOaJS@q;z@6tVt8hd{(s(9SJ_EcI>)vf|x zfAMvivpqcz>ps+|a(;Z*@9{}LR^xgDTT{n>*X1*^Y=!J3{s@@rb}yF`-!yXy*D(h6 zx;@StCTZuK@TszWi z+$$M;jJa$MyXtC#s!gpcZ=au0YkpsX|INJm%XhauyMJ%D;BO_ioCK5By?5D{+B#fx zxRL*`v4V5+{3jQ!JD%TIcjSD17FUtxvgK+s=FQ?z-nd$`rc5BmawhwcPYY^!`J@|G zswY_W7<4Zz=G5JYd}VF~LS?#?_WG9{vhb8;v(Mr7xSKdgA%z4%po| z)NHV(Jh5!ORO80|D)9pP=0~?(n#Z`~3uD8%V?If)9@Z5LW^TE`{Hm~}cnN>OCx)Kq zo)7mty2x%mJ@kUWNBsrt*>71XsruE6E&j~wR4?c2J z<=-Xv|JPSWPaBVQ>V1n7*6rLh@5Vkh--smJK<5=P@<%>BkT2ht5GS`r`CfTzar6&y zzb6OT6S&v?I`}>GV*>kE$D?tP7ucPDJl+56w3F4UsUf?cPyL+m{55+%1OKYoclLQG zms|^+pmUl1R2svfgiqoMdfT*q6z`3&{*mF47tehLKLuu`G~9U1k$(TD(+ur3YAd!RPg}$PENB8_-!`j?550eEEbcU(U3=|h z^URXJUtQ`AH`&|WT=7o-c5vao4_&X=^V#{gz1?#$`He;Xl^Lx+ovak+2v>gC-s8M> zQ|g*^pO4+_u8d%kyMDTPANPlessbmEH*0@>$YgS)nSIjPwNbS;AKu>R{g|+1;xEVZ hX7kMVx!U~T*ZQ=4Ra%XUDFXuogQu&X%Q~loCIEoiW8nY* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/flaming_axe.png.mcmeta b/src/main/resources/assets/wizardry/textures/items/flaming_axe.png.mcmeta new file mode 100644 index 00000000..eb5c833c --- /dev/null +++ b/src/main/resources/assets/wizardry/textures/items/flaming_axe.png.mcmeta @@ -0,0 +1,12 @@ +{ + "animation": { + + "frametime": 2, + + "frames": [ +0, + 1, 2, 3, 4, 5, 6, 7] + + } + +} \ No newline at end of file diff --git a/src/main/resources/assets/wizardry/textures/items/frost_axe.png b/src/main/resources/assets/wizardry/textures/items/frost_axe.png new file mode 100644 index 0000000000000000000000000000000000000000..bcb6fd03c05ac393255dc89812c139dca3752940 GIT binary patch literal 457 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|I599dSgOV{ zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*K*ttaoG}r1dPGw+V4D)nx46!)9capsa zQ=!Ol`|C4Ij&e3CJo=EW+aWDGmv8#Cu;zlEg0&kIn;bGarFy1i@Cb8qcgZZ0R&rdi zj)QysOQ#EGUz*CKv;Et-lAXWqPu=^^_r8Dp>(~&GDjoV&$RRX`sa@;#m0e1^62EQw zUS_`R;-RO~Ti1Eq%k+M@PjgqI*S$>chF#wtbS4(O+H&ytuUR%WRt#76SuxxZiJoP( z?cmo}TM~Io4o{i8w^nc7-cwZ;F4@}L4cSvoLboJlbug8F+8zDZn&rTfuP#cHKVKjAk0f7= zJA3L;Pftn0&kdgUGEd(*HuFWB=Dw->w3Gi{=iSVHUOet)yPMeu^`8X`GMf`Zw=KOk z^}&Y!zQ4=)4*e}uoaFO3q_1G@q_VeVOuW~AiT+5xu9f*G{13xx=WU0?BpgmLFfcH9 My85}Sb4q9e0HjOBf&c&j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/identification_scroll.png b/src/main/resources/assets/wizardry/textures/items/identification_scroll.png new file mode 100644 index 0000000000000000000000000000000000000000..9a6e7afeac30e09e3ad04caa7468ea8fc838c1cb GIT binary patch literal 538 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lqGVU|?MC>Eak-aeD1!e~l%H z5(nz@_pRSBYwf~k3->W)UpB9#fkNWr-4Or=1V8JT{!N`FHioH)St9-}C&aW%zQggp)2e(=1 u(t}BgGW$<+rNyevUUkYs_($Gz&WF=BJ2Ll48Za<0FnGH9xvXl&=o&8yW$h~mt_&rqAXk89QotIT$}$399b3dhbc~%btQZE z)-TT#<#fziJ7!$n(rK1yGD|gI|Jj1hDp7W}wudv*)8Sgr21bMA>I zbspz$+qM{{_MG}XtE1+qlkbUp*S5FV=LwkT+POFFh}&`Wf=4}HqptpHfg{YnT~<7j z-yitn;M>qmDPI3}hUkQZge0+^-?_z-;Y7ohb++!!p8scDnd6yR9OL0SF(Af4hM#>Q zM<#oW<%F}gwH2r05@%hE5j@+h^4{w92h*zxOOC8d-Lb+(HIy?ioKtrF?;pFWPArt% zr#NR8?<=W2hcDhxeRRe(`LB1_wQU!)Us>?iFaF!x|9-wxPTt!IKJ|$&5AQfp&3fNq z`j=}}n&p*0q}QuG{MUThYvQKtob~S)$+t#CeCxJ8&vD_dvBp-dxfKg1_guLkEcWej z(3;P-V$ai#H1~h0tMgjY9R8wF;yjc33VVOSi}4{MQ@Q6Y`^%pBsqgB3!46OiGkCiC KxvXkC zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_z{x4bW4(UvQ)31O2HDJzh!W@g+}zZ> z5(W@(E=o--Nlj5G&n(GMaQE~LNYP7WXJBA7_H=O!u{gbV(q6B_1tLfNj~qP6{z8Rs zU*nD)BCH1wiVM_EUSroG@R2dbDD@+==+fqeLA`I~*Ctr4a9*wQ>_DN%XZ5XHw{@5A zxpUw4c^$)l(S6TXEjzvN&zU73{(Q5tVt1cpviB1w^UrzOlRnvo=WbPR_dI2=q2P$e zzUO`AkE+*&_QV(e*nA~r&E!Q5OYW^J?ucBl&Bj zf}2k+`1+8K=5NO?E$i^@J`^KHS#WKfdzANpn_4)h#soLagbx} zTkkBC+0@(l@Y&h(3fk{%{?GXH=y-Mi_r2c_?w@!3&b##zzO6P}43_H|*cbC0c=d0~ zmhx$_j0#f?tUg>csP0{B%e#Po#q3PZLoWOD#lnqL&IayzH1nF;)w5eNu5~U`*|4$r z?B~7h;WbPOc41--t9S3I`t^9W_l|uYkCn97=?B@yOn15|_Ean;UZrYRTfW}qJLewm zeR+q+nnx|&x~b>SlSg~6eO3Kt<*?G)ZKdR$iUjUyv5L>6V$#kRKGMG<#kW_P|5bm8 z#%%^i^X!!^3+0|2xhOKT`DB2P%9r!2O{3QK@8|yV+RCkC zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_z{$dGZQ{9cLk0r_6Pu@tV~EA+wG(YK zgbO8()lXltGS@DuSu$(VGO;gFnakOX%w{X8$m;Ccp|L_kY?af?Rf`sTF9}-F{6NEN zB9GFvEB%X{6=v{RI(k-%9i8GGWH~G5T@|0Z)1_4<9~#SdJ^#Mv{b&0d?MJ4x{5U4X z@NwypeX7e;Hkk_7o7|i8Z2Q!D7FDI@wAVJj6dv~<+xdTO(m`)Aoj;r`8}4sgc;-sy zx$GVR+%IEh-gv?AASX{|p3w_E$(q_do-e07 z-7okilb<0Vc<+%QW?zGX<4e+SKbgQK` zcAa}&Jx|)X1Qyn;Lg_%sxO`Om_PsP^SM29FMIe%`sUvb zW2iSdSNK(U)1p}n2UlAiE^7?;v`)TWV#L2@o8o-$AK4Bcj%JdoG;ga|dtlyd_4Dl) zXNy-pHQliB!laUViM@&C*=!BJmR+3A_R``0Rnxvd{5A1XQ_7d7nl=4rI?r~~p|(<{ zVXZ}ZdH`?**j6nDijMXk$gN{HVR5CA%YbmkC41+*ZaN zTfTAmUN+!qZe5tzv{B>K$-8qy%65NQQqT6sj-jsa3m1d$gzHBApN zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KnZ?D#g-VTMa~T*IcYC@xhFF|lJL!Cu zaG=Psdh^TYWcz#d z1DE*P9$UVvVqYo}mA&Pfh^ynY)Ei4Ol6kw*9v$P@_q^-piy1cOFMiZKq50_xyLM%d zkl0!iCV_p=&GMsHRzH?<;9Stc+Au}v_O^{)p~j(q+?vYPpU+Qcb}-In zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifGI0tRGAR}AZf0O$nCQWOIo9#$aW7kZgiE;Sg}dDS;|1w= z)z-|KcywZNGwbXo_SxHv_v|cP&1d<}b)H@Bp)>>TO==Pj*Lsw;buR2o{K3dD`;6_{ UZ@C&73=9kmp00i_>zopr0D@m$#{d8T literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/spectral_bow_pulling_0.png b/src/main/resources/assets/wizardry/textures/items/spectral_bow_pulling_0.png new file mode 100644 index 0000000000000000000000000000000000000000..f089e38d08a8dff908158049294ef608c1f08260 GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lb+0uCjgZc)W(l4ws>kdpYHYh#ps^~3#Q{Ns=tAYJWxupf z^W08fGsSPt<@1rp_{wK3`~SZA!XJbAk8}6BW$M1#wQpCev2S9O7C>*Qx1HyS*=ww*s!{dw=*CfE0e)pPjfn!GvuUPeOv tz}ug*c8Uskaz6R#8yZ>o_x>XL(AO>R-^EtCF)%PNc)I$ztaD0e0sw#erk(%* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/spectral_bow_pulling_1.png b/src/main/resources/assets/wizardry/textures/items/spectral_bow_pulling_1.png new file mode 100644 index 0000000000000000000000000000000000000000..8f89801aaf61cbd4db8930ca6ce694089b0093dc GIT binary patch literal 407 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>l1J6sA;^&{%#;pCY=cYn9S7@kd*NZRQ%nTa62Vd9q zJ7v$*ZmpcvHTzw$3`^3yWl1l7ADZiVH$|vzk?6yWx2+$y`kmu>v1*r3$KHzzwBLzy zzggt*uWSB{*mqT5ZvF6lvh7aRh37ISHqCC$s5(^t^IUwWPxG2b)~dA(3=9mOu6{1- HoD!MlX*(aeQgGMj@B zo^WDYeyXf|aqQc-vLEgzlzl9=y2$*z^R9He;?{}#%XTkGHxF9-vCQJa>5M6JI{i

    &#*M9R}I*X4XL4k!!)37(0C(ZbUiEqsl zPm#ctB0H?#f6i*X{#LAY%8J*&@;dJ1hD1G1-tWFLB*>$)a@xfA-_M_2_A*DN&E&k1 z6dU8tnLCswYbdR6UTk=8!L2zloHtg#(mJ#|ZjNr!`Sbsaw)Jle8bIVpKmNN4Ytgp?Ft)@rd&UE>_#{HhFdMJ4r+epGb=y; zKf_S(b|lkIjFtDZd+cjn_FL(a_s%ggv`l$1ckv7H7mA9id8v|L_U!U=FaDr-{$g}@ z`ehadh9h1V?@HLNo+IV_eB0715>nTbmu3{k>-{M`axW@|F=oo8l}!oqw;MdR)8UVM4?G`ONHwU-y}QWDF=uesp51)lLQm O1_n=8KbLh*2~7YW7kOC# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/spectral_chestplate.png b/src/main/resources/assets/wizardry/textures/items/spectral_chestplate.png new file mode 100644 index 0000000000000000000000000000000000000000..0b4917dea682e38b7aa25335c49bc1ab2afa77c5 GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|oMCV>b}-In zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifGI0tRF+30I%wb?)Wb$-z46!(UcG6zI z!v-R)_P17XsI}afv8wG8i)6$Ep6a%oO0h*eVwGasc;arn+Q^)gxP_^!Ws@pbWK?IT zW@wL$hzi@el>61^cG{c$vDRsw;H~)N#*Z!j7O^@l^N+o`#ox!*?;0$!>-5jeGe6&& z?%rN*IQRU~ZR<=Atnq)bSl2tfy-sR!I+w^MBej`3J>n!Dv@-gaf8Qj`o0vZ#olBpm zV#h84j;kmCHKner8R67a*Bj zYS>a&diufgv%AyErFaC}k6hzB#>G~zbYR=MujyAiCZFyO{LCz~qa%Iw)RLq7yZ^Jq ZPu!JvODS&t6b1$c22WQ%mvv4FO#oaHlvMx# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/spectral_helmet.png b/src/main/resources/assets/wizardry/textures/items/spectral_helmet.png new file mode 100644 index 0000000000000000000000000000000000000000..cd8b2e5dd252614b8c50e1571384aa10843232dc GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|oMCV>b}-In zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifGI0tR>Itm8p1{DsFvHWuF~s6@a)QLC z2Eo}2HZ4vTHv72y_xJ09CJr|*ZaleVE1UD@xuvruoDgT8oh37*lKEiO{o!{Dl0qtg7d7##zsdMU*6R}G!j5AW7f?+BOF)F Qz`(%Z>FVdQ&MBb@04j4{7XSbN literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/spectral_leggings.png b/src/main/resources/assets/wizardry/textures/items/spectral_leggings.png new file mode 100644 index 0000000000000000000000000000000000000000..20a2d845d7f583f69c5b88adc58a404a736ff35d GIT binary patch literal 245 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|oMCV>b}-In zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifGI0tR%C4{6R>r`<(B$dj7-DfcIYA=h zK!@IfH!p6q_#eLe_xI}pDG(>+R#bEF=eeb`CFF8$o%`_Yn(huopBo~2+e?xn@?N@3 z5sxVFoH0#o!H3YMKO0shA6owN;Ig+o{ARhwUo)x22pR0(x3hHhyT3QRmqlEak-ar)>)TdqS6 z0^WhjwWqoI{(;i=7J?G2QF}C$*?57*d=pFpy6rSXGN2eHre~j zPZ&*^@-cJozbBV=K6o3mZ>N^?^__R5Bg1|->7}3Fc6(!brq-L6Ausmq2!9^aepki$ idD>dm*v$Vv`VBjh*RNunyp@50fx*+&&t;ucLK6VD-ic8F literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/spectral_sword.png b/src/main/resources/assets/wizardry/textures/items/spectral_sword.png new file mode 100644 index 0000000000000000000000000000000000000000..95b2dfaeded7cb2aae94df6d0aedfbf1e6c726d6 GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>l%u{Kjxi2aQds%tCFs}Y0cAk_J}hHJ25bH>DbIaThOcI{*yiL z$^yQ192`q!7+hqmeG?h33bs!R?V5F9YW|+(FU`&yIVbZddG>?~)U@80vRTggr_jYo z^SZ?0#El1DtIZGEd1PYl=f-u9-&9_ZaNd63eO~G@Ti@;Rtjf2at;&4#=(j-On+_Gj zyyMDk(?Ydhimd*AEO}1M_BDS(=3bZMS~%r(;tB4H>oXZO*e9Q4-d{0w1@F-vhZz_c O7(8A5T-G@yGywoE;gDef literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/spell_book.png b/src/main/resources/assets/wizardry/textures/items/spell_book.png new file mode 100644 index 0000000000000000000000000000000000000000..2043fa4a3664b1c5c341fac81079dc2b2c04d951 GIT binary patch literal 430 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>l{y|A?T*$SMt%#)-LG za!xv%T#t31t=G6*PyhY*z3=z#X8tD;7JBg6DXo{Ei~oFGeQzC8`L!5h-)^OAMhW#c zj+^6{8Ekm%i~ZK59{5+m#L%h~Cb`1dIn^(R;f9u`(a~97qxAMC-hR*%xa~;)O`g|f zAN{&n&cDwSWI6aptgne7_Wt>^IftyuD=HZkS*8TN6tYa-@^;q^>k8)kwJz7c7yF&* z^IFNX&&u+sLg(e^9rnc>4ENj@`#e$od9IN`p~YeOUVa7%mBLpCTIBO=N~&yK0;gDB zh!sD0{bk9&wsrlE3CA8=#iE904S ePaUZ5mfv?}rPsOroX!jk3=E#GelF{r5}E+Fqpmgp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/upgrade_attunement.png b/src/main/resources/assets/wizardry/textures/items/upgrade_attunement.png new file mode 100644 index 0000000000000000000000000000000000000000..bfaad40150515cb9ac107992e48dca8a5b0487f3 GIT binary patch literal 556 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^PXNr}OT51_lPs z0*}aI1_o|n5N2eUHAjMhfq}im)7O>#A&V4`k&Je8(=!GJ#+{xnjv*GO_fFoQ9ULff z-2S}Xso#uIcjmS{7x^>MPc(@`Ql@JLPtb;49DIzLZ|f)U@NwO(xvCnKAeO_hC zev{rWe|_yDj<2&%)7^Kpu!LDqai))-*o0QwO{o(DCq90`cK-gk$sQ^zuD_nVn(t(} zJ>R1x`g6Xpi)L??TKD?Vu6IAgQWE>`{906Fwd=%EE|1rDtNZNgC$ewP<91jWz;SMC zW=g|+e_e)mu{(JjUamPh=~c$g;#FqrTJQW?lym&BOM};L=Of!R=5Ebcv5sv)|LntM zcOEUvHC+BWc6i4VfwMJKY2#V=|k<}9mz9-)`lJZY*WZn zyyN(18=1pAtAFh459<2$tVY2?`gWq~RI!G;hu7a)QQFY4s8vOxNpR; z$7di-{P)~LCtlBRr~t*fr>mdK II;Vst01Msu>Hq)$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/upgrade_blast.png b/src/main/resources/assets/wizardry/textures/items/upgrade_blast.png new file mode 100644 index 0000000000000000000000000000000000000000..d3e98d96c77d072b33fc491c61f579c330ad05b3 GIT binary patch literal 371 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^P7QP*h|OI|Bm) zXMsm#F#`j)FbFd;%$g&?z`(#>;_2(k{*aMR#MtVob+;A+10#c{i(`nz>AjQf`4}BV zj_nuh-O=!db6X)pJ(u7@#fvXW@*c3sIBd1L+1912Vm#GrVZe*cuxwm-0cQT$9shH185dR9Ge6ZX6bWawlKoS3{p)vD($hs#?xZN0Pc zKgA}#dJ}6SW13mYyI_w22WQ%mvv4FO#mHdj(z|D literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/upgrade_condenser.png b/src/main/resources/assets/wizardry/textures/items/upgrade_condenser.png new file mode 100644 index 0000000000000000000000000000000000000000..cf456b020efa9206479455c491625394747983b7 GIT binary patch literal 411 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^K?c`WWn#t1dic zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=k_bBYS9Ds)WKX<%Sr)bMn146!(UcG5=g zra+OS_3xE6GW!=SJgL&LEb5A)MwE_6#*|;qixiw!EM2>G;WUBFLg87z+SvB5bzJG{ z*wPjy^>uDrxV(h^*=6sF9^R`yXZ!pv`+uu>`g-o?SoSTt6xt`h zuSf~aFAX@EwSsBsYLWBXL$aOCGC8Iz)_e1Gam9X~d*H``M1@V)wjNS<qKfl>tkhw>BY^O2`7(mRZKZ;VagzECwjEhc`a{ZaKoK>{skc~ zW=;LM^I^Kpu41N5p2iz~<~+Q@z4Gcx~x|CEW7984L^z N44$rjF6*2UngBN3rZxZo literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/upgrade_cooldown.png b/src/main/resources/assets/wizardry/textures/items/upgrade_cooldown.png new file mode 100644 index 0000000000000000000000000000000000000000..4a4bcb24a299213d5fc354344ac445eadbc9954b GIT binary patch literal 452 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QCeq%qvjNqQ8| zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||V3OwHGknPZjE8}NG0@Y+F~s8Z-pTvD znGz+A+n0N0hBwLvd78Liyl`QXv*X1lj`a?+SL^;|w=}&ekoPdid56l4D10nq{r+2+o1K96MMQ&FVB1N@zUY)$X(~= zicJ;LU2W5`Gej#fQp|k!XNEOT^p5m%RypPtTga$M@D$a*IBx&Zt#)l?_p;1M=d*=! zjT>x2(j!(r)YcL?ewtwiQ%S6QXedLPI{yZ9r5c;|43m@$QN?Oi1K-IjCn{%M6=-~* zy?9lprTXV=eunfI<@D<|dKyd#mCvS~|896{t1Hi81-X9jc@5h>?fkqh{kmComhtA^ zvQ1aN%UeCY#r*QFVdQ&MBb@ E01{%k8UO$Q literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/upgrade_duration.png b/src/main/resources/assets/wizardry/textures/items/upgrade_duration.png new file mode 100644 index 0000000000000000000000000000000000000000..c79d092388bde006472b99f3ce8d218b55cdf22c GIT binary patch literal 412 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^MdM{A2k4{+~Dl z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>FdgVpPQY>T0i=b+II#9Momu_#}JFtdnem_ zGaE{@*B4H_q&YjK;FO95*P`y`FVp0HFy7g9?}@m;Z^ka~?U!8HUnVKWzEaT$+VHy3 znN4|%^TR#*1z+DT@bvYse*TEN(fh>bC)4fO|Afz#jb&!|#jC~tvg~^8cj+f8tx8q_ zJ0t{OmYJ*noR_9sbK`f;<{pF79LdH9Z}=3g-W?c*KB)x*olLI;kitZ7ehl(m(9U^)fR^5 zccdo=9g=8vYP?pZDaB{V+jM8nAr{X`6_Y{@e{*iSzP0jm!}YmZH*biU9aHF13e(tN z8npf1=FJ6(vfup#;;t6`cYbM{@Lu!TXa4K?cjy1}-4MER!K}6ZI~le}byPmfX*>c7 NT~Aj(mvv4FO#qHur&a&} literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/upgrade_range.png b/src/main/resources/assets/wizardry/textures/items/upgrade_range.png new file mode 100644 index 0000000000000000000000000000000000000000..b7a21cec78ccef18bf8a917ba03fe019ed5f14a1 GIT binary patch literal 535 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^PXNr}OT51_lPs z0*}aI1_o|n5N2eUHAjMhfq}im)7O>#A&aC4tM02?_2(EE7?*guIEGl9-aFaeBRWvz zSp9a6M;9&zY`Ji7A^)8a86^*oIz_4zqvi=ZU%u-;6Fjs=vnh zCHw8_dU^R7X?B}jGb>~T6~(%3eH0!#Ppj`TnLMTKdgXpYCle{r^PitMUS+Gu`Tj5D zmDAF?^%-kLlY1nRRW`72%5U2AE38lN-|uBHPt<<*b~fIBQ}4(4VAr}VWez6uH?i;6 zFl?Ifb;|2qS~W#)j)w$ro^?67XE8%%>~^iaDDTj=AOzTfOX20bR zJ1sBL?V7c9mIxQCo3Q59y`P&eXLS_4n6vqx(Rudso%Lsae%&r$(#+^4tZ84i^V0Ft zONAJe*Z*n`-gYgiXJMsB((X*P;*Z;EIqtN!ZMt?VJS_bBox6X(%CE1RpQ-#|_kyi? k-1}a<{9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/upgrade_siphon.png b/src/main/resources/assets/wizardry/textures/items/upgrade_siphon.png new file mode 100644 index 0000000000000000000000000000000000000000..ff7bbd37116da053f50d37a2f96d71e44064f593 GIT binary patch literal 447 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^K?c`WWn#t1dic zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=k_bBYRUYH$9yi-m!K(Z|!pF~s8Z-pPBt zof1Wk)vxDJyf~wU?Jr}l5DRPJ!V60eOcQJFu)e0UlWXVK#$YzyTML{lIv%71U$~Tz z>$^)s>QR6|-*vykPha_dPV#2woAY_!^U8C@_xOM4cV}5LYP?hmZhp1$jDp@vr;yV( zKc95j6!z?k=aPA+dM0(m_9|EGO{lsqu&XT~cgsq%Tgi807e8<*iheiy@YcIZpDK&F z9kd?`H%$LhaQ`U_Tg2XT#Rl~n3=g*i^?h=8*LbN^=(9cL_T!C$Z^Ty52&#^nm(09X za8F2~3)8NZM^+X4EA8N5RJ?JgyWpwYgO+*I*p=*G#rQowqP48)Lu4Rp$p<;pt4V)+ zZ>|se%eG}*_Oo{rpU<1#xBb}a{fF-q^**Q!d!uY26miY#$B|ciHa(gD?{B{7p*Jbb z$^R2y83(+V|MEM&+2-el_5WNpJospkZL#_fo7UB(56UyHl`t?cFnGH9xvX`TmWuM$3?)&Hbfde1zyTr{BT+Y~Yyhiesu7qU2 z&y7Pb)Y?~N?Dk>KY~)~m-7Fz-Mec0kkHl*S7L+7OG9NT>xPE5S(&mTlsj`RHM+QsY zvlmLLs7YjOQ>=*n@Y`0JnVFgS@aprEc+4$tNap=J#N#ej!gwrsA5XfU(8{MgV sf6w^O-{1W;%qkX^k~{uCC|6~OtS{T=eX7)jfq{X+)78&qol`;+0PB9EmjD0& literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_advanced.png b/src/main/resources/assets/wizardry/textures/items/wand_advanced.png new file mode 100644 index 0000000000000000000000000000000000000000..02a3044e4b906970dd0eaae4898d5cedfa6301b6 GIT binary patch literal 506 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>l*O&6xa4(Izc2{9^j|$vq$9(?z`)?? L>gTe~DWM4f4=?8j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_advanced_earth.png b/src/main/resources/assets/wizardry/textures/items/wand_advanced_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..940da730367d437338d53ae40053beaf773fa7b8 GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^NcO92l0|E_n2i zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&nYTwEEUA$@RWgpG1=3_F~s8Z(aC$g zof1Wk&7T~8N$< zcVVg@BogMYXZXP)Xvz^%9lJ#T*v{;TWA0k~u{+zAZ)Xx(DKzn#_>VhkZ{*TneRWxN z<=_85b@p$BoA;QgZw?mQ8Ogu3NuJAa+fEf1|4R}=D^^->ZDQB4^*C0fVN>@v^GXTV zucSG-dMkDBClEak-aeC=we~sou zndA2S`o`0?n48~BRTlhdtX@><<$Ja&U%P(MlEIWa91(zL~Q%ZTOTv4~aEid&3>-M2PWTkxj{ zJo>!dL$mVio>_aCPjw_$S2kALwWh1I3f$CBZ0Ng{Wt#HirtdxB<8Ct23q8JkXZ6th z_kqsWsDY zJ}>#lRWCHd(Rrq$^HwwS4Nou3h>8%1TR**tC6wjLrDMX*ZS%LD&1F+x=5jE0h0+3} ztZp;*Bb)Yq*}B{#n~yOe^4j?}hX<|;%I9j;eu)Xau(<1GJKG13NjVifhbE-&U(sgA Z?6IRRaLYUCRt5$J22WQ%mvv4FO#pCa%M$l%fq^l~)5S5w;`GwVd%c|! zC63mcFY#$skY!>Q&peSM@LouW_x**S9Z#mjGxa9 zgA05*w%IK(x}-R-Er8=}f7Nm3=X0LhKCgT*-~TuFOGSBchTFgGZ0`!_UY^ii6LaUE z-JQeVMc%KP%N?;y@v<=AoqrlOq7RSqU5Gni#QT%+&N~OrP2%k>&*DsPpWVeR$sE6i zY0AYd$0DW#UHLahH-zzq?Kh^K-xRN@&4`au**a^*lxzlmq$BzrO_xwpUg+0eK^_iL<}shc!s zEJyr$YjKZ*sl8$wf3qx~#IoQ3=a0?zYIi=`@uOq*PEMtTk-qyk_%30zseOMyd)Bl% zv85s_=gz;L$5>(6VQrn1)%0#&oSJ+4{{P9=5AU#PEH#j>F*4e#uyyU+Nz;41G`~G= zn{uVH^2V%%hhpb#+&zs~PiyTH&21;6|2(o&BWVtuDSXgH35!WLL9e(Lhp9e zZ9jA6$AYv-u|5`_KSF$SFW$X;`qd*F=UTh7gPwql)Pdu|rz#GetryFNwUk9__tW%l8Yr82)0^@I41 z?)6mY3yPobntk^6xnkql3>LiSU$YzyHdC!N^HSZ{%Gk3iEA#z3$9W=thnp{d*syii zpUsR>**(9iBe&9x*;zcQ?$=ShnD3>+f$~j1kkO#wiL^h<>>CrgQs$hdCymYCj7Y nY>GXVj5q{6Hcbn3if7pUptJ47%QP(p1_lOCS3j3^P6FdgVpM{4@l7&&=>sJN_#$-pRe6C_1Xn(mqyl$>`fvqd0S(-WV}kY@Mr1Wiu=XBsAJl#**R}ct7c?pcrEl* z6mD4|7QgsH$00vwk;bWeOSheVSjqQXuI|J6p!!C!BEW6wJrOY Zgx@r5iJtPwh=GBD!PC{xWt~$(69A)f$ld?| literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_advanced_sorcery.png b/src/main/resources/assets/wizardry/textures/items/wand_advanced_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..135cf8401f7d153fd138d50013805ac09407f2df GIT binary patch literal 468 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lx2ba4!^IK6bTzeaPS z%yIkkx1$$(rlkv3hyQc=_vYAJP1lXvUSBABx=ZHH6lT45dBs5|Tu*k+$vN#9_|H`L z?Sb7Uac3LnA69C;S&`@OKmYyrpMUq&KAi9Vmo@6nY>|c(rPfGJiQd*Fxi=1Pz1q9> zQp)3>pIGlboKxC8Df!beK?XO=2hXczzyIiUmP>noBYtPlGuJcSB@Ov&7;F|@xxO`H zZRLDR>GRAFQeuwE{}9VrQz*T3PJUuT+q@`FcefokYLA`VQDCGOWW9Vp`+}{<%wJ9Y zc~$bIY|hlKq$^RA%j7*j2iUHBDm_a|%Ko0+?$tpXj<0%_W!+x;>C57YKQEtg^S-!K z}q=5gu#&?7y|0ymMs|7YoxA)dy-C+1%?}l$F;U-#$ZTZdhvhLEiwm)XD3l zEQ;AO|6aWAK literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_apprentice.png b/src/main/resources/assets/wizardry/textures/items/wand_apprentice.png new file mode 100644 index 0000000000000000000000000000000000000000..3b39afe133f795cf732796dbd380ff1cc3d614e8 GIT binary patch literal 456 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lBb z$npK}gI<*E-j%cJU<;dg^JE3)cI6!{JH9R1uW)?D%7upAFXS_LqoRU33>L0fa3IHk z^Pt5M)xAzZT_>(9cqWv^?frQ0dF{SG_kJ_}*ZIZ0W#_hY@(NGhcNg4X+`8b5aTJf@ zc^Q`b%0bK31>PLEd`s((bN2_mJBxy>+=CUWId`n*yzatzou6&nw@VgQeuARY*bmet z==|b(!0Iyh{GwG_bGGVK@A<4T+qFT$?HyC)V!tcSB@7P=91i7ey7KOMuT^B8V`%6O zBgt=_N_?%$&A#kq(XI%aG{NBPI-^ZS>OR8dy>8c+*sB#>+m!n`zu-87uEu7uDU~G= zN4`Z%dVjRg>}tBl=2GH!Dwu;^Wl8?3jAEIxOfJ9Fk;dYVsLMa_}3U5gH!;$z^8 zW#_xsc<_+juU45?@z!SRs*1Mz?Tm6X-F5j@%)Fbw7S8YMZdw&r!BEY>z`)??>gTe~ HDWM4fAk4p( literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_apprentice_earth.png b/src/main/resources/assets/wizardry/textures/items/wand_apprentice_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..4b25eb504d8e3bd1d09761fa622459358409e11e GIT binary patch literal 459 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^NcO92l0|E_n2i zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&nYUb&*E35aGQaFF~ZZuF~s8Z(aGnv z4;M-tkDvd3+YHTLn~IFsg`Yn95X<%SgKpaN_x2m?9l96C%=MhqE&O!Rl$aY=6WP6! zRLcUgrrrN7^vr$D@x;ii8~fDHe_Z+f_t(0rdF=ldFB40ewAW@zN>St#;Y5ok(;r@x z(2tF?nw7O9?*8GoE;15Q4aba|cpWEouNGMs@|BIDX2%Xo-{ATCp8Y*`_Kla*%E_H- zOQdftUVlK?YpQ?hEVX&@__V*u@oBOs|=JDjqeCte-Iy*Yv$FmtRw{@n}= O3=E#GelF{r5}E*Ut;xv% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_apprentice_fire.png b/src/main/resources/assets/wizardry/textures/items/wand_apprentice_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..ab83f220d39d227fede3c22664280b91dd7c6d5d GIT binary patch literal 447 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lctX^fpl#QL zyt#fa%-{CsO<_cIR+{wrk1MbL{`>AH7H|HePeKA#S_c!IP41)9o@U zYZ8*r=fo`F*=;?kM(%s!UOy(2=?o6BPcrZBOMG|sSkxD8mrBy|QdCwtRFn>Fg4FwGA^jc74t-nA&iCZRhp1Cms6dPQ7mZ%vo{i zYpY()AAdHj?tNTndDH&mCUy*e5YCFfe$!`njxgN@xNA)C$1r literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_apprentice_healing.png b/src/main/resources/assets/wizardry/textures/items/wand_apprentice_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..5633f1532a25814c0f5665f1248fa439cc9af975 GIT binary patch literal 443 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>llGcS+gVv25g$B|XA<7rXhie-P8WwJOI{a0+y$k53+yHIuM+J%Z7hK`#Y zm0hCFtX?u%+rOTjQ`;6z+jeYXN`<)8$-nHKN2||+g37rsH`cRv9j#fcG2*c*$I(i$vfxx{H~c(HP33%`=>9} z<1U$8>boqw?2Gbp+4iK(H;rHRbGk|WqkT|0t zHMwV>gUXu1y4dvO>huod{$nmKNB-*^`m^Ya&yS-9Jijh7UWwrGyQdgnb?o)dgMV)o tKFv}n`#t4#|CPtpZ_hnF8X*6RQ(mcxn_+&-dlEak-aeC=wTW=>u zk+%8TY%>EA?q;l<#?;Qy@^0z+gAetdJ(B;Renmp}68{NBu0^`Day6V{rKL`>1*>o` zaaf~izhRw-;Bv<)2i{b@mgTp3Uu_}(!C$k!QR(9hh9yOjGGzxE)_JMO39ql7_;DfY zDt^~FWe;|qwRKB3{iHhC`X|eay9<_{o?daeu2_^Q zwO5kGc~Z#q55H~Z#7>XAePdJMvx5^lI(B3$ozd?uKcqWrS>jZ_2RyA0elWXn8UB(r xpRra}e0|laym>`GXBJf~kKAdo{p-T`u8#VH2ebFpF)%PNc)I$ztaD0e0ss)xyNUn+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_apprentice_lightning.png b/src/main/resources/assets/wizardry/textures/items/wand_apprentice_lightning.png new file mode 100644 index 0000000000000000000000000000000000000000..1626715be95669854e90fcc0b56343d914c7e488 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lEak-aeC=wTW_aA zkz@7s!KY#l?F!&D4GFmTs6bWY!b3f^mf+b69J!`$_Z8b;aDQQpin_FQp`xLIc(8yI zck`*$9{WNLXLhI<1i$WKpZENGLEMA+OaCc-YEx$V5VGsAQOAY%7mrByohVD_-rhBJ zS>((62i{*?vT@JJD_gqnI5%DkU{2V;!r)!3C$y90YSOgZtCs}*+*_E!`pjAP0qat$ z<4F>1+oGbllJjPzu{JzB&T}&*U6^4=VmUw zBvz~Mt^cv@vga9--G@T-i_Vzr%rx1h_Sdj+?XFdgVpM{4@Qo&YOP=$ek(ZkclF~s8Z(#eM2 zPKhFI^Zi9k7CxMHVUlBr$rg(k&a8|bEYFloe+#eD{l(5|=~8WCvhB)*wY#xGuHE*3(-dV;!v-RW+=>X@I@6ru< zn8Qt#r%o5`ddAFbAUvz#1;ZwZD;75O@4jqq-SuiW>tO>4ucaxc9zQ%2_|D<} z>5Kev*Gz<_T@7CLYo_qDqqU1K8o%u4jJfJ_{EzeG{+pHB*StdzTH-`4EMXOsg41wZcVGT5$Q%((u=Ey{d>W`Pqo>7&i;qd3=9kmp00i_>zopr0JNC400000 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_apprentice_sorcery.png b/src/main/resources/assets/wizardry/textures/items/wand_apprentice_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..9e5f37e39d8c76b81404383fc79eafd0d1a6c3c3 GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lbF-IOSuT&6-W|0z_maHum&%{ZKIa#7H^`bD;gdG9dzAk7@w}xjPBWKzmNNyq zf9sJ{Qk>g-+357@k8k$)QtDVe0WZ28>5_fFy-CyRnb>rit sUE1$|X-=Q7dED&P+{usU*?r+&n^Y_Er>Nl#0|Nttr>mdKI;Vst0K-1G@c;k- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_basic.png b/src/main/resources/assets/wizardry/textures/items/wand_basic.png new file mode 100644 index 0000000000000000000000000000000000000000..3b21bdff7cac1534c710afbd052b1f43739b8be2 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lwU&|D!xqJz-Vxmug!_)^LG2j?)w#ArcO-IIbd?yyTC|h#|N=> zoRS8D$;NtTEn*#d&Q^ek2;L7S!hhdqs{M+OYnq(+@0&VLrRd$BWy_ZFxJU{J9QZIl z_LV8~nP+>t@*YjDbYM7K&+*`2e)8cD@y>m}_pe;3$*g!=QbIx^f{96?$GY29LSlV^ zfq_9y>yO_TGanTtJ1{UGo^8(aKat73Z^ATZ#$ERsos)l8-DhB6VDNPHb6Mw<&;$TI CAEG7z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_basic_earth.png b/src/main/resources/assets/wizardry/textures/items/wand_basic_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..83c3e104cda6cc6798c7aa0257efa19e0b55aed6 GIT binary patch literal 404 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^NcO92l0|E_n2i zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&nYUb$Fp9n>jNa>1+uc*!tR=Ty zyHui=?{T#8ZL@7e<&q6C3rfolzHpt%&hTOClHURwL`r_VS!R*><5ULg`Ogs*`zIes zo7ca=zsTaz%ePY%WX|xMOG^Zjodezqww-d^ie%k-T0N(QdHHs!H}1Zzg`67yX?XQpPI{o}RO?by_*NrE@er5`Pn zd3KXAD5_undv9q-wV*`LcfR$#PrR~Ue4XHV_h($ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_basic_fire.png b/src/main/resources/assets/wizardry/textures/items/wand_basic_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..3e07a039dff78e1156d6947f85dab77ee0f6557b GIT binary patch literal 396 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lgq5`z7#JlzT^vI!PA{Fj*NfRv zq;>zrUMVGxM@|8TYuBF0nd($BTbJoGPgvMW@p#4a3XHWZ-3iMDa+~TkB$_((GLy_W zxNmnDiJfNSethoL$~Nx%mfz3aX{`79!)o=p+|=RuCoXON7na+;ZO_hmS8rfj^Ynv? zk-0}=`o81Ok7`{j=2wVkXL$6kcjja9Z}+%mV(d8=TNlJmcPd$3E*4h7q0Dg3oq3nz zoZJbAqNTe{qW>1|l|G{MSu|)zkX})hv6SenXzT?`Bi44$rjF6*2UngD)|m74$n literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_basic_healing.png b/src/main/resources/assets/wizardry/textures/items/wand_basic_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..e88fc7d067283b54ef2fc884f18ddc650ecc7d22 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lEak-aeC=wL+`@@ zBCY$Uctr2=WIA|oos;@OaRDofl#}1sUO$n4ap~yN{|k37Zd!Nu=-Gv{MRZt7HYlk^ z-)d^)k$qy-BEp^>|HY@D`@ZG#kM~;ZPyOPa;u6caVYA{?ql6c`C%MEHMup1gr&&eM zly2FlZ63bdVy$t6&%?!R4Y9la-&WO0{8M*6Pj~C?Q>!@-)qJ1-);IOR&??c-w(&w)K2al>ja-Rna&9`+nFe=0MGZJ%B> z|HUpn>CX%2$i2V#ZE>pooFm7gnnl)4;kskHPk-V2Q!iE4H--BxnEdB8i`7Ycsfs?$ zdC6W&Ll(Sszap)Bcw6oko+(b-`0jg5e%(9m-z@D`6)mr|Z6T*!H|EYReaTR{bkd`z yRq~HBr8_2<`?FPDUm@bN+~d}ZubX0Dh_AR)=U+61O^1Pjfx*+&&t;ucLK6TAmZY@+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_basic_lightning.png b/src/main/resources/assets/wizardry/textures/items/wand_basic_lightning.png new file mode 100644 index 0000000000000000000000000000000000000000..8d6a61183f8ae5f7a2ef4e93927fff2fed434f5e GIT binary patch literal 400 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lOSZ0KU|^K>ba4!^IK6bTp*K^a z#PRy{woY#s_GJ^Cy|-H4@onPOa~F7jMTevJTphc8i?jTptp{CmG&(F4IrKd}J}X)D zPFw!aBJ;$%y}$hR`TzX;|Ge`4_s05DKe$8InzJPQ`s1R-`Qpa1kk`CBEo`4(_TN0` z_b;}-+*6N!^z3z-_%P+j@ncL1k?aia?5@8K+vU$Y{rKyF3%i=5)*gHIdu`9Q(>l-X z7-mkdj?wQh?|3lz6W`o-6`|#O4|LSFa_BwX9CLTix&`mOUaG8bzFxLq@}F#WtCRLp z7TYxYa=kR?FTE^#IcF>H=}i}m0=Q0!EOR+|HZ1!8Z0**TQ=UtkWZpeLvPtLBCB{o$ zt?linV|#Y%DsVji##VKEg~*vSkB}E%C*{5nFAuMua8vaAb_NCp22WQ%mvv4FO#qt1 BtlFdgVpM{4@(&|9ri#P@bMsZIU#}JFtODAvi zIvgOmdKI;Vst0GchHl>h($ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_basic_sorcery.png b/src/main/resources/assets/wizardry/textures/items/wand_basic_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..042487abeb9d7db31472d3faa96721c1fd580023 GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lZ0Pb_fK`&`Ow{wB1Y5=&YI1`-J&ct@#_)D=fLu&JnS4$!(U{EgJ+bN^s1Q zFH!uuHNq@H!g%#^DZQHKb0nV~vS0d-sWp5#lR-!Ol&*%x_ooUg4tXy=8DneQ8C2aY z6KAqaW2bUy9z&NY!;PoSvp#zjeLMN}=j2UB7owbJ8FaM!ED~w>-fh0y{Yup4scJ=6 z?kv77z5W^h;-$ATCLI2nHS_fCpIpE6j;mG5?%CGp`)NII&ZK%1j+$_$`%|m7`fN8} zc9(PN^U4TGiRPT^%buKk>zDEWY_FqH=#r~WeEeFED&=NhV)Qze(tbQczH~pc&gSa= oq}{nDY-z?S@?U-*HT%MSb8Ge5TCwJE1_lNOPgg&ebxsLQ0Df|wp#T5? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_master.png b/src/main/resources/assets/wizardry/textures/items/wand_master.png new file mode 100644 index 0000000000000000000000000000000000000000..7bd7f7d70bce0f58ec27bfa9bd0dcb85f2a242a0 GIT binary patch literal 517 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^P7QP*h|OI|Bm) zXMsm#F#`j)FbFd;%$g&?z`(#>;_2(k{*aNCmq{`AYg88l1LGu57sn8b(@Q7&dW0lO zw9Y@Db0CoOnU<-K(}KtGc_|WU!4Hync5?6R-d3cTG4oxJj%aWcr`6gfvz@t~B3eP<`=O&8zvDOs{7!Z$tQpV@3{XX{6&`gTZVNd}i1EPF1y!b)QDa_u9J3;%rn z%q1@J;aB;Kmc_D#p+QzTn+~0wwsiT!4OxHwC4Wz0x+!S>o2}luKR;)~l#_ohzdU37 z%glKbbK{&3nvIJOXq{Rmaf_=UKjDDO;y@ct3x)f447O+G8yi}CWlztxDL=@#cglhl z9kXxWUc;U&5`Wj6VP%Nc?xx2wTs50yYB$QgVtWyjTOt!7|C4#|_Zt@$TQZn>E?nq1 TWpf|{0|SGntDnm{r-UW|6ZhPh literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_master_earth.png b/src/main/resources/assets/wizardry/textures/items/wand_master_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..6b90ba210cebca0d6e95fc1eb8a3aae423d686bb GIT binary patch literal 477 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^NcO92l0|E_n2i zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&nYTwqGdhnSsw!fW0t3jV~EA+qm%Y} zJ0*%7n?KoW#>Mt#vR}C%;goE$g(cTD*gM$KJ9xDT3$K#| z2N$on7uQs~KU_M-MwYxuD$~AOm2Ug|vHDzPyxar(q+9Jk0Qpao7EXG!uTW5brclXNHo1AH1B^nIbp06`8qW7LXT00J zE@joL|KdDs4`*%Luti~$yUEA%aoWrCKEzs{^jqI>BvUN;*SCw;Sg-KPZRJ&%tFx%) z|F`Fh_TBGl^Xi%#=P3G4fa7Es-^sAD8$BoHJ>9T%qw^#c$Jq`y&IRsfWSlSg{G?FW z_3fU!9S@bIrI~$HI-H-_pONG_X~DL=C);K-9opKPeu?RD{=>L4H@6ghWL}#3fQjWu e*Ol%A;?ZaOU3-FBCo?cGFnGH9xvXl+1&PwcZjMBTQo2%~^&wD=S-aY33JWrQu*ey1+%C>&qdoq#HW2y0vJqO(E zR1#LtU1+v5x9gJWSFfj6RXe|0mp4x2_e{}ze&Fs_%X`~qf1LY-;STFlk9YAGuCZi& zpSEhMP4f9VvCYR%m0Jk9SS>7lz**s-`IXniSNL78^e8O)qiB!xEQz;@+urj_^dFtF?)5zuu@hOB z(w5je<=DEPKeOliMqL3x!Idi~YMe+=Ui8{3@2>ZTP$3x>T}v)MZ;>bdw=*IO_Woha gt-N!gXb-dB^nS1T>XU9TFfcH9y85}Sb4q9e04Yq)A^-pY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_master_healing.png b/src/main/resources/assets/wizardry/textures/items/wand_master_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..a67c6dcab3dec26cd0e5e495f339d807f566a01e GIT binary patch literal 477 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|JYldsy2N81 z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>FdgVpM{4@M*PQ3hdc%b#w<@4#}JFtdnZ|Y z91aj^+pq1a&BYg%QCJWVQgYu-O;E{j zWYV*9XyIGiwP?lVLJi&@8Y{d1m%MxY`~AcH?Ejp1XWPbKyLw?-R>tYap7XbCW$Hg$ z!Svwwz7Xf=AZ6Jlm&#-A)(K=Am_7D1n;p9E{pp1AiC0cA-HAUKETnL6!9uU4LHg^; zAF%nIw^4gGKlD-2R&mMJg-6RDur9sAACS%K@TheD$3gE6Lzl5GwbHpxq16yq}5!t`RBDW zk}fo~v){6`se1V1kMG~if|%=5o7dLOlzBg8$L?3#4;anld0HeX7})C6sK7Bx%B46V z(qrR{;|4t(c{@{2JH2`}DTc35#@*-g5tFkKW{Hts9~J4ha!o#von3$D#DPrFdgVpM{5um+9Eu_NfdEjIEw7jv*GOmrnBS z2uc)bo9`cUBgV@^YcZ2Jr{bfmcZVce8uJqyRatbKy2Q5fubQiD`a5Ap?@gyWI|RiK z9~HResjyPui~2?Rj%kidlG>y#b&u@Un6vuK&072Or!C)CK5SSz?dO-0)2H9MJO7@e zCC<9w-#62BsR{enaWsUk^;{J*rTAFoxr)VK_HQe+=KN9WDztIMrd6gZ`>ka9XKb-b zwmTtmATlBDe!FwQ!P6JTkGZpzlz(55{^``;myP_Khi|?Xeqipk^1s7c)6X-1heH4ZR z8Q$0>(RUyIdz}0G?Ulr4>&_ifGny@HUPMfYUz`5t<=$}ZrP|q{DivQl*Zg$e6eRS# zZSI$<%(8ujNgte_7FkO59&=)}?qu`aIs1eF7fVjX%W1rml$3-FU2JkZb_EDsHZkFdgVpM{4@Kyxau&`Aac#$Hbs#}JFtODEfA zMIK+V#J8-hckE@&A-HpI%(P&D(d6U+nph z#4yI1{MZN4tm`Z#SrcY0>yl5qy84OSzYt=3JOig)%pG>dJ^S^i<#LzqrHa1-UzrZEZ$H4R^!@fEzvWXOTP%9LYgNBn zPjxMWS$goQtE+w-lHX-hebY7N3%kwqb+1nu@LaQ!HA}zD`o^-=Md{$jf)#fT@cEyg z#ho$FM?P99Zi7p5iEj6Ee>wekO$QaGrRw^B$WA@JZRhSi5m6_$zd0||TX~4#)_d80 z7p3=33kB{5b(;U&v*mVf)LOB7oRc(DeMQ<519ZerJ}uhxOHU=(t9EOJ0fVlfvQ6UxV8H6r%Cb&e{YMv`{&NkHg(gV(^mgkgcw)uxg4=Z RpMima!PC{xWt~$(69A_G+eH8X literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wand_master_necromancy.png b/src/main/resources/assets/wizardry/textures/items/wand_master_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..dd729046236c7fe00779b50da2ed880a9081b807 GIT binary patch literal 447 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|JYldsy2N81 z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>FdgVpM{4@!szjc>iiMBCKl!s;p3%Y zw9(L|ZmRtH)((;KqO#@ZKJR-zC+e4jCs?e_91nWr=_PZ3_=axP8HIM{6V--bzt z?^Q<~4lLb0Q+~qC%p4WQJJ+|acy?@F{=2kg@x>4Jrst~%+}dTaKj!hXI{nb#U1#2` zF3w#r^Q5J^L!peY>&5kF()pM^Jz})l)IQ~O>LUxkePs@Dlded6@bYj5h`848VxDk* zKX=PtcCO?7b}T~SwglEak-aeC=wZw;3~ ziR1O@9&AqyUBbB}19g_HoS9S}zG;W_#*GuE%-AY)wyBj>HFe<)%@k*`O&dRG6rF5J ze0WjA*--h|gd96=o~MT4=ib@W?SEhM{7ZX1U+U8fJM`yn+qe5hO~KMohHYnMh1MQ8 z9o2rIAxrA@v{#?B&&>&K32iui(xc|!rfZ7EZ{5@3)a1MxnH$!P7gytQOfpj9eL{&8RoTBrPUtZ z`1L_o{87;tyZjVN!;R*a>7Dr^@kLM1c3!xaTujXLqvt#(JejlTMx5i)$!9PAoS*+; z=ckvCcpo+&m*=ki&3$o`iRQY~UEKA8JNCBi*xM!&Hs$eruSNH*m&E9aUt?)goBcex zLh4oI?6?KXHwH(ZZ(7)ShShWN%=TNVpM;Ap$_0xwWX{?z&GR_)fyF7|^PSEsPEOmu qH=O_6Lki{F3IW64J&D3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*R@Z8hIF~s8Z)k%h2ha3c4?{{f5Ms!FB9y#T< z#a&x zUr8^>?*4sm!o7sVTdC7Bp7u{;@T&+nJD+&OrbWsA#LBFV-1jyV@F_EtEV=Q9DS7jn z2f}YOr5g5`vn)6feB_5jM~gLMbHdrjb&E~}SD%zGa7gW3rhIhsRWXNOe>85M7vc?I z?D-)U?z`XS)~&FL+Scc#{r~IYAMH_`_F=cShmp&-Ps@_mi%IM_*|^u`w~vL>lAix; f3)ZScbkzsxi@YyNZTN512?`5OS3j3^P6H=O_6Lki{IZPa&Uvq6U|^8V42dXl&d<$F%`0I5 z0q3IB#FEq$h4Rdj3iRmcAWgJVg;MAC?J3xkYuFWPaNH^TYjfXZZe9YevST zA3MEkliy#q3zrMB!g8)3{5G{z>+YQiKa0fHE!}CYVso!_&n~?RBOCU9w;QrT40iV( zJbl;{y7N@c%jzGknc{*9rrHcq*A2Ju8#t)!+2r@~Wze?lvmd|6-kM&u>pEjz=(+_8 z6W71bU(b}{cPW21(*ky$hr2A9Kddxgobc?lYsHFr{%l)bGQKYrkvqKqSi?X6Z2j%p z&*Piir(48E-4^lbKd~x?_p^J0s^H=O_6LkiLgJiyEYhY73=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*R$mHqb7-Dhy>ZHA1M;t_2_ZJ@j+t{G9P3`EW z-rpL(1)A1B=>EZR`!~b1Ylq6XJU531>2SO@vPe+k+!$ee$44k9$L6k##r-?QJ3qW% z`Xsqj@X9Ay>D6`28TK~w{UXjC>y15rY}JELvsRp`dKfip_ScTv$D4BFEd1MkKbXrk z`zuGo^zt3`>pV(VEHYZ{|ADK%i!Z@$Ey()V^+YA&;p00i_ I>zopr0Gmdi_5c6? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_boots_healing.png b/src/main/resources/assets/wizardry/textures/items/wizard_boots_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..65f74b282c2800823103bde846d1d5082e34836e GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfxfqNqn7dX~Dq2Ae$KyQR1ARo12cW z_Vn0t&F}bg$%bFi1r}4ee~5?k&zri&`0hPBMvFOY|NrXfyM)G-Ka_3=>e~1I@Au>n zI{MR$H(c|}oK!;aFje#OhB%t-m>ZFaJopy-m89XI_gmhq=(R y{)6VzcgWp(9JkqSk&gb6IrYpPnk?@V^Q-L7u+3OBL?1&ybxpUXO@geCx|#heiU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_boots_ice.png b/src/main/resources/assets/wizardry/textures/items/wizard_boots_ice.png new file mode 100644 index 0000000000000000000000000000000000000000..13df533a7b44a90e71228fb43a2953112281b216 GIT binary patch literal 409 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfxhoTAZ$$o5sMvAe$KyQR1ARo12oP1(BD?6+xxk@nIHQOpna9*>%R_nvJ)_|woIy*YAz(oP%|??2vSRygaW*<&b? z{HS@Siq-RDhclTEJil(f-v7PvkI#RjS=5aKych+XIvz7$3EkNgoxQn6vg_KceeWOt z2-5GD7u}w2Qgs zo#sB#ed2HMhpVE~7RH`)pEf^Z_wDq{|Fj*vgmliH=O_6Lkig64)3k5~pUFfhnwhD4M&=jZ08=9Msj zfOAo5Vo7R>LV0FMhJw4NZ$OG(Dmw!M!yiu<#}JFtS0`=cY6=i(`!BsHqjN$)aIkKm z|3&UCzeVia7DwklDBiMdn@h7dpHQO0tVJAVC#Eir%glUv|6Kh~`*W7x8S3@jxQjQg z$&mde_nU3PuEbFD1?R=@taG}bEL_a%s@+o1Icw=-rOmo2g;y#}beg`qX~=HZ%M0_r&x+S|`FoxV^U`Q!sxo5{vz|qRhxcREs$HVSo?k9qGR)%j`#Ckq> zrs_jcWvP2_zA-pF&*}W-S;5*Mb>Q&%-QoJiAEF&ywb>q?)n|DgoV@Q|puP=D`Xc35 zdihpnRRwkIYgIo9%-vk=Qd4;-SWbxb@(2GfjAvw8zu)=BtOg1oPgg&ebxsLQ01c9p A-~a#s literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_boots_necromancy.png b/src/main/resources/assets/wizardry/textures/items/wizard_boots_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..c92f5be74e8d7724142f69eb64aab7ec9d5cb8c0 GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfxhrtGwry{lvh)Ae$KyQR1ARo12mmU*dD;v|ov znv6sFy~DzVO!<#^cXZ5-T)cTEL((A$7N=Xiy=TwAIM$mVezh__d~e>5??PpQC)RFz zy-NE?e#7UTH;YBW&mG%RdR6pMQgL_m^VJ`Wch6igr7Xjuq?+%p9K-E5mR%mlT#V%O zW7bSqA=1#JE;qa79)D}}bE`m2{zO$#b$(K5d zdAm#P8o$?R^gVrN-RzL}_3TsG2H8h0W&b1INjRH4d$pLsAMpAXqIrW-q46>Z|lU7mgDH|M?zx7#V-=F}?*-_v?9C1*qKKjB&?-*e5=ZznxC P4GJqyS3j3^P6%qsYL(Ae$KyQR1ARo12nQ(v={7(7>1HZpr1FXWRe(s26(h-u=T;jjp-xqq0Bp z3hYkPRGkvkz9)Na>z+Fk)IV$5JX5-=86enkBI`~K+jp&ixwD@BY^uqban0w+$vwey zox-^9h-|$5vZ~)l>Q=&|bhejA5U-EGGX&Wt6p9P zi35r6cJVQ6(3v0mIfd^~ZtJ$(wKu-+P3Jq9{B4=_e!chdP1W`nZKZm7@A#XnooVr_ gy5T~Bf%*TGd%X!&yo!0}(?KEO>FVdQ&MBb@06W2wm;e9( literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_handbook.png b/src/main/resources/assets/wizardry/textures/items/wizard_handbook.png new file mode 100644 index 0000000000000000000000000000000000000000..aa0dffee0a3ded71c59213327adb5cef4395ee9a GIT binary patch literal 451 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^M#SJZE@i+GhHa zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_z{(>i!Mfd8rJ8|(F~HNsF~s8Z*2x?F zm>dP#?DdY#dBWo4x76wYyTQhXtPf0cRMkq@gqu~{j%0JPB(aOG?QIP^a_m%Fn_HxY z#)*j!TshB1PKYgTaps;|RJN}^t?Ym6|Gq@^cf8hx`bo?7ls;dm5Wv(~;`a2|`txVh z^6lKB+1<`eneLG;@+YFkp=+(*qQ7i+R2F$|2%pW`6lv{#?cB0UWpLqCkjpv&mb^dQyArjQvo_X?#jh<|c4PV1Pvr~@3=E#GelF{r5}E+5 CKeF@y literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_hat.png b/src/main/resources/assets/wizardry/textures/items/wizard_hat.png new file mode 100644 index 0000000000000000000000000000000000000000..9c8bba35a074607bb9892b150decee534ada7a5a GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^O_&_!)Q#ZnU3a zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfs`Xu*jLsu3%tbkj)Hc-8|F1Th`8JrI?ch!wM9sD zskDplWbP%Nv#+tA2)(3Udv1d9j)mK{6~0tcXc3qukZ0z)C!;YUAZ69mfB$}NHm*-( zP5D!?U2WQ|+L;-}WqSico*%AaidVDp`_5ppbdl~S${*rwj3vG{#f?)5oK zU;3_Oc(Hp{cJ-{vO`>%3;LfGKq2Vq>gTe~DWM4fxUi{! literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_hat_earth.png b/src/main/resources/assets/wizardry/textures/items/wizard_hat_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..7022a9173a8ff2ca3a5bb45d0e011132e3543827 GIT binary patch literal 446 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfs`Xu|~6>%wb?)kj)Hc-8)i2N?-a8n-@*NaFA?oUlMi@u}67&CAtZT=-vdXZQEr-~YYmb9WOsT zt{%zg5I6UR+&No+x6lPs!_{qGZdvt$F>lZBdvBMeSC(dlCYB1Pp9^HHu}@#?<8Q^V z%50zE{eRL|CmyXicKf*a#P^$`4;}Wt%J9ZNV*et=vn+4lt?+p}O=y83f1NFdnpxql zAW4qfGNKMob|1;Sxu$f}yIAc{u?(t*RJ8Bi0>=&; to?p?ZuE=2a`_-rT7YC|tz0v;XYyZ}|$ZiT-B`97PJYD@<);T3K0RU_SuR#C+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_hat_fire.png b/src/main/resources/assets/wizardry/textures/items/wizard_hat_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..91ec14888921988a73848c4f52df4003b55610fc GIT binary patch literal 457 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfs`Xn(z2~TAzV|K{hiaqQp5rH#aq} zgaHJci&7IyQd1PlGfOfQ+&z5*QuI>U85kIKJzX3_EKaYTY?yV}LBRFC)uBmEEs;!~ zkJXO322AvGz4TPc&OvYTIrbBYj~c8*!;*s}ow(8kjke`*%swU;VV!+R@;{mlP8gg+R@Tr=(Q&>In%=-E`v}=hE}O zV%f&mvtQ3!A;K{AeMHW8UVoi`3{&4v=;MuC6W;pg7|XiyyD##pmVJuN?YdX^@a<7I zW}CaU*R+-&4UHx3vIVCg! E0AeGx00000 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_hat_healing.png b/src/main/resources/assets/wizardry/textures/items/wizard_hat_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..519c0b9283d7161a6ff46163e72fc33da04de7cc GIT binary patch literal 443 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfxfq>0D7h+snYfAe$KyQR1ARo12(}L<`F-1X^})GJqmg7@qQR!z> oAjEdS^84rXs0pG4=RW5DVC#;bkT=J}B^(rnp00i_>zopr05{I8T>t<8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_hat_ice.png b/src/main/resources/assets/wizardry/textures/items/wizard_hat_ice.png new file mode 100644 index 0000000000000000000000000000000000000000..5502d87633f2c000bcce4428290b8e5a27284b38 GIT binary patch literal 438 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfs`Xs@OPpePm!@kj)Hd^4ZU0q1?Je)Ej;Mg(R(z` zQAfz8Y1_Ob%@w@T(yVKb+&}qDByZsdp$$KLH$+Q+K3N_3Pk4^jgfnm6yQJmrn5%KRjng-L7y3i@i5}W?YM6xbXgL?)L3j z;ZOIv_XxVQxc@rx^Ygv12erj5yC+}Q+SJ>y@@?35R~8qOm2qcR%UL{EP~uRWu`pJY zK|s)jMd{MSXaT_)k>LzJJ%P7ZeT{LI;(svb_2M&U-sarpC^k8C%;aF^{TF>65)2%Q kfBwu&OOkcs_+ehdxS(Rfo5uC;FM)#3)78&qol`;+0K96eh5!Hn literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_hat_lightning.png b/src/main/resources/assets/wizardry/textures/items/wizard_hat_lightning.png new file mode 100644 index 0000000000000000000000000000000000000000..2bdf692d8ca05080a2a12dea9dd3d3053ea1ce0d GIT binary patch literal 443 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfs`XO8r%u9>u`GAe$KyQR1ARo12=)L4Tr|C@Gi&F)4<9$#&SI^(fA_yp&A!L>_C`Hd=&K{hiaqQp5rH#aq} zgaHJci&7IyQd1PlGfOfQ+&z5*QuI>U85kJFJzX3_EKaYTZ0L8`K%&)N{e-H}Dk;^h zX=hd>r{^6M-NDNKKp>`Jv4OJMk+vzSCjzymskp6+e09PzN|iZ()0f|S|9`LEpU61r z&$}ewGZT|%MwRnz+rCIEZaVi7qpiEY$~Ei?ow9322aET-fbCt)D^H}H`}q6vudNB| zs_$wsSY0kKxO!x=tFT4MvP4n0W=%Dwi)YI&-Tl7C_-sN~g3q37?%W0cf14z%JH&Bd zUXOUQNKDA?uk-rnn;Xq!{vcrYohg3L=Swz5eIawYPjOmUe4fKT+hE}p)~#WWPW5vs zOtxIA_iMBNx5BI>SDj!6>vvpVoaV9T97+i&m$PWD`P%)VrS*f@@%_o^VNMKJqUQeR hR^IqBEBomFhx|-}Wj~ju$0mTn&ePS;Wt~$(6999qsyYAw literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_hat_sorcery.png b/src/main/resources/assets/wizardry/textures/items/wizard_hat_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..d385a6d5de3bf4f6276e728d883e836b4beafd4b GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^O_&_!)Q#ZnU3a zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfs`Xm{`1DeT9L6K{hiaqQp5rH#aq} zgaHJci&7IyQd1PlGfOfQ+&z5*QuI>U85kHvJY5_^EKaYT?C5pWK%i~^6fS=b4zChH z$7c+24lfoyi9NtwA;%w3@Z61Gpe04|V6509HNBjyTl?I1e~54Od3O4YJ!j5^qhIe{ zoDt={?b@?V|ANe4UAE6>kH{{*UdmAMzVMu`!r5tJd%ho$5ELx?X?uNR+S{`CwhWr8 zNj=>DW}yL7f}FB#S0*u9T%F#1JNtZ)*JQ0(m5+Yj^kl2pRX;N&Yc1oagg+T|(fzAl zTm9PS?vlWt-!EU^ay|bGGpmu`hPnN#uD$)om0*zX{^&Y$GS9i4JS(=zi8gdRm?M4t z=+8^l6FV4EQrEJcIDE{7HKek^Fij}DnY}b$rb(7jJJfd0FQ2$dAuffMf*<;461ZCh cewhDdu<0xC5!!ZrAt>NHUHx3vIVCg!02mgc%>V!Z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_leggings.png b/src/main/resources/assets/wizardry/textures/items/wizard_leggings.png new file mode 100644 index 0000000000000000000000000000000000000000..18e41a07887fda3a692340052b69b33fae4e92ef GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFf#M9iENa;euaU7K{hiaqQp5rH#aq} zgaHJci&7IyQd1PlGfOfQ+&z5*QuI>U85kJ$db&7Z%GfC_GDVt;9EYeD;rpw{Ug{MjcqkVflgQifE(P=i`EHYpyF!QLUTl qbn(ApSt74fm71T1bd>YguT>0{&mt6e%I_Bg`OwqV&t;ucLK6T6PkXZf literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_leggings_earth.png b/src/main/resources/assets/wizardry/textures/items/wizard_leggings_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..7b6a2b4d7bd69b314ff3bd15995a069e368641ad GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFf#M0*~G$ z%gX=lncJLBPFmR7ATqH*QYtvxcWT+n$@b6d<|uz>ve$bgUvYWiwsdLXxV%|M-epFd ziTtQGNtBgAn)zbDnk|(K;TNKM!lw8o)t*pfDF|C2syf9i;MM~9_qS*7zhA1L-IX{i zUS@~WxvsMh*D>GUCcJ%-%bWZ~4T-Zpa?WDe!J(ND#v;Fi{ZyBN_OIiDW=nU?YgnfI u_s5*pt&i8dJ|xld#OKb&G&9qX`1P#o8)Mi@CFjir`O?$X&t;ucLK6VrUVFFz literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_leggings_fire.png b/src/main/resources/assets/wizardry/textures/items/wizard_leggings_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..95c79c1062dda7f5e8ab7cd5e02f2fa027100b98 GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFf#M3&w;0^GF$9p1vpdpA0Y8$T_4cii$}+=Jss|2W58yWuPD%-O$vTHyDS zn5J9V>XZ(aDS%9h~@Z;YhVEa!h9k9xZLxvXU85kILc)B=-Se(8(c_S~AA&+alz*N`vDYtZ` zD;TVnB^WJRklc{t@Y+g9wx~M9jdS{G*MNsw6Zggc+n)5`IM>tE?e-7K_WI~9>}b(D zFuOBDt;^6UboPR?%Ws@XNDDP)Ffg7Wskw9|w}O(vXXz*U%qz~t-JW)LjmAx(pv}O*Ae$KyQR1ARo12A$JoXzbAE?b zxi9+;2WYKGEQ#vB?U-8iA!s8!H_*QX+w$5~PXYJiStyMvMC zRn-aK>nAx(FDdd;aNeL$V(86#Eo*Ao%E|W6>*gqbXR_COB!8~7{qf7hKl& z>ehUmuXK%zVS{0SXjg9>BLm+T9XI7_^^JB<1ei1)XQc2i4wu-QB-j4;?0t3F4Pg%c zuZ}iqFX?&DH<_>Iw%?r-avS$|GJRR{fpZq?4i3wNKoi;e<4!>BUb82kqF9!>t~(C$rKhW(%Q~loCIE9wdQboW literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_leggings_necromancy.png b/src/main/resources/assets/wizardry/textures/items/wizard_leggings_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..ea0d6222dfc11719dc6b2244309b6b168c22e08b GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFf#LUGH(s@yTic1Ae$KyQR1ARo12v`)}kGw(trP4B*>4Ru6{1-oD!Md9AeG^XeSV@3rM?e=pTjTVyV1 z%U(fznBTCHhOo=H=O_6Lki{1Wn>+nPEU7#L(TLn2C?^K)}k^GX;% zz_}_XQ>gTe~DWM4fJ5Iq< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_robe_earth.png b/src/main/resources/assets/wizardry/textures/items/wizard_robe_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..e0c8e0226c530c941addb8505455f88683d670fe GIT binary patch literal 491 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^J-8G#TRb|M-KX zISV`@iy0WWg+Z8+Vb&Z81_lQ95>H=O_6Lki{L&h?)Jj|!7#L(TLn2C?^K)}k^GX;% zz_}F~s6@@8pA7ha3dj_Qy^Wa?uFMSve&r zKh)+oL)Ub>ruMi!-=17#KXK9g!>i~S>>2Bu?rCW?Ik99;ado=nJbOmQq;K|T&z<}8 z`Td9W4|u*$4QJSACeL8;twpEf#lw%sK3wK{9<4j+lh&;}tHdI2REGo`%T+z;)n<@e zC)zOIMQw2oceVe@$v1c$*6L=4b{j4=va;p9{IxME`cWT`*f+Z}_4D1jmlt20Z1GFt z^nJUzkDl+2S>fdNls$sCXF|#@y9+NobuN2{hzm`znib?8FJe+P>FNQG+Id{tvSuzn zs#C6adLPrH^8voS)<%;=&uov%agAh|y}mq_;ok4Ar|;C|`1f)z?XnMeziSN}TX1cP z_NhZg_J3E12XUGi*X@1KW_f(xgE>3H(|pUnOgyU-o!F!B!=h2TdF~(SpH8hc3x#H> lbj05)s=Ma?d$P&upVEtE+OJ0kGxvbP+|$+1Wt~$(69Bc$!_@!) literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_robe_fire.png b/src/main/resources/assets/wizardry/textures/items/wizard_robe_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..6ab1acb81c58c09958b97753c5b70eafd7f9f2cb GIT binary patch literal 496 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^J-8G#TRb|M-KX zISV`@iy0WWg+Z8+Vb&Z81_lQ95>H=O_6LkiLZWOvy(wx83=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*R7~<*T7-DgH>SWvOLjfXf^J^~jFX$-M%3#;* zkln?}HfNW}C*_tkdEeT%%=T{o)7>+dg*%UrZQ@U)260yG%;?=(Az|QC1k#(l??&M!9jOmZle(=(CNmUuw zfv-O~4=8r~^li3WciiE;4_m^G&==;fIhPjgsghgvt}QVo`n|^U8NbcF zw?{RmXE__a4Ny@R)9k%DYyPY1ho8gwK2Le&#QLu6cuwpZ14n_{IT_N^vz#BbP0l+XkKM;pu7 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_robe_healing.png b/src/main/resources/assets/wizardry/textures/items/wizard_robe_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..e72cc3f1b5c7903e25be543a097f6b5f06fcf1b3 GIT binary patch literal 472 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfxfq@x1qa>&n2uAe$KyQR1ARo12hB8)hGJkZ7CVt?Il%fy3$G z!JrP8<$fn$D2SY?*Z83GAxXSN{EO_4&Qu=RWY$ zzo*V%|5BXcd9u%BmqG#8i(A(ja4=oW5OBSC^?U70Gv^CzZ8X5Opbd(>Eh zho?34$n{fqdkrTBJ$hy=RQ+?pIf)x5Ijki^x$e}sz01p5pZ+pLxH{9%^YRqu^jOV% zYma?paTMstv=F!Y`7e{{z{1UHzQGJphh1B*JmUZAFZ_AR<$^qqQhl4Nxjo;To|m(K zx_#%TM7Y(ai3+EU9_`Ig(UE-7zj$|G`ltNnvg^j*udG=6@KNHg|6#jdoBq2L-~XkV UFa7lIFi-${y85}Sb4q9e00~LLO#lD@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_robe_ice.png b/src/main/resources/assets/wizardry/textures/items/wizard_robe_ice.png new file mode 100644 index 0000000000000000000000000000000000000000..617a30013566139fc293ceed26d03f963d27d1d4 GIT binary patch literal 489 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfxho>ReplDb2vZAe$KyQR1ARo12R@u zp)Ik&@S4Xmk((CJKR9g_(=mws{%}{G=gOcn_t=g}EPHKdwpnJ*=S#DLO8M4E)FmmO z-gN2jYKV$jdxXk)OiMw9s lhWGa??tQ(uZc-WRf5vIwCm80%9zPEXaZgu2mvv4FO#s+0!Z`o{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_robe_lightning.png b/src/main/resources/assets/wizardry/textures/items/wizard_robe_lightning.png new file mode 100644 index 0000000000000000000000000000000000000000..fd873d5158f4e8e5531240646717dbf3397c2a6b GIT binary patch literal 497 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^J-8G#TRb|M-KX zISV`@iy0WWg+Z8+Vb&Z81_lQ95>H=O_6Lkif@TK)Z&LV0FMhJw4NZ$OG(Dmw!MW2mQ#V~EA+sgn(}4+V&{?r%xhC?Uf%jctzB zlm%bhIr5sS+uk)fy9ru}E?M0C;DYV`183)7@MRG^vq&IArP)Qq`v9M6zl-mZ^s4uF z%gqdT;hghL*Q_SF5xahV<>9$ChuYoKt>LJ=siKU2w8~)+V1r zjb{~as4<_{Pl{Z1rG?8<&%Vj-4YyFfrLxQojcK0CI`fvRiyRT;%lVQhufNnrwJ3D6 zPomF7MH#TL8Yn9X`Ix$u{ah)MJA-}8f42K|2BmfDr)GOvX>TI1{WK9yqTgTFnt zeA;o|vn#dhNejDpgwM&0-ns1Kj`N;>*jdjm rSRk3?v8Z(8|H@OpGR!?UPpW79qRcODbvhp4KrKQ(jq)&PE@{MbRyEfaUR5^c+ zGP_nThC3IIO_cj>ab`|@;o3J(JSCe=&I-TC(K0 zj-067`bk?(91Uyz*tC~xl7-X&^%UqaS4 zow#1|@4()VYoaPwY&SLE5?Zi~ZF$6|fSba9dbWn$I%e{%@Wdq7l}@(m&9jae7y0^;=i6zVt-iOM5;9;ioZI70^ZZr&t;ucLK6V@+sudn literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/items/wizard_robe_sorcery.png b/src/main/resources/assets/wizardry/textures/items/wizard_robe_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..1e71d8626da8b22cd1293743b73423af02ac2a13 GIT binary patch literal 472 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^QsTgcvx?U*&FK zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFfs|77%8N@cV}Q=kj)Hcn;;sg*1B0*p}|=6&A#(z_H5^~ zs^ECe&~W~HI0M6bbBX55e>j^K$Z_d(9eQb9KKo>$jB|Ex%|_Ox>H>lc2fo)btoYs4 znP$4y^wZUK`ahM_O9hV?cCXARlWz**nzO58p8UeCd3QVW3{*ueJ|8&qwtKnsZ_TA! zbX+FybKElLrjnOt!L!CmT#MD7t-j0OT*i*+JPeG4+id2Q2>o z+IYXgdd=O9@6Pb7ad*B|ogmkD^Vs3SM=_H%cBx6tbyHrtJns8{-dSyn*ME^VebBkM T;PWC-+%b5%`njxgN@xNA{s^{m literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/particle/ice_particles.png b/src/main/resources/assets/wizardry/textures/particle/ice_particles.png new file mode 100644 index 0000000000000000000000000000000000000000..96c99eade3c961c321562308511aee20aa2b9463 GIT binary patch literal 957 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)2UEx*7DJwkCaI zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifvPz0^Fa~=}*vG)Y?B(g=7!q;#?KJ-k z>2QH#^{YL$C8>5PORKx}{@XIaWO@wOOVxlLep``buYAofv#N_)R0;m3=WEbj-M3^UjXHY_jK|aM3BVpJ(qpnUlCsUzfSy>E4OU zSU#UGz2iFdP3PlJr~B=~q9)gG-sx6RH!n=yVbz-bU(PS#l;O@_?snPan40>NaQ^qF z@0tX!T620e|GRCyd;c9@zy6Ez(wfD2aWb5ja#YtAXG)^dLc9l%5txMexh~Pi_=ecPL%mqF4XnUU~||^*7HG&mi21vPgog|F{?!}TC^ zl;`sVUUn~FVfrE=+B50gi`IwB_CJ2ryt~LUJ}Dz(#YCH|Tc6sG+iy+{fBBMYTkYp- zic2{ZJB~kIvu@oa4;6{oa}rLkTlC{^%+G?9|4%-|Tk+TMO|fYYQ~i_w+u<+gyZArz zw&&G*-CA9==Gn(9&kZ+3KHQnS`Lf@J<=mYwugq9GE%J+V%*W3x?KMXinE&s|iq~(R zc6en%htt=5J=ODXG8yX{!c@Ol>s|foWUczfmf8AG4*TL3KC2fCn)&#c{xjT=e*4d> TIr}>U0|SGntDnm{r-UW|XzIi8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/particle/leaf_particles.png b/src/main/resources/assets/wizardry/textures/particle/leaf_particles.png new file mode 100644 index 0000000000000000000000000000000000000000..d24657c93072d5423f8974590e23d5a60be1d10a GIT binary patch literal 701 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4%caKYZ?lNlHo zI14-?iy0XB4uUY_j)~cC85kJYOFVsD+3#~niHh+53t@<7U|{m{ba4!cIQ%wjch_wP z5!+;*%aPiPRyGwV$NctZVtgtrbmLT3Zh_#2;I!3Kelmt~|7;Xl`Bc?6=}wEwRhFKs zD`$zUUM<`E-hxXdjd|bIjJW4#uFf$Quh21^cXY;@Nt++@al~kG?!EZjVuhuW!-L;{ z8b0cnO%6?}>AuVRX2zOHlOI2h%vmytsI zMt#Igfp;#Zp-%Z*7!UMC|8?^f<^J~e*=~-@2Yy_OfAqiCfY)H&(Y9*kml!ohM18tA$1`)Y4wha@b_S*0obOlMkG{Aa2%a zz+3hEfSvtf@Y#m)#kF+;iBJ{zFRk2i-)w8s)jEX_*21s8EH}_#jK5f@m8UOv z;W+!hQl0CaKUZeEcs=@Bquy4(OMv0t-lzBfy!rX}ZCJR_=kIs9JzsPFS(h;H@z>Qy zQuKdJ`nB#thZN_osIr6I>yO(xJW*D?{Y|j(QFj}c>aPh84zcfxxnIrJINg3#n4m1v z&*RMsLUx=#J#IYsxqRInjkhdy-@JFksJH$5x%hKaeEE*n+f&*XPhwzTVDNPHb6Mw< G&;$VV3q2A5 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/particle/lightning_particles.png b/src/main/resources/assets/wizardry/textures/particle/lightning_particles.png new file mode 100644 index 0000000000000000000000000000000000000000..94dc49c5599146bf0eafd875870a572fb499be3f GIT binary patch literal 2602 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 UrxeX%U|?YIboFyt=akR{0Lj@(V*mgE literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/particle/snow_particles.png b/src/main/resources/assets/wizardry/textures/particle/snow_particles.png new file mode 100644 index 0000000000000000000000000000000000000000..9d636de1d2c822c78f9b919ea124d679919da778 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|yk@Xh_?Fkt zz`(#+;1OBOz`%DHgc*1_w_U#}JFtZ~F|n z7z{X=KmXVNx#M-vLC4#U?))tR9z80Y4&v8mPXEL$puru@?Y7~=!O~~8heHoA?BBFu dYeJ-&#nZ^*-j6=~VGIlm44$rjF6*2UngE?=I0FCx literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/particle/sparkle_particles.png b/src/main/resources/assets/wizardry/textures/particle/sparkle_particles.png new file mode 100644 index 0000000000000000000000000000000000000000..d767eac39142bcb67c04a86c38c0292df9c01e48 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)2UEx*7DJwkCaI zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifvPz2cu`=(SDaOFStmNt97!q;#?bNgW z!hs@3&#w(h=?PR)?eVf!(c|fMe7uZ1cISqRE3A{Z{1JU;@KL_t@gZLCIh>u^id}t% zM_6aO37xeO?|PVQrE8ZU(3-=|bMN=={C=jA`TqBVX9{H4 zr=@OuZ1KT+wM1-;L&O=L)0<|@+&K5ppR!d)g&88I9X**csq3gx_AIxVK5ggk@9@)q z_9>%V&f)Rwat4Oj>ycib3>R+R?5wcqi>fIvH*b~C)1L3Olz~C;c;SMC%O-(3VwN*~ zF10@l|FE)W^~Pk;8z#OlcAaCmaPJ=9{qKR@;j>ruZU6MDN`-?d%z$BqYm-7kZl>h6 z+|5m)vDZtt<<5Tm(W2}ThkOHuJ0h z%72(!$=ZJX^n{5RGp{* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/agility.png b/src/main/resources/assets/wizardry/textures/spells/agility.png new file mode 100644 index 0000000000000000000000000000000000000000..a037f78aa7f02a2001c69643a03b4849883ec748 GIT binary patch literal 2200 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/arc.png b/src/main/resources/assets/wizardry/textures/spells/arc.png new file mode 100644 index 0000000000000000000000000000000000000000..ae5fc756b56a48a824abeabf20b7bf153d2fa92a GIT binary patch literal 2059 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 b{xDy6uH=;b!FZB^fq}u()z4*}Q$iB}7Vb%N literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/arrow_rain.png b/src/main/resources/assets/wizardry/textures/spells/arrow_rain.png new file mode 100644 index 0000000000000000000000000000000000000000..e1df005c0a9b9c775e537b36756d2bc6713ca4d3 GIT binary patch literal 2421 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/banish.png b/src/main/resources/assets/wizardry/textures/spells/banish.png new file mode 100644 index 0000000000000000000000000000000000000000..c321fc86ce0d3c0e4f35c1dce938e702237b9d0a GIT binary patch literal 2250 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 WXG3{AOc)p#7(8A5T-G@yGywqmZ5|c? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/black_hole.png b/src/main/resources/assets/wizardry/textures/spells/black_hole.png new file mode 100644 index 0000000000000000000000000000000000000000..f48a1f5d93b19c93005d18381ec7c7a6b6f33e52 GIT binary patch literal 2113 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 xGIf4Kfqj3h{|Q~Z9vaVda^J3xrPu#6O;zeKq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/blink.png b/src/main/resources/assets/wizardry/textures/spells/blink.png new file mode 100644 index 0000000000000000000000000000000000000000..77af46346158628b5770bf3c49804f751ea03b14 GIT binary patch literal 1937 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4%caKYZ?lNlHo zI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_WL{nqB6|)k6qruz`!o&>Eaj?aro%;*q&&2 z(c|^c&-~qR{oCH%o@M6q@3NT2pEb*zwaoL1z*2{37ca*ScCAp3B_U1DM(-7D@2Gk4{W{MnCB}yD>rELW zY@cjQ3#jn^Z zDhwN{o6i?7XL%mOzK8XIuV>3chO=&5=bVo;d=4<>U~?3hVj=ZN|NknbR~0GwYt7Sgi1wxJyFT{S?q|Ui)iNFMlXkZU)(kd zH*WiW_u5{zMH;Uv-py$;K5~(Z>!;$g=Tdhz*3L1Q?Wnp$;7R8mn|YcKW;405eejW6 z%xu9~@$gE9ePdbltk-5glCq+HvNlI43e3ONq-tRIUG7f*^VEV#%Hl^VW*zt7yWjm$ z<@mZ%X@RrJDGTgb&6O_Qjk;$Ya-dT|DdMqUm;1rlkAo? zBBAnv+)0AMi)KCW{97+9Fwss(iEU$3aDj%!(kxzPwZp5<80@e5*8k@p|M?F)&)3X- z7Si`QTzHO#QbOj1lCD`2=fm>nHJMd>k8m+KcKExKSdh0P?`k8(4uPz;B@0DfA6i;J zWyZ{%$Gq!*Nlu?66n(94GH+NghuhCL^Qtwkv2*NEw3)o$ve7KzyM?FFDbJ~1seA_~ zEIIUaS8A+Y(&?^5CH<60v$SQ?9%l3Z=V%b`w?BH~#99#}=}6)Hr$vSeAEr(ISev)I z^ys1)cP*dUht6yNe0_`hfA6QER}-!rmXKe}=*DdGQPMzi&l{t%njGngnjh|^oH(}D z^4*=itwmLhFFR#sI?Y=-Q!6?7vy9D_nOz?zT@85Ke ze(pYZ>LGKad1T2RJHam}^S4WI%DFlBw5?#PP;1UtVzO8JGA)q9-Q)6%nlj~hyBhPl zl4T2~d-U*L)P-*rzQG})*}AK4-Q?6_6IAVD-&tFu zetTP9dP+sl#fOGr>+iTsi9fh1F=D$=3d@6S^F;o=`#Jf|-SP(R{J5uY_N#Xodv8lz z8Itt)SnrR0{m&~?j3ht(wAmTc7o+DM5^*eHPm{qJ!|+%J^$sqMkkz7LZrU8a(lV!> z8nrq#9(^ya>G!na@smiV@`=06bQKkp=2#XlTm0So^oEZ9i2_p@l9@uB+nQ#aXq{1D zxzw$1jr``~`&E55{{%iJ%uBYfoZ8sfq1=D}{KWkFdH#1ldb=&=36?+eCI4_4m)BAu z&q-f&okSg{O!M^avDb)u9JBS%@2f&}7U$RP=8~!UP*(Tva(Km;?)4k0zsD`vIcu^1 zKemR&$KO5sa>CbFEC!Jej(RZ-1D?o3$VU+t(_1EbqtEOGJ(!n0=qGSK( zANP%to{wJ-%UJ(1-h{s52;t#nUi} zQ}o$o)@N^QlnWgSx1IQS-7k3EvNfl|c3S<`yMF3@(42h-eyAP(D__slpk7}i5j^jW z`UT;4dfAf&7KR2CEQxrvWQEnW6q)?^d1D@t|UC`>5cFXVT|YraUi{dUie8P_Iyw=^00n9FE&tzhB{_09=8cP>u#@zRj4 zaEr&#o7#6v1m&jr^cjoNp z0*?h|Un*$Re%kW%E5q%KqN=KSJyx@}om{OyKVjXp4R`M(2yVOjKJ9@nlbDAikCK?X zu*=4^C(qnwn5?zgQ__C=(Pf%vuT0`)TJ=?G-OVTK)$b+zJ}50vaIUoDOV!>dcl5>9 zF&EEm;c9r0(r6s+Z6X`;?6t|7rJV)}l0nw}9gE|(|Gi!Czm09ZKTECqrrEJpGMXN@ ztg5;nG!#wR!l%1vg~rw^ml#5(v@T=z+<5NOjpf(=wW zj%rGit$7~6u;oDYiS7BvbKT@avxPrS`}ZMm`+tTnBJO`8Ub5U}U|?YIboFyt=akR{ E0N#v@Q2+n{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/blizzard.png b/src/main/resources/assets/wizardry/textures/spells/blizzard.png new file mode 100644 index 0000000000000000000000000000000000000000..543cae08b69f5a6f6e51888de90a645fca0d2dff GIT binary patch literal 2745 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE({C|XBhtbe6ha9 zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||U=$QJWj+4*|0xCrE;mmX$B>A_d#6X| z$UHASUVq=*xH?{M`tCh%^p4Kf=?YVcUZQKgE$QY)S;h#5yn?v6n&)?3}=~aOg+9qG&-nsx!28I0ZOTp9_4Blz281_?$3QTZze6` zvj5J&EK}1w^Yd}b`#0W6)EL&T63QAG4RSrY_oV}eP*$}&7q@Q5-(-n z^t*eo`UVBs$6bCnDK{uL>dTU#l5fjSgk{;3J#aj9D>bcd-fzQ~wJ%d=?CaR{ddcO? zbF~#cmyg>&xV2RC-!H}2>w0F-K6trs@_pG~>if2H|yu^DYhI}nU8pt?)!6S`p@k# zee>tddVITIB6{h)Qx0l+mH#dp{!7kkJN;1P?^o4T7g=N-&mJu4sTK6Rc2T7@MM1}r zV_L3noaB-}UH9*m?WoIc?Oz|Wcpc9t)BaEYj=wyk`*^b0LywkTr^4H5_fgyH_4b3MGowOm?8KHtlp2^{Tv64#S>5i*%IEP3 zCc=-yCx=J!t4l~rJ(>FZ*GV%SHSVrmZ9XaoY7>2ZJ%rlQmM;0}ckF!Cdp#z<-j}l; zot)SH(m3YRQKOdmNuQ3$zvw9sJfXLEYF?@%M^C5XYmbv+cUJwV%t&gg&^dK}6W`9S zw{x4Ufe z>(AUWGA|O}uM^a9HnOc{UK%4O&mFYt){M2YJOZTN?wZ2Qx@ak{oZS6(kxB9M_McjP zzd~;QdH=O94TX4%w=J@Wo%%(pt5j9u!f%IIPc0RCnbLG|pPb+NsXwn>W-qkukB^C5 zu*Sswb5}Wcm#w4kl?g0@Z#X#@v4u=cvsrRexGkKGdC#vSEa(5eEWR@J*@1tBNgplV z%iDJ@zoFH5^U<k&-k7qQ#YtiNuZt5n9I|^|E?*T)+<5It>qC{r zSAHJv{(R%1gnk;6NbJF@vz|o+8eb0hp=xtYamLzgG3i+k_sP{<)QG=j@AiFbut@s) z2Uh2vS?oC7^YP(pd9(S4SD|yVSQm=6m$7Svzp?hw zSaQUGH-<5YW6JAGC+!4JR`Mtb7md;^q{#(bX_Fovy`o zJuF0K`efr`3#kceUd;{-duDTPXPDxpsuUY55wvKEn}&Gg+67&fYa+yxSE{rN+vOyF znz`ahxh2QU38e|!7FMcog=_2mT()fc%fc+x^J{cHo@LwES~P6+kZyWsfd>k^EDBaOq*A866x&ay{*dCJZ;1b!KK5 z{bPui-9J5Q?Wva>e@_2Cp24;AYE{+k)Cszo7xTCnp9XbCZS43E(-icfIi3HaWM{#% zuxa0mc+ZK)9AdK(5bXK!(Ad%UPD73`pIhPy_QkSwVZ8$THKinawZ6PNkngo*O8J$* zXv^GG2d~bo(;90{*a6<&q=cvM+c#lvLJ8V9zf zdf4e?wCVU>|722ok)z&z+JSdJg`S_A_w2>&{6*W!4<4ED-eVFV<mUDKJ@&}u<_3O+&+zhpgxO2e%r(L)B`Hx@r#oGM-sb2AW zt$ARt@4;1u7j+qTswz!&@^1YUv*m8Wx5@q|JmrP`RenD6VA@|)xx)NZ?(xMdS?y!D zNOt_%8F7v0hiKi}7ekUfr$Uy@=l`TPSvvHSuj^&537rQ594_Q$>4iRQO_?xz zsaCIteEM7_d#kERvxCDo#`a!PSn80`>ahKb!%jwSR%XScVw#+a94t+HzM1PAn-))2 zxBo4$f2Yy$_1C4&oD_(B`TQQAeQ9P;iJ}6l>Tb_F0xdd@ypt;qJURJKPi$6GiHXPN zz{Q7+Uh=fxn64AN%4)5UL-*e;*E}v>`o<+5ti3DQaGvMV%BRT zoti5${M)ZB5$gMpb4Tgvu`*nFnOo?DZ;aWQ9#(b3Q6|4KgDl(Cy{dOgqVj~8a0 z=e_BnIN?QD)s*%ksWbXI29sVU_fJo^S@QDzs}$Smhx5!T%MUAO&60V?S7e|Sv3_@q z-tIYi+UG=MS{fGVpK8)SCK~-x|2!UjC)tN5%H69s%s*~t=;8O@m0KJ* zI>WlSdNOU`4Do*J&x1wiOj2BHrZ(^nzm|-*b1FD z+siFkzRR!v#_@BFJkrvyzlfdN{$l?tg*Y3LE8eZwjuj=`c=T1+ullbL$KeHwmrwWD zG(CUs7p~xgcB`HmEuLw&uP}kXHEQx>)5%}GS_3T3T%V+txZm|;+0Lk7lPPIMYfmgq ze!n57y5jWw58Hpv-!NgV!42s|#ps>P36}3CbH=O_WL|SVmwlj3i7`h7})JST^vIq4j-K!+Yx(J z^mu*t+v0aSzn?q4S6JQ9&@gl{i&yeSje|nE`#g9>1(&RqV48MAD~omElz^pLOP99T ziM(~cmEmpJdnN3{(vM47?3sGqZp~QrcZ15ZlSe$yp7}d(=l40A!{xutw4Rw#a%fW>)Y>jR|@mWDbGb(ZaqRx9>g&w5k8yi=@|X56Vaa~2_<6$2 zN4zdFZA@L_$17@?d>mvtF1`HLmGmR=7>9;jzGc@!B?&o>ry`NJxSiR)?S0GDwRA-} zN8Td`@1E;whMop%6QYi7ITMj9n!Gjiftx@$V>qjBa*)#&79rMWKF&&yKB)b9l~AR~ z%s4ASjd8k|iI8DfwBQOgClj{bLrEH|4n^$sT7KE>brfu)4v+idUJX+A#Dd#;#W&RTvT`%LW* zqaQqmv2Bc{3VgyxcM3h@+O=3qsQ=L@E;O8sT+9{KMloI@(RW>)`Wn8q(!x`Q{=nbSq2RB%z(t^-ZSL}M~VJhOIu z@;X+2@BGBI55CvB{CsGwv3}3AtMm6wy(s$n#+U1o$Mk=SNSno-?Y4h2$?Sip?I!{E zZBEav??1Wd{J!ZY_w0ZW@!t+2g@(%nUpeV}*fe>ob!cfb-q`Y1MR}{Inas;ed$V|( z>*hzgS^Rs*Gkx8>2M-$UC#zncX!hS#a!1YEv<*L<*5pbuxPFu4tZit^UB=fdg8F&&-!oe?9NeCbehAW%r9@-yWN(;B}f&pr>s2*@(S9BH=6l|0&(& z|3)RL@6?g1Kg#_JKUyyYR@jdYkMYsIyFx#;OVRA`zil^v)}l5r}@pk z&(nWwVgAV=%KZLd&WjnRrzqT+TQ>cx{=d07?>+4*KC?5_Jl)8@qsA)z(K(~~Kbk4U z>6U*3nO?ii{97Rwanv;aPXGMb$9|lYSje>1V*8%Oi<`u=;NigRoE@6SH; z%edxmxqZ_2x8==W5Aq9m3lOZpYZhya0aPaQ-`@EI>r=JPjKVIXt+fv%$0k?wA zb>_B24aua>KKILo`Q^Ml_d zvy2yt=WG;rnU;Nsi6yCGzEU&W`8!3ziwviIZ?fBAv`_v`!~}&nCC3OIcb&tZ?2?)V z_Lv6WC}w-k5ITt0l~;^(ve~q{e>#}B{b4BNR0{mSyZ%Oj&^c}a%?P*Um3{@M z4^LPmwrx?36Mw|Tjt=(w>}L&&R~&21d*5gyF|E9{CYa~#zKUmCW^Hy>IQ&59)%v41 z>KGez!}%;KY&5H`7!(~@^5ORy0YQE{UT4iNk$Q2SGnezsn=gt?X_jZ3-umRs=Fi^B zr+ZVli(KvkqUB3C!9mWfro2Lw|Jdv4W1+1c#J^PtVOH=O_WL|CVq*I7iD3o|44f-HT^vIq4j-MKSu*9S z&dm3hrb#z&|R6}cvOu_c3 zqskp20RpaC+Z4LqOmMj7sWv&%Xy(lCd;c03a@<(|ZQkcO#rJo=`t)F3c zN%5yWAMXR7)BfiJo`|P2GGsYrGH@|Vxz-)@t`61lRuY`s7+}Pxz@lKaeAcQ*WxE4e zT$I;p%xZji`dDy)*ZnTGpcz-C>M8=X~T1xVlqGLbpcMB{y@qh1`nH!dzP!Z*t#M5wG++hV_JuS7cr7j@Zc2wi};z^@n~JEh07$Xd^723_9t%bW-DRp zc&RM=$*23tE1Do2fY{>dtxc8b}P3`YYZsWaaEsVurX39 zwkpQy{U^pdHf0*~TmCg0r>V>2KVHi!yg{csQaes9q?YSeRED3LL9k(okI7w!VyhdW z^^-ijc@m2mFaBp#2ocb7GM&)Hw@UWtOC`NIcMAW8-mzLF&T!sW)+3u~4p&d~FT1t8 zTU8!uhRo)^Y*J`(=fo68n>#H^tZmxuH!m;W@at;1r<+uxtv!=Mh=7#S#fe>gCNeAd z?7yu^%BfVXcq0|A_gnq%?=OmS-bHI(nVc+<3f=mc@5v-1-AVU!)@sVcXZhl(K>0a&a4?m{}_suj>zvPi_ zx9fDP?djvcH2=>0wterLd%tCsWK%uPJ5BRjnewzJ+mpLB@$M$Z9gC6#daJihzHo;7 zcf+%i1-I@#5fyvLA#!OBgZBCFscK6==nX~TtaPwBnI12n{O9r48!=@bM>NizPrT)O-SGJ)nQeJG2WMxsf4lpfsp2%-WU&R$ z%9Qtq$E$_)CEQz)=M%Gk{^aF;#+eR+e|J3%j0riQJb$T%{EFlo3)ZY)KKJm@+^MX2 zt^00T{pOc*3fa0~S<;EiR_~Y1uH3V+*R)v8@bk^`1+Q#a!)!kaM2HC;{Fu;F?N)j^ zM#}m3<(SyBujkKCxI5i(-rlRnPQ*;LJX|x^=-ht2{v_T0X9@f@SzWsVrreiXtrS$w zC7G#`c67yhOV6@Mf0U;;^{p(8o&EWX zwki5}eNNo9DMQ$=>dV{X7rY#8`0m%R<}P&8`>1A7uxOTe{=Sy8)qJ16aIe24XVYr% z_(rMhLdhF7b~$qLm$zI$|F*^2Y#(P=)9uHshY#+Py)6-U`-pV$@!}^R5@*d;x>4j6 zFiGoe+mck4)5oX6)1}&0EznZyESOLdlf*s4C98kY4U-x(W>@dW z<-Z~MRAH zOPyv)XM1NzH2pRxm=x;;8u~C#Cp)In`ymc+_dSc)>%KlT{PsG zBfn_bPaezE)IEQXzx1g{(akomZ=A}p`C)TxPSn;JF6p-a_>mxcd*ABRl5+jo`>YPW zIPJAT#&SoE<({n>M%&liI3b_^Q!={jy|QSo<7M7`Yx7j>cg!u&soch4Z}rYWD{2|5 zwpB)%PP_Eox!!)BmQx?Af4DVQnc;?b>rd%#MSngRHf=Rs;p7;qTf$g*ly%RS2WP(& z9$a;J!}IvxnR%Ln0%Ay?ehydP56wv#JGjlTe`hD6ZnW%J;UM?Z}I%P$&VeJlezu>?6Tj^ zv$v!D`oHGtJc+Z_^WUZ3c`vu?!h{_Ayw?Q|S;uu(G-oN8G9P`oaD}`59@}4=p6xq% zrnXu>O~>nS=V6yuSsmNkF3Rw|DPz8Bbn@h>LmVl_Uw3&4G>Pi3Q@YItrY#NclKzeD<6^tmPbcIM0|w!OQ1`or^l56+%^ zIz4$^+V@|o6my=Z=RZA9K26_%NL3b-Cg0X>pZ#%B$W?dvIAxU8r+PSlUG)4%Q{AjGUL0Wc`Hv zw-;_QbvgQE@tT?v#p^M1j&5#Gc>Qnjo=*oQyEfh3vfL*{>*(bDlINPH+dn%z^?R^1 zkMZM`UuV4c-ygu(a5jGVhaWZe2I{iYVpe#le(qh=v~2Mzt**Xl{H#Qm@7*}aMm*=x0T5tEmDiA>C00|t+1rn46e=hX4^ z^J|N`t38^L#&lDzJ;j>)_zkQ7QWoM5ez(pqs^MQWcmIdr{{Ku_s}zF0HuK(QU|?YI MboFyt=akR{02J`C>i_@% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/clairvoyance.png b/src/main/resources/assets/wizardry/textures/spells/clairvoyance.png new file mode 100644 index 0000000000000000000000000000000000000000..81ac7356cb1c26ddaec6c3e532b68579a70c9b2e GIT binary patch literal 1981 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/conjure_armour.png b/src/main/resources/assets/wizardry/textures/spells/conjure_armour.png new file mode 100644 index 0000000000000000000000000000000000000000..712476c5f716f7ffef9a48409efebf9ade46b6bc GIT binary patch literal 2197 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}&M-I`I~Zp( zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KnK%Vy4K9Vgp2fhxq2%e}7!q-~clzyq z8F$fR^~+c7eqQ%^-QIhq7TY@Jx;Q8)t!e3Q65?!$SBje;(6s#nmwtzWYX3>$5AqEH zPF_1aJXl;S8C)0?g=R(s3iy3c+ju>D{q^1VX5O7S&)dKJ>cfTAY2~>>OP7R|hF(8o z`E~B?@+T{gYn^K65oJtvV9`x;`P9F;vM%DFwS&O>?yc@$nq65K%*)=}Eih(mWZk^} zNX@?B#+d@94{TR7e3#(7pmOtnT#s<>&2WZ<#nTx#T;hy)DG|3P9$PUei_eNM%;9RsB92HE*8#RTefaJ7(@( zQ^FLtC*ygO%7&e1n```;xEl|yT)gE%V^GHwr6nRxA__|dI-NLlvOeGUlxQ%Wa$9#+ zH+My7-M?MQOOyG2GaT@;ZkNnH@PtqOT7q=xrjHz=3-{K@yqBFTtj+RBQcPpPlL^0> zs-9moNuK0qS^UlJ8=GNs?`#iCmt$PZ9KI#@Y_;GWlZBf~dY)Zm_1W4o z#rcv+qnAr^VdJrjtUhadR!;l;eyUJV--fGPLJ?-aYqzamKe?*?v)r18;_Ki4o-ng@ zRz!EieZtt&hdo18SRiFk2D?eW%BD%RW@B|6#nLQq4mRL!3^ zk-IW^lq3{*S`}6$giLtYqP&*x`oF(o%YvFzT<5T_-}(65pVJaek$b#1ItmDEiTq~G-0yl5 zR~?>mD5m1!6XS!MmCVf>d%b3ObuI`~&bgwoeKyNej%fYK5vhy*P1umX@7r|e?e-R4 zy;j>SQ;iCjJXA5y7I2uP7j@vY z&)b;CzrVZVpsoMB`Rn_y%;ND@_E~$ZWRj7uOeEXAWtL1)A^unYhTM_=l38{uVs<`f z)5OTs#{rgmKb$G8*A9{r6mVKa!B!VR631B4uUi6M-l4W_Ejv^gSmP{QUbp;{J|vYiCO@@Ophi=BAr%er}C8TjHH&yi?Yzk-FE2k#8x#Szq^7p@0RL0` zuWYPWug-Xtu~qy=MC{VA%!1^%TGh8>e}!Kw+^t+Cef!J*-*U$n^F>eBd-zNFPeD`v z@eHHX*Khw{xP52IomUDRQ6j2={T2QSZ`xZ#&X-h6Gj*>G(+FMl<=XYmDBWM#uLW3H zu5z7Ss%m!an#I0?DQnChyn5Shxn<_@qs|^dC9@1~yj=L0<*dx3KQYH18hnupoZTKh z>*>u4Y!W;t{lq(+{-`)!RSfL#mQ~i7d^>g(%a6N^7XA_ICVlxe!P0~Kp{LdU(z@bL zJ00v8o<((Py{esOc3I?o?75yjlYZK%aS1#x%sf^y>*3z?8&OBz^9HW>c(icG+XdTa zFMePn(!XNSImNpD@iWwwf-~AO>J*CEnY=&Qf9@)m6L$3oaXg-U>@Q>86opkOhdC?! z_iyK3dHOf={9>1n>@C*Ql?x_Jsry)R%Kn;HafgWg^FJbdT#^?3^V3q|6i?6i@-1P? zgTP07>-rKHzxyx-9aXuhY!F{~_vMpw>D>1o zO#NptZ}Y9fX9D^Ui~=qwo%{H6&AIb}0hwmuUe)c5jZyrnD8!dm^FvbVz_46CH zzA3GC&DW4fe%|WBmGtn}$32{>YI`&i_MOmwWn*s>@7R#N{gHEKblTmIK8ycfmpy;t zaL*nE)`bpyTQ_g66VSCvs#kdTUc%V5$=cj*gYW!{-y`)a(zD}QKI>-m3% Zdl^2vQm5=+$-uzC;OXk;vd$@?2>@NgB$ogH literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/conjure_bow.png b/src/main/resources/assets/wizardry/textures/spells/conjure_bow.png new file mode 100644 index 0000000000000000000000000000000000000000..641971804d923739b60d943d454db68125d2052d GIT binary patch literal 2215 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/conjure_sword.png b/src/main/resources/assets/wizardry/textures/spells/conjure_sword.png new file mode 100644 index 0000000000000000000000000000000000000000..cc78cf8ecc697194c3f76e4c467afb60c7d5ceeb GIT binary patch literal 2199 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/darkness_orb.png b/src/main/resources/assets/wizardry/textures/spells/darkness_orb.png new file mode 100644 index 0000000000000000000000000000000000000000..2be9852d479ab60c00dfb138964f9a7bd6f6405e GIT binary patch literal 1824 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE({C|n;HHKM~dub zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFbeR=iOqeK(aFHTw${_dF(l&f(dp6s zGU1}F`?vasmVPh!?sL9Jzo%E`=z<$zOISEtyP3rLH9ErgFK+n6FJRBic|_V=apE6F zm3h3IS|*FjC^a5Xnfb%)nDM*YUrNHm=bm*A{qA#HSkBkeJ+ySy)#|rfzrB6Yem(l! z|Bqe_@4m;|v~}CcGBZ?s*uwDOP}-rR^M3q&>(C<@vxB?*xIqhJfzT$ErqJIK7J|mk zMJWa{y+7V%pX{2OA9pjQJimsA;X&{8;Cr?A3$9`CqE zA|E9L6;|*2ed+$yifE$`_t-Vx#a)bfz3!H<$BWW!0X`dMEUa3)eS2hnezJ*SzCwP& zJSQImp^)`mfy_MR&&})g=BF>XwDsCe#}=<-Ch56xu7$qKBN&)xZoC+mTw~#2@lJJF zM{vXR3e7VthL@t>8%oGMcz2#zppCihq3KtFhK7j`4HwK1IMKjToH)&4%_fD#OTIAe zQOM%k_^Vst@KY9#;Ff}4+M&3$gEvaL;1b;6_ww+|k# ze50&RNBllhsTTsy^c;#FaQMkumz9feWnEQYvZ`y|sRIQTDSJ1&W^wu& zSylGm?wv1usKNixeTxqNjJBS+DYL_)^AA0cZuu#8s>dxcMP*0oo$me}ueW#lbcncw zUJVsGd@i+UF9jduhkf z)hAQ)#QHrVl+%3@d_3nj&3WL*bNq_;KBdEj0$wM2FIF@eKi2NemU&h#dFK1f$~eQ9 z6EEf*lKWnv`CDTCHp%LPaWWTp#VtS78+=i8mN(d}?BcjiXnJ_<&OS!#gAH@fFik$e zH0uq&M-`oWD;dn0Vgw+`dyHZh3V{ zr+eW!jh+6J&sUsE_c2vSZ@S%cLgczkxM%$rk$4YB8`%bxJIWC$=Y;Qh)g4@WG5_Yh zy5`)YMYdcmvb+rh`8gWS!OKd9lUn zfriD>G#`mi>+UJ$pVj<+{&U5nlIQC`7Z@$KH_V$_|1i2&{^IraFJC8gemiNpD8(r= z_)gKHr{0gb4|jKZE;mZJx?tvX%l2#PRz8xScU(;kv6^4dZX~vY$^E3FeYg1xqlX@$ z`xXmrkGLDE*IWI!&nsn>>Vq$F58^f&e3v|DXX*YWxhv#s!=?j@{j1A*4Z}UZ2pNB9 zZRb9leZIdp{PC_g#Z?DqPhWoL*N#x$338e>ekVH;GEGmr9-bnw{dT|gEr%~Qe0}E@tMQ8Srnk#c9*d>i!3@ot`0lxO)|y>i^?dR% zYWU|=ut^mS!_$iyaWqHxAnQ+W#;ruCEk2 zqOyRW&vSxCn!!YmMY-F{%1fhT@0#A-6`;qB+%qrJ>^`|7G&zdrj=%)r1eXI%O8l2BE6g1G6= ztlq@c)`dD(j;st(P;oj@Dt^tT+4c@a?f&4fTFMleB$3 zn{p<37|Z>*;y1VHih~Aw=8XtHKI`ZOCdS>#)(WC!dhQ~bEdeubDmiJj%(%iM)xwZy zDN)u|d{%~EpZ7)oA^j@{>?&3VDEbP`Nn+JrEx9{+%7&RMr%HY~ma@r`>!-}qo0(io zmFnsn-v8vOm7l8Rwpj5}P=}A${_9Q>nob;>re<<^UCPg!7$3v7jei+~;>DF}5_~7l zh6s9WdMZ>_*L6|h$&a_)7Gd*#zLMcC7Cq(KJTq%%P$Ad({vSD8Pu|+fcKF0{d#R1v z_jLyFo!T^WmcCHC-LkI0XG&|c!xMillM=Y(q9ME`;ZEtv^XHPSB#qjfcSfl3n%u8? z!zgrLIr-S0kFW9#WG1KAe^QpKdty?4zjn&h?%Q*A?>M;hs_&mi9TCgV=!w2~zis8U z)nC4qy)={7urALQ?`j@opAk8Ir?5uQ_SJ`X(d#$w-FWm` z8FQ~fVAK46pPtKDZaniPXy#(|)q6hsu`QpV9zJnR&5lDKC!db_@xsRMpp!@I^-Ost z2aQV_F3Tq!`eRhK@5qX$MmJ=O?#nKp5Z7+M=c87--LDx69P8ziigTO4YQH{nRlGo^ z`&Xx=+~xAZq~gBK>DM);o-T=%x1PUz`(>3chd4LhJ;Th=If2b-X2o5*yv=7XcM za`3u4Tn<{yifaDuTEeG`I@%eNL?&(*-nM-^pVj^C1{|4rrX1hDZxKk)DynQR+UOwT zbZz6wXPZ;HT$>6T>?Q8aVoIIiq20Yn{Y_f5*-@vyCgqB^Q^RlEyZ19F@#3!qGgO&A zeP*5ZTw6q2)oG^CZXw$*0&T2}?N=I%CbV@1a2+;bbX*y;AmYS@thcgNzx7QOCoFUF z?Bo#MCB3_+-F8w&i{GQpd3WYCIj;A9Q>_x`VDW82kWi~(qJ+Q4t9lc~1xC>e%A)7q zd|cYa9lB-i!GcY{oyt6Te+2eCyfH(PeQws4L`7q>t3NB>%(nPrKkM2Hjnvw;ho}0R zXRgb8^zO~0a%+{w=J^ z>sPZ`Ew3(_e4T8%Of3E6G%ks0mD&u7M|$0yj@#v}_g{Va@vUca6HjakSS>HbdV1Rm zJ-vjRVojdGlYSV6U#ps9W$L>yWAne8X4B8Fxp41>+9z9|<8~|!eu9$&8vHJ1wwTLZ z%y>6xmf8J(?}G2t|F?~pR;qCE>QSlt)eqUv=wD;#6gzK3pvT@aa^RI}BS3dgq`^UfH^TIo1XaP?n~{;vso^1PM9=TD><#`hS9>htj6v4 ze`qh8oGkD~QeClc%SoL%4<@S5OIsP{)){$CZ`+QF%IW^$vv=4|FUy`Dxc_Xzg;o;> zbw(@Bi=G@-OLy<%yE=R3g>4&(R2O}m@G403a!}2W=llYvj-8u+QY81@|I_XwUcosr zxrX}jSeg6(*}*0DKFTeA7c*;KYgZ`L^QB7hl+8BLU+*NPxJ0ew_Ka*%r z^YeJ*A;<0m(ht5_m00KA`6l=8#!{o{%#ub@C54~55|{ffOPF*lxkPHwWsVtp)``nS z*}L>L_I{pk@NS#q@!vHM0#}?9*sW{#<9Xz@uyDn10ZIxI-z52CFC9p|aXZ;UPN3a6 zY5n=D#o{NP`0_YANI3~L`CahrxNwqDZeskLo_Usc6E3_rEU4!B9eYUS==*IarxwTj zyDnMsX5r(HE)kCu@9t%5z9;8tlJcVL;~hPx-#u2<921T1+&-xJgx{k6-$LJOv)fO6 z{3`iz=HA@@9_g~ebi)E8W=~qggx4+d`ZKJA$fcM{rqGrvyI{x z?%qx8x^JFC|-$`tS^tn)v9`s$x>t2uG(Nq6>q2)(_Z(Oa7-A~{LOlYxPO N!PC{xWt~$(696$#8F>Hz literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/dart.png b/src/main/resources/assets/wizardry/textures/spells/dart.png new file mode 100644 index 0000000000000000000000000000000000000000..a91aa5bba497eb9399095d0099aed3b61db93774 GIT binary patch literal 1624 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/decoy.png b/src/main/resources/assets/wizardry/textures/spells/decoy.png new file mode 100644 index 0000000000000000000000000000000000000000..0db5fcc640c3510abd25bb11110031c71ac80125 GIT binary patch literal 2058 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}&M-I`I~Zp( zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KnS^(ig- z)~Eg(${g5wlfD1pACGqo3_I*{8Ftjav9K44tIF<>VlHf1ucgw*>C3E}TFup~HqZNT=H{D-dFSg&&QzO+moqTbygJx1U621lEu(UUh<4N4 zk_jq`Pb8CgmDoI!OjtHFbt>J-@Tl9se^(@M!ODxrfrz-I=Me#AaEHu7c4Gzpf*E_pdyVx%g~?6ZZ$MUZv7r6W*w6 z9?Dvh8W2*;I1m6s2$XV=8d(Q#^+zP=|=nI+Vq=>`X{oaj+=-o3qY zH~-mPlagZUFuHN?*sms|O+QXDly=>I@pwA-p?@NgX&uE&jtS1}SfnRlwP#Cl-~0KI za_kD%8VnaOt~pv7%oMQRc+!c9XP>zgI;C4IIWhf)Uze{iQ(H#0kKvm`8cR3wy;Og| zBXv||uH0RX*3e@G#j~aJ_b@8XNnvOy*nMd3(v?~<+uOa9Y9fvQota!x6vPONm31BEjtf4xGqV3 z_|5s%RiTU9swThHExB=gnV^5oBh8x7;1o&4Z6({)c-WXj-hY~0Ec~wekKrWa^aYbQ z)E5XB3aS+;6qVc-Y-ngQl}HaX)ZkJKSbx1`Q_fyND@O3pGeITU`IP({w@CuZF6nr;75|p}9$GvVL7( zN%rIllLrpjdbKZvGS#2%od17{_Rl8!nwOQ++9%zWoo@f_={B*tZ%Q9$a;C5*Ze+_o zICC2u!mD;C+*zB}B0<7s`>KG~cL0v|Lc zsd%Iqo|~)GXxgzc;&qf|RO}0$HkG|{uho*xXMcS8nP14YPd}z&#`<}COT-(CSf0Gg z&Tp`Ax+GG{wo%OXY=_Hj`(Fpn7spv?FMb2ta|eu~n+4Yt&p45^m_tosA^R5c&11-zX8e-(rl$9|Yu-6Rmv7%# z@bbtTFAGJ-h;<1Yoj!4$5e z(O_>`?}js#7P22Q%3C~ztoHKy$ON`Lt0+oN*yj``x#`@A?|cig7GzyGHs6ldl_gm@ zMUr35!)O=!{_=kBh~sC9e3nz2W=y)29P(X~&aCQ>%D{`cpYOX=kw<$nGXnI;(( za^cDY+aJLy1`iwe&hQtD+{T`q7I|*xj?=5_e`~+qbUA{eET zcYJ*|JI5`yWM9+mlhXZ}hhFkzTvk|TyVatbCAaprM)O)-z5mZd<#zrM*#G-93@U$tLp* zW}myb>ljNe``x_^^WNQmr2l%eg))o0LraOpq8Vp59xM9R*!}18*ZRaYiXx(Fy$MqV zuSsq)Z#^+FT=ilCi*~Z7h@(%iA z#e9E*;mie0Za&s4t|(7!m}YX?^mVrNTeZ{$QQ`##?ysa)NoD!(v{3L8j@jc`DboW!zHt0vf3qPOGGjJ@USwp^2Gxth~>qpZBcylR7%0}HR$#{EjK zN>*HF4Kfcfmypjm#U-v@^L^!5J^5+Z%UO@Bgvj b@qQ!b#ov8av)^Q3U|{fc^>bP0l+XkK6GXBm literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/detonate.png b/src/main/resources/assets/wizardry/textures/spells/detonate.png new file mode 100644 index 0000000000000000000000000000000000000000..823f9e4c43b870fc04e6c5ed310372e806df0cab GIT binary patch literal 2120 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(~Ds(|LD20|NtR zfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=fKfn5LyYmz;uj1I>{mTq977@w@0}jKCMHz! zc>VqD*X|iVH+$ancIDG8F-=M>tB)`x3Gzg2WO?EkKOumtYsrD`&Z!)tTuf6Xl9hfX zFqx`6dg|D`WXq9`2Gs=_99c|@<`hJERY%>vZ2a8FxO)B9pBuiPnQ6JA|6NMzx46xl z_usDnyZ^uX_Ly7gI{VK|Sm&-8{=NA8>(lS1+bbWc-)(bXxA8T@J$DwANrwLWF1owt zxLo_GyL#?^G80wV8Te#QpR%_RRz5U&J(HN==Axs0%(tE<=-97W<-#1&sie@=sjy0B z{@TqC-*C++Oi*Je`1o?MkL)aMSqMTkVV3rFo-XpO`j|9(QcOp9Dq3v$mEM%jN^xgnLIuIj#7%)O-Nee55^xX;Wm z3|cMvVC&N6Rd1D_GpJAC2oXJY#KN+bUv>OgeOmD@5BsrJ&6vtXEon=ZW_9 z`}(GaE`FHUYhJUt@pP2U#}m#K#xe^c&T}r(vGlU8QWjmox#rs;ci|nE4kxj;v94k= zWH;w~r}V-3L6O9qhO3kJH)*ebDAL@?Qn%@GV$ABsXS#DDj_;Tj=pFv7n`g?!H6v2(Kb z4@K&1zHoYpS2>%;qBWKl2PIds`?h{rkoY-F;AYeW-UFswhrNnCU8F8JL~MO;z9X!; zu9cHt%2?$|M=MkECF$DE<3^%sOSqV|<|rK7A>7pdDl35HEK3-pbc3;j-!Gm!(apvO z*EXz@s1m5jp6EP(@3i8e8-M@4U#O^H`00i+zjAEqi-(PegbylzS-tTR=k(tvUdi04 zUa-31a)aT9*V_+G{HwEOM^od>(hskfFZf^jC4*0L?iPNno|Ov?6%?niT)+L@>hID6 z4HG&H6b?-|&~PA!DNiJcZOZ{WzE98Oa-J%2TAsb=_~uc!;`xn*8#r$r@riHXzIsYI zJ;8gWxWgK5W>zWImKQ96T|1V6g%=Ys(D}B z`}E-5l4$=UTA%ivyQAs2*Y0>hE`#7vokeOPO%M5Tbbd&M=7Qzyk~zVV&H z3(pU(Wt?r*_2(hyjRHBF?@}@>eNHCId@3zV4xKRe|J=v9qveIoMN5aStc-lFEsq-< z1ZK>OPAJ-UQorc@eb*U#zi7>Avg)YU;mnzT=$-20F!R1IbKS#a6+(VxNbHc#SG8)l zY+ot%ebbT&KGUW;%u()cWNmF`{I~7GAy72^c@*0h6;QZY{%Ko zsjTrh`78U$)w*Zpw!Om2OF|dv8zns2@$lMh!cD(`>fwRB{^H~(TN+ZGS8U!`r{n36Iz}<(1`pmkpJf1;nO>fiXV$L`FDD@ zz6f6A&B3I0DbiLoW4p&3W%1O@+t_dHdn@GAuzcJ8?w&5cX0=bbCvaK6P{X^YPZpPeG7_;$xLrFB=2Jk>Qh|Kllty@S#P zk%ynn^N(E-Fa5@OaCyrTr?|Ju7XCh~W9o0eeZmnL`Dlfg%Z;k90>SOixLm*7>-l(T z$>HfuDuNzoJdXUh=zP0Sb#K;*i4ztZ>UkEHx=c?vCs^y`5wvK%z~1NGOFw=ydd{)5 z=-#fv2`gXzRF%_kSt=OV)XHz1yMG_lU8)xH;A#0KCyN;mH#qfq2MX!C?yf62-hA39z#ul{xNr13 z1@jY2dsiOXaq`j{frj<@GAt99?p$!VWpim;wsQxUAjjL4ZaooJ1+Qbji_E#l={RHU z^-j0vD_C1JoR(M= zG;87Nxn8q_Tqo$U-%7c>u2TK&fh%8X)~jXsAJ0C{Uj1a#h3uT4_v&Z$S?~Y!Z|~E? nFRv`zc`xq5y&v`c&;PTTtuCzzjZa|(wFo?2{an^LB{Ts5)*0LY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/diamondflesh.png b/src/main/resources/assets/wizardry/textures/spells/diamondflesh.png new file mode 100644 index 0000000000000000000000000000000000000000..53a0cce96c61f3525299dda6b1cf917f9938a727 GIT binary patch literal 2132 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 B?CJmj literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/entrapment.png b/src/main/resources/assets/wizardry/textures/spells/entrapment.png new file mode 100644 index 0000000000000000000000000000000000000000..5f949852e2a1b9c2209e6f5e5da06bc161223d21 GIT binary patch literal 1910 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(~Ds(|LD20|NtR zfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=fKfn5PW~fPmn8!OJF};YV@Sl|qtkEqtA>gm ztIvKLTbg%wxxPcWfBzw#N2(oyLaL6!@}5sR!|y-b|Jk>x^W#YgMK?i?tRn?83zsFn zxIO3c)#o8|Z&mBcuUa;9US|BpNnTfPE?>1Tzdn0y{(9Z~KS@vi$oF#;eE(;D{^74> zHNFfF9+)t0*e|+spXQ#w(`)ZI#t4K@X}ByXx@CWvykOuGX{VNVmZdHtM`nf_$NhWw zP<2lDzWqnvR$sl&!cbSW`N7-$agUk9@5mOizGq-&y&24}mEy0_sIX8ug^!781;;x+ z+lMc2vDN>pc7OMEzHDqzjQpK9`L1=p@7aA>(0JqQ9pzUGr9TU8ywG3zzuVp5Any^U z@?GCnxgKF|Jn`(8S>uWPdpCDa_%GD>dNz~Z3XaAbcZCB)d=5_in9ys)=O81vd|TI4 z{m7e>j!jGP?$FL_O4oBz*Eq=h=%Z3izu=F%)#n8?1>eU7yiaS=bW{pd{`{+D)!dC< z-m~^B`P#Njed3yB8(E*f?6C^XSnspI!ACGKglXcW?f35Pk6~rdVk}k;DEa9A+rnMQ z^!ZA+7>_j^A|*`XE?zQ+4K}U!xF@vaK;uIH1G1e>J2q_Gcks=dEx}&{neO%r9S%6; z{6PCo&owC})>fXIQ)0K3&QF*aIO9^4^V8#VelVubNl=kmZE$`HkHjm9K-Uk?t zPOe{?%Y`NlW)&;9eN)({i*Q^@tx>votIOx`sq8kN8xv>Sh}R$LyO(e*e9kHH5Sd`_ z*6K9v80X>#$3KQHt8A}dVn4xCB|kIxtOAeV^2zZ}3Yl1ySq>U3n!aWaV&WP0^XyXEH_SYB#N$@iW{-H=rsu7d6&be)-t!A>!h5E;j?_m_pVK2&FjfJGd6y5dAdBOxL5v2 zc*HZy`A@&Ev`kM;W;1(t_9Yi=#DM>%9dVtqV`?ko9&*PUL~E8 zFVX>qwmU5S<5yZ4p_$Fq?ULu^uS>i zy?5tUtyS;E%AAeMqFp3Q__SRA+b+(O z?)g)|WwWNCxU9}?8cT%#fy|YKJ=0W~dPLPKIm-KiE$=}qmOfyKvWuDe`yHvDrl_lJdkH~4<@NM2r2 zY?2}0C8~5PKy8ZAtKVF^n;PsQ4)ac3$9Yo4?~mT*nj;E*62GVXOgiSV-Quh}Pl?Zj z6CT$kPqS73l8LVB<-M7FhVA|Ha?7vGo7A}^OSvZ(UAz%f=JfMcpE7HpSJrBaZM$pI zYu^$di5u%Y)m<}%cgOMLF#PYvKuMWThCj5t=?j?W`$;LPn(}E zM|kT3eb?|iGE*D86sk`z|7m-zvMK!#w@!+i!i7r@lCFd;)bMY~4>VeMf|*P9Q{q2c z_HTx3&DWeXo4mm>>FU;ss#d|B5(x@TUMVM7iWh$pF8GoDPucBs`PbAY5tBL19BZ#w zoD;jQ;H+)>eofuk`ajB2=L7}WtdzVOS3iCt_nM1UZe5227n_}uVPdK`-_D~(XDzwP zZ+w)tiT%@Y=(OIvq&wS{{dOE)`$aJR#{S43JclDL=W^kPR?*Ra%9DumagQqvW~B*HrIIBtdu;Cs5tZ2ZDqPu zy1$igSNk0fLxX9hCa#NIvZBjYFHrY;^I(xP+wr3(=lx<`ld>quHYikOeVX##_Gw0-yV13gkW`QRr=;$)bCZ zanUst((;wvu^~SnZnKGiPtP>*vYiSZH|f&r{Cr??c12Kb-uT8~495oG<@xro4D^*j%N( zwPm{(xaLQ7bvf0Wo_r9ir|?BP`(3L4o{zT-52zL}RBo`Yt15pheRqzXf{?uIk7fP; Ynf_Ozopr0H=s?o&W#< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/fire_resistance.png b/src/main/resources/assets/wizardry/textures/spells/fire_resistance.png new file mode 100644 index 0000000000000000000000000000000000000000..5fd495a6d618548cf60c57312e0b59d561e420c7 GIT binary patch literal 2419 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)2&Q4l?{#s@(dI zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_z$hT5&wAG6jxGZOCxfSpV@Sl|qthdE zVy?;_tABo{`gv7YfBGJkZ5!vd2u!j#bxEM3aYB&81U8OC7&}wU`~gr66@vO*6v*TW_6v z)_MXNOL7`G9GEydT@pPEcpEdl-b`SOdR)nM{yIye+Jy!IjkTEU@< z|BdY$b#ookyHBoj?3^OyoS~y>pz5OAsK^q>LQzJ6jDoEPzKVLyQkgCMq+9i#&4Uk*n7_Sc*)@qt@xUgP#M>%KnTOQAnBKmz zOhL%Vqf|e6LB8SdKKay}bGs|5ju-pz&VO=apRO^WCq1 zetn|;6XWb#)+>(dPFoY@`Rzt!6T_p4R?Cl_UNVWZ=%-TD{R;TlFF@k+}o zzH73wUyi*~3)S8D@}};azsC!g#mcKUWLzF7?JCk%{^?)&{c8NB zou$0$$Goq^@ZMT_Qs7VG`R7N}PQSVF&32a>UvfTAU`6$m)9wBO{E{X!`^WuT)B1sCBb$z< z#?|hKxT%Ns#lG>lf4Zuk_2MBO>9|{d@%v7_-e1wa>bani0!N;P!g^r?m9iU)HtRZ- z6tO*j?6}5f+Lyn>%y#4&FN>YUJ8JYyC&2#`Pv%=1;<_?3!5n znr5xnyw3b-Dc98~R{M;nQI&0XLijYLEx6eP8@L`E5}z)y$@K13p4{x|7oYh|IQ`_q zUWTQnQ5+N4G6aH@mb!4v&=up9WLnDV<(2f3rE{N1S$Fg8TSxBo>lqn6eWX?DEgloD zFkfFtgI8k7G`&SDSGT_Tx4C7r=)3i*8+e(WB{*~qmbh>f{?(l3)yv5#5tPI{m$f@$ zQSYyesU>Qj(ME0yLzFJ`ChzuTrJO5uvrFRu{HwGf4R#+`n(f znX5Z|4;pFAx9$yk{Kam|G_Dbpa-B`10^?Zj^0a??gEb)u`d^Hv`Ed%XJCC80c{%-)$iUzSwv zSlavLm*|UwiE8WQj?Lnguqt6VAD$t_eg18%f=c5gi+!E9uN``59G)?G?v~lkD&4+I z`h7k-ycYTufAh@2iI*#GN=^|HNz2Yqn3nVC+&+{0l@DicIaaMHUbH1I);IN$ci)?T zJ$oKM&b(-_a00jXgWt2f&Zd8FU;g9I0fGAw`#Sz@-78~LJ@u{q9WSkob21X=yw9(h z=Y86JhOC`)<$sHxTO7X|GyC+{wP za+ok34}HST7kBr0LS~Q0=b(8vzUkarTl}j(f77?6%Q;sYXutQI*t=e3Po*vE`Q>}7 zne&WJ9+BSNsj9@{JuPTY$kVmu^`|c^%}n#w>*ME2UibXRD<`E3Q4cDm)*iWY>49;@ zACYrMDnD)Ivafu4{7Q*&^}YJ`ujTh0Z~7)Je=TBX;rRRYcfmjJR5n{rn^2!@AHJ<; z)2?FP)8getFZM@jmA0;Daa@r9vgtL;5|ay2j7y4;@;J(@Jb0G>d%*TdIi|1zgK#o+1c=d#Wzp$P!fk7b+y literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/fire_sigil.png b/src/main/resources/assets/wizardry/textures/spells/fire_sigil.png new file mode 100644 index 0000000000000000000000000000000000000000..63b0993dd8d2ef496ae7d360fdb045b3ed5acff3 GIT binary patch literal 2060 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/firebomb.png b/src/main/resources/assets/wizardry/textures/spells/firebomb.png new file mode 100644 index 0000000000000000000000000000000000000000..bad4d72863c2f303302f0da86d77c701fbcbede4 GIT binary patch literal 2002 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)0_xCNpThPYOK6 zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||;AG)pWbyCwuwYuam~GSg5C6C zx7UighQ4i6f~04K$pyN#huree43)g1#Me5Li7$rj*}k-QkKa6PuYEUHGVP1ng4!csi>Ef zZP*aey}oNBl0aS&P>sFN8uNh5IU53>WCr+H)?X7GLK<}x+bz5Vr< z{)q{0lPy+duUKNk@!kHE}EbIyh^1j(5!N0nT zX^~>?;&oQc`Yji)=kXt9VGLa0y5PI?hNSX2`tLfO#AWJsoY+$`$5q#Gn_sK$_5-no zsq@yK`KlXi+rh2a+{Y^Hb?IYOrcFcC6E{(RQTrY%MFZ=(3<=Z3KfGxZx_{P%VTSbD zBKJL~elOZkAf@AVXrH^z{z{buHy6(?p}=nbid81drRO?d{U~&0LWMxkdY2=v6NR3B zs5{(ueyU|*zzor?3^jFOQ>QfUVgIOA^H%YN9n0LxhfDQCe!94~Y~onJ;t(ntXmF^4 zp_I)@K(Ntbf{;hYr(YY~EA8*h-=Om=<-pR(2CA#3e0B&Ho3d z{_A8e2$!)F2o(x_>cjdgbmJ-s#;5fL54r^e75RKRIX)+y(hXX8)WL>nzGOk){NLZ0 z!gAj}JMpV>&tLwCDkBDF`;K|fvn1DrB<3zwP1EU*H{)S*iWFtO@&8zZ`lBL-j_Nk% z_*G8gdnPxz$;)Y?Y6(GDLC!ZC)@JP((hvF?fm8W3mon{G+O&@pCme?L_Wp(;qup~m-Kd* zy^%BGWB9?8d4BIa`A|Pup|JG@etz$Gul{~$bf%O0kHxiPrxxdy9{(-3Z?>$lF~bdm z%bUdRStN8wedztHDC{}mY+9zL>POrDB`hWH%yS~8#eBqhyd2)G_3JCq_I^Ky)#5lq zyZx+%@AWslydXI*ifIq~|2%`X5f!uBk7Y z`t`41c%9KQ!9G6^M*kht&K7HiKdDK$F|&Jvx%5LP*BgPaihI)*9I%#U&CB)_l4;)5 zXn*|SyW+JBIkWD0ou9?C(M&_>N$8JfQ#B$@LrirJ2J+0f7`mXr)ajzr`v(Hc*}eBf z>jVoqS6{kh9`N9#OWVHrydPh!s?_T|Jmo!m1DaOC;5T}L3;>od*KTdG7@@-9z zxObV0^F`*l4f@Fuwe@T7YV5BFT+y=aio_JoB8MKv(2$tZJOOJo&fBhv`6K&;X~uq; zc~zFq#ms9ewrnnoywjm#x>s@xnnG&?iTlIX69jp12g^d?9 zD6P;4&DLaGZQWAazbiveo-Mnz+xddA<>7gbjLK^~BCOhZz8}lE`|X)_;I_5e9}np5 zV3!DEcQ{-v!;sbeP$%59ZPEeNR(5M1O@Gf0?^$X5eb024x3{t>PkCHWcH@HWlZ%fu zkAMGRvpZ3up?+%Ov&#W)0frg55wh$DBv>|FOA=hum>9~o=5*_fR<_0!9Gcv<&1|6^ zk`>Q(efYjfvE3lVOvGize-j=?(bg`GM#F{we9knqOx8J;(C8p4nCPL)=;S$-Lm=>k zqRX1em%=OZBUUI(5!6zO*&DY&B|ucs;L#TG^zC-r?sGhNym|GWLcK>qfp=LR|Jvs6 z8pFn}@w8x1QS|nMEq7HJ);;A~SYsiUdSqu?It#bW#-d9sLJT)^`br+Fgs_-9L;lmnDlQFN;$x zu${eD-X|+}&ptV;uqEp%b&Cw!-mmevbbJ2uZ!1@Rj~1yW5;hi=fjh z7SG%vyXD@o!|B&AEQ!0e^+fiT@86yuH&EDmxsdnb*zopr05CRwzyJUM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/fireskin.png b/src/main/resources/assets/wizardry/textures/spells/fireskin.png new file mode 100644 index 0000000000000000000000000000000000000000..0b0efbb5b24c051119824a61c66bda732c40cb0f GIT binary patch literal 2052 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)266m>8J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JTknp3O14VelswzPxN$g42d{=bb4+_ zTB_vn`s=0hKcBHVzsJV-+^Zhr%db`~yc#Bdvn+ zp`iW7Td_+qvsOUs6#uTh8PQQeS{cildf%N{_qp!e=c>4MtNEYLoO^R_;Fn5}T6xWkp+TGf zh|LdvfpP=q!Xvz;>JN@s9CnCRoW#}BF@dqxyhyl+$651iLFk>i&wfbs+s%HYb*Cuf z2hTBo<{5K)Dqdtd-Z{|YalqU8F2_3_ZIgy#CZD4QLI(p>b~xRhv!vmy%q5{;5|Ula zOQjbzc0RL^_B>SU|7FM13m@_riiM39>@He5LohHhPFOsjkv&fZcp4|6O<0Po@M*I z@WFwAgZ9lu2WNc#w^CvsxBOnMN9zQiKj1iX+|O8ow{eyOk7zgZ-3RCX*1vqurobF{ za@u~@Hqm1ud?v4BLbP|5ta!3X@cD72 z8zxC`yz?!A9!ftxx7hg@D`S><D!nNo4?9jsChpMn zSh>k%(h`-md}>afp^w+!IkUmLLH^JipEIq$-7WItWtY1b>pc7Ol1==rd}>|Qj2{mS z-Ug;F6$tZ6yxd~v^sp&kb)hWJ96{E1ZL1UBsbsdFRrFxi@#p$|=H4x3XYYQQYP>`x>5|uUL0zFWoTX3e()iuRA%G zHiYgKwVu5zSA501I5jW7r@NOl@Qa@-^7puw{G`*>Mk?K9PL)8L^1_7*^M8wca_G{w z5ohvzRuc0DO^Lpp6O>CDQ;Xxy_FO$P zahmZ~raNWUU+<|*4pUefyPcQZe#Z9Q&v)W=EB-j(z9~KgDaa4 zeOwR|=XANZ+9u6VIPT^NicLr3^{6=XFqOilw0*{ z?#xDqSLas7>@W}P>l687&A-Rz!Lg`=!K*Eob4BPWXfAy3biUQ;$(CQW-HccFem?N1 z>fqYzS9X3s|FZ89pLFDQc@B-v+I#Au7#c=h&4_Pq@7B*{aZp z-wt=IGvY0-S~WA?oYl8oVDHs{Q+-i->AcI|mpI&I5}Nz>@mrtc)pqX_jPCvX!yjwD WA_N2h1@ zOuH(2y#Be}>D}k}KA$r%FfdT!TQFr+=!PR*4}$J6iSEwuSt2Seyed?Bb*>3-ruMO} zPScg8-pRLuwp`1)-LasPJI|F@RPeN&^ya;1cH6!GZ1eqIU4Vf_-L~hCcgmmB|G)W8 zamv|AQ=b0M&~vzdQGfoz#eoa~$7TNhobj)w=Fi8+f2SR4oUyZ6albD67GBqqXUfmm z6#H8kyG3=pcC0B8wRbFDre70!(Ed=vH=!k;nk0p|nE9;BS!?Y4()E7NWIFz)N3XyB z-3A#U-{nRnzoyNW;?d7MI#YK;SoXa6?=H-1wB}f_y7`m0`-kaSYW-?2B=t7h`V>wp zJSon*ed?(-y31GO`+dClPAgd|OxJJjf**yf%S?9WREig!GB|A>Gskq!tc^U@PJdOV z=WmZ*bhF@Lsnl!76xoRVU1#>!civ8aS@|eu25Wk)`U9!uhfY}?4wfzbVK4UA3*7dz-r`VldZ^XF$hDx%W%g4^G1u>1+?{A+o)#T1S zf#TG?%N{xYRh{rs?3usj!g==@P91ukP{;eMM5AAo^Ztw0s52j!zbAAbxV!z(72Oy6 zHJ;6@7HMdnmsD!CNPF#!CtUT_k2lXM5cB)~PKzx;`_Pn@rAy-swV69zx$HAPc8lF= z;NQOBE#npAX{YpV+%hWr%`fXy7(t+x_uBC@r zIU4!9R;+Eat*-gif9%c4<5P|ubeq6tq<2NrLt{gP6SJs}l!hdSvj&6ec_A%{zs^nH zJQdHpUc6D={dGp7(t)G9x>%o-HWur+FH5=kb7I>09nW6uNKoMD}n0au7IiHL;wQ+-KiN%ECh)3)N${&9Je#r4BN2bp4(-E^d3zG#JEte) zu2u5gjV1NqF(eSwKMKL*>u2g&a^FOX6opK&6?MuI9(tr#)I<++cD*Zn-_TQ zTlkRa!L8BjymP66wdJGn#-%VT;+hZ zedF{`p6-lCw~2_ZP@tgT6FIE4bS%nXIZQD zJ<7>h`E%gi1e3FYf_Z{wkUfh;5IX>LDVp3CJx9LO8 zroObSvlrI$s&QRpY83QxlhDc9R&95<-E{Hl?Z%%TWWO=#eItE=XPRzn1c$(uhUE$` zHEYf<-E^|K@WBP6SLrZvwWh9`v$$>tx{+VmLo_cLoQ2t^0L9VrJpWBJG?Y+A-B91yUbIPr(IaqG9 zLiSr2Z>?NKZ`U?^=_hxW7wlTNd8^xRU324~?fjFuoU}5%x3j+GdbwqT4M*X$Y=%e7 zT{rVv3XE>pHR^c07ub57-Lt)I?^c#}=F@*Tqd$h6edzHqf9>3%C4_EH7i9OTOxgqxHo$cz5cef9DuRA}rcJUqIUp!$v+~+fY zEV*INdvE4%7MH%*Ywgw+%dnr=H@qh&B@XqpG+}2%D}+D;OXk;vd$@?2>_Q~ BWDo!V literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/flame_ray.png b/src/main/resources/assets/wizardry/textures/spells/flame_ray.png new file mode 100644 index 0000000000000000000000000000000000000000..ecded28b951636a673a3682bb18548c380eb082f GIT binary patch literal 1955 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(|3M3=C%ljyTsc zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL-|c|>^_8DI5ob7f#)H}G_E42d{=bo%Rj znRL-(_0RWg-Youp-Cn=qOrJ{@N=qDs6tpggP2qA3xGEON#U-$E(NqVIn$_Y#t zd$c-mG-kA3k>&_p%JkLQNwsNdh)Qpes;Y0utf-wg*2&(k{&??MEx&x)wLaO;radON z=H9$nIq&nF&-JxiglyfU9G8lZ@olXQGnT5i zG0n2ozd19GW6@3hRV?22zAPatuS?6^36E$kKL1W?^5wIlObqko&VPL5DPYXOXzHx9 zZ!yZ)K^L;_Pu2cp$MMpSN+(0k`x!;_UBA8^xmzU1ca_xh>iz zTM@kLuAQqem(~%b%!!>3L>}3MB;S}}EEl*Ue8Ca{Th2W!6&IF^)HJ-#<~YK%mBTLB z^q8pGw}rV*zP2 zFnw`%ezN;M{`3awv8B@e&Ni%&{xFN6buSQ<3mg)be`Grj1=AS-sCEe3Z{KE47 zMY+jICmp{o6X6IomFr-7lDOV{n`Omv1((nbx&^*la2#?cxqS=Wcnw=h()zhv&>(SzM=RV7G4@hwPnc!lwkkbRW2D@Wt$f(46_A zX0qm|q7$5DGn#8<7lk{vHS&G9lKA8A=K?+pRvD&jwq1*bJ??(~6fpC#xRBp@*0kRS z`?iUjNckR-+`XOU-uF}Y{j+zyk;$2D?)KezD_T_mf742l^uA3Vt(C{*C`u;PT-Eu{i$L+oQa%VHO9(6b< zeZ@hEz1`O5>BDgQhEC-I&NcSUnty(q7yO%JV6G|iT7%oM^7`T5X=l_gFz;F8yny3Q zY}0Nx=J#h=_swXZxi_@z&6>?uRvwtm`{SG1k7Lsl9#vk@n`6gReBrmOPkz&C{sV68@fwHU8Q%EL*iv|-(4F(|KgTEQmp|;Y{V=sK z!h$QlmZ|#9^b?zF#oQ7%aZaB8AS-ysHLo0 zqc+f{$(%ze(>UJ0api-GWpWnv*KSl>*SuEwpw)6#eZ_tG%|C7%zxm_ZeXZky=E0qn z$*WY)d`UdV-OHdGJk8_aZM72D7m{bpXIJ3ulV@COc3m^XcX$m+iU3cqZ z&A|niQ!Vs&RA!t%SaUw&i<3FWUIyFHT^zD4+c;%C*RMB^{?d5l(j(~=1;UKM?&o_n z^Y?se3^=#+ucPTxS!od=)%lVc{4C0oLq4i~VX0F4V)S8WTDRPU2~6yQ0k!9@$=e=Bw0H!$n;0xs^*x1}?K1_>1T9w1 ztZ7S}loxh#Q#Dg)ASqJsd{38|KXTReyX@=EsoT^oIAQ!hW5LbSqAPgA4ZUmQ zCrmj~vv*^b(WWV!)0QSr5OVo=M`5>?eO*Gw$(L%kukU(vu;<5*MkR*xa{0*zzE;&% zssu;c&RV%zopr01OLCdH?_b literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/flaming_axe.png b/src/main/resources/assets/wizardry/textures/spells/flaming_axe.png new file mode 100644 index 0000000000000000000000000000000000000000..00ba6b6e986b049516f973a2420c4e460b1da149 GIT binary patch literal 2290 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}oER7!ELCF} z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`A?A)SO#`dZv#~Bzn>OEZ?Ln00zo$i?v z`&9IJ{qx`NYCnIj{t}XxJC*FU<>uui4?K_*_ z{r&gAZ!!bvut7}v@bagx^SRpDjWyZVGo8e9^QCrU(nVFij)n>1G z@$5&>uATH)fBd#^TT}jxOW7aS27H^kMk8{{oW>@rE;ChqufQpb-cL5}n^Va1B)H4% zWcMU$;n^FtI?Ujj7U)>ds4HJ8M zWa$K1Wy?tt$Fk%qwRyt0o?HnOTzXwgbh3d}Nb;Jn#2ph7lec=Tosekod~@=J)eWKt7ewq5l>4jkpqsz9;LQ&n>vt;Y=M5 ziHU8Ti~9PEC1kG6*vjJ4V$-+j`Gt@ZjF!y*e|*;5_vNemjK3L^ei~nwko?v$ec}4; zN1h$5D~tcf{P^?Fs}uO-mG`8}FW&6^XM^d{;+u7oOjLVC(pelgoQUH8u_!`t(hY+s z!K_s8lMWZTgxAX_Kb{+Xb6YMmvt)nnRVM3qFOt8nRPH(dtn%pr?ma~hSQ+@_B8LL3YRiR}QmQ7o7QzPXJRi8F zZ(a~5?<@(?Ie{`wQq2|9J~{J0*1fv%ZNta+`*(BwtL)$Q+sMB9kx5jDU)-!GSMK{6 zh;EsYycV-)R&p*XXqwac3*iRR|M<-pTYB! z3loGNPTeeVJK^2jeXW%4WN>~~ESXd)HBrKK&4n(77Z$g)T=>M4BQnYvEDDxfto`;b_sp3y zn@sFIwP!s2^YHr&?r8^!enwD=k(k| zIeR(nRNOL-T`2HU)ZXHBFwrBl@>}PpC?VfVrwO0)HJ!Ft^d+m}6#?y*~2+THQ}zPa7oukz(vn0a&@r`%#- PU|{fc^>bP0l+XkKw&^<5 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/flaming_weapon.png b/src/main/resources/assets/wizardry/textures/spells/flaming_weapon.png new file mode 100644 index 0000000000000000000000000000000000000000..24b7002b0cf8adc090db31159fa63f9a397fa3c0 GIT binary patch literal 2003 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/font_of_vitality.png b/src/main/resources/assets/wizardry/textures/spells/font_of_vitality.png new file mode 100644 index 0000000000000000000000000000000000000000..b07e442cea492ac8d5a2b92c5b987587e70ed3eb GIT binary patch literal 2387 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 S`o+M&z~JfX=d#Wzp$P!*^nf`4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/force_arrow.png b/src/main/resources/assets/wizardry/textures/spells/force_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..a388c0bdf7671661fc76206ac54149821cb78f9e GIT binary patch literal 2013 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}3>g>`I}aaX zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifa`Ff=Gm0M(jbUJ5&+>F}42d{=bh>v= z$aTr%_4mu)&y~F0BQL<-<2-4X=V>kvPW{z3SD0#BOzxUwF$W3ma9kzOT{f|0m1d@x zYHUd8iA5|;4vieC(}OOq2+3LsKK(bmy>0-19#n-ABM%x=dJH9K7Q=R%}d&{ zXJ=~PE&liX|9`pv%Cf7odj3BaX8OW+r?H*gLE!-gl^g6`+oZ~pbE})(hE9ILMvwHGQU&Z`b z4#Tgrg}L+?rZ=i^Pvc*x*%T>wXZpv_H7%z(J&$czlO%c6sHyva(gu%$#`x9yRx$=x zJkGK4`>()2xts)5|Vz!V%o?O zljOmq)#V-Zl*u6_OMq$5*TffF!))$K9=ytGVBGXfXXnnZHrpP3^pr2J{lHjco%Uw4 zqeNK*tAFiL1u>O_&6?7WSeOo;vA7VLczyeOrU(9fVimtmv=_v)Y%bnnzf-E=T=(;u z2dN^bwN~%jHfi$Q`Ouw?q6|u_)TG&&*6st4<(;( zF=Tfo`1O6`UH#Ikp0AkCn@8#3Ca#|o_Vdn3|M}@@Nm;p5P}4uIJQGLff@DsurjFk9 zp2Rq|Wu1+$UUss4Vl1kkCMq3Pyy~-j%3>WcuCV11y-v-K|CmekKr9_CuLC-3&O5{&(U-e-X4|cNqt8_b-cD9po4f6Tkxhtj@Fy?YsaV^7qK zsb4RxZ1{QYtn4@CAE%rzt~(@AW257-V#?$hJA%|srPYdAFgGW+8o#N2vV6_T=o2-W zPdV$3?oKrCekGSULr6MRHTK$J`_I>ZEIRYhysU?{Tde5cCDtYOiW*@Z?Z+l`E$rOz z>|n>iho4*oR%xAUv^Xe~Sh9gbuR+CIkE?*=_6=Vf?FTDa+c!q5p3rQ+vs)(Trr-3h z8zOE+_(;cIJ6x0bRA}#pWN!EP8>c_0|9vc%^h?K}=CZ-1B&IMnH?5vn`KBN?x8n&b z+O|FV{xZ}4)XHhAbEZrM`Ecp9II+uY2a+#1I_;r{c2<;7y*x|B1 z{{BPbGb}ULNw4~8_EN|>WJ8w%m)g1Q{+|mSB~yG9N(@vCB$S;w-Q#Q-thW_3$eM8{@o2Be#>Qd+X%?=;TQOaHnmtL|wPk7(*Yod? zoo#urMJ4~=kL?-poNdV_2cw^BeU@FFwI*w_|Gg7Gs~sBt^IlF93Tt<2$k)oeY;i&QGLYPuvnW`*R$hcl&0} z$CKRFb_MA0EZeDF;5~6eOU9~d&XgrheUeA`wkG_tx^O*yVRGcOzv*qq{wg+3$j>=2 zr&4mx_Q=-8Lr>PFJz9S5fEI^mmG-Au*^|;{u-fc5JAPH#Rc?;$V?FmN_XMq{r83^Q zAIaA2^gkd=<-@J}g{H#3waji@j4RWEPR*FrU|hCt?t;JP+*fUXthK26Ye-{D`TiZ( c&;MsoUFG>rZNkf?3=9kmp00i_>zopr03Y&`wg3PC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/force_orb.png b/src/main/resources/assets/wizardry/textures/spells/force_orb.png new file mode 100644 index 0000000000000000000000000000000000000000..e87249c489bb4f5d7da96befad3def42b77f6047 GIT binary patch literal 2057 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(|3M3=C%ljyTsc zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL-|c|^I@h3_v7TEoD=KF!m`F(l&f(doA* zNr#KJ?ce%)$>j`{vk~9U{E)frDWe{uA><_J6c`f_AQHNVX=?d`9gkcsVi@}mh?=XZ zEOgSc5LFkDF`D=BOoVdgl`PM-Ve;ReC2hB{)7ZYS^kVy^d#~gF@Ar$oSGPLrhkcyh z0mmO-lW%06)MRKl9LRT|>~`vM)jtoJFSs=;FF3%_Ar!zA%I{e$u)DKEK`FsOQ6e|M z%|UvK#<9f{eN6s|Oze?QJdPfH z!6awgBgAr0B0%H9u|;Nws&*fpZ!f!e%ZG0BW_5}1)9r7!ot|$Oa&3pikzfhK2OP&3 z1)H<38_Z*1%ly%y{ebHjs}1Wqg?S66#;VWTRQDE;xY;tHZsgwtLAF7{PU^ON$l<=>*Et@_cAeE)Nm4?^;1R7J1BtfRD{7I*5C}5 zRL5P1-rx8A`StvKCI*FdhccS4)J}OHaD?;GfvD9dqqe(l5GyF#?R)Rz%b1%=H&-Kf06iN~h6d~C@yN;a7< zDBF7GoBxNJ{>b`63I8R8a(lgJ>gvTGY}n+mglE^YnQD&n3Ljq07nt*TrFnME_n-Nn zzyIyGD1Rr^DF5MMbHC?i9;>?=^bk)r$}V8)yXb&f-=b63|G+B~^7Q@iD`-CXf=n`b=l@mKn^NF!D3NF<|! zCD-C3Vdm}+uQQ!Val2D};@auwC$spZ-|F3cW|h%?daG_!oNzABOi#{kN%N@b6&7|W z=I<`P$}#X^|M9iqnBR06#rOWFKjnsbC=_|MHfHVhy1>D4%XHgr>pjKaYt5{4yUu(F zdTsPNtM_x9xVy|Ut7i(*0?&)}w(CvE>UZ;T3@&Zar>YyZXvpt;mU&3ul`wZ4BaKZ~e$?sp%JP7>qUygpqqC(BqW`&NRh8t%b7uxjSovduLp09tR23ycvVR6pMHqR#i zv$eDQ)1)%bsH);XLHYEH`}eE-d(YhV|Cf+$*TkGqMWaJ0Mv1kHS-lo+W}2K?vdnU3 zTh0HY*EwqDf2{HFW}PFVIIpO%V8$%T=8_`?hR=M~p0zRj@?5cEpKeuS`^P<(PZ+Ph zByjumVhtx7SMBV@#l4Xkk1U>T_&;IewV0cGJoF_4rgHgiKe*_GM4Dpp_*xvA&gBQ}3|lx_Y_HqnySkOTXV*GwFcQ zhCj~JmiYKDtC;;-=KkHseQmSF*BAYM{QbjfM*Hf=?ss=nb zUU$H~+&-bE{=lP@gCz#4fBrDuOkkPUoMM?am4!<)_=2CA(jl9kkLA@@nseKl6&cpY zRdiNARAhfRVevi1yZ}{E-@Tj9cBilZc=0ZO$JR8%9?v#IPm9zVA*CpVvxcpePHn+# zUmojlJZbxQaYD(w2cb+;gv8W~7iGGnzm|FUvEhB(FR?`}e?KUyFBWunZ}+K6z7%*! z$4Bx#-;LjY?4BHxx|YhbhR2CHh;Nd}HuDbUC6`+w>wUHcI;OMw9bG;u-f2Zk*d-5-{cWEcIiJ$5jHjOvF|OiRJFxQ2&31&B+xe zuT36{+%M-`RhA*hI9d9W>$#*!2C^BFTR2}QjkX{HRxJTsO)oFvBl zi0fft2hXvVFYI`h=&R>YOjHRB3rlb!U#gtsarw4XYMQjCtxNR`nop1a)P#_pi3QbjA7r+fZ}O}&4ouVPQ|7OUJI z!)?>0f9p!MZ(Dn6lE&}DGu$0?&h}U4tvR#*k7w`RdsDj8rOz7`2uR(lTg`PK|NpFp z#*YSDWG`*x^*S|^(NJTn%`DySNX<~rLn6D@=-Vu+U2k67#27iRZ+geRb=jOpYJVNR cUi+6nHsWQ*&x!*X3=9kmp00i_>zopr09g#Zc>n+a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/forcefield.png b/src/main/resources/assets/wizardry/textures/spells/forcefield.png new file mode 100644 index 0000000000000000000000000000000000000000..8dc0a6d4625aadfb6843339ac7f13fbd46183f0d GIT binary patch literal 2210 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}3>g>`I}aaX zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifa`FhW%AJ|EU!Q@2L*LWIF(l&f(dj4q zWy3|=_ZR1f?hRjmzuNYwbNTMx<2^17E-HHplolQFlt~d{g=qy;zF1_hg zlZK;!=EO}39SW>19EvF)CLB37ZEneK_T9g~N@wr*E+=+1cX#gk!&AMgLYFT8eD(dG zcRQb-IN2Wj^#2Z}hSqb_&l{L4nlmtnU6*CpJXx?<_>lJUvZgB^6xmsp{%ZDU={R`9 zD$vGn;@Tz+w*$wlJ989R`t`#YR5$UOS$W&kmDfklQU2~zRJpUBnc>00zlQ5;YjnkWCaXnJ-IsU;M3S>^SS*dpzZh%JnzS*H`|6~y-Djhp9}uW` zxA3Cb(X-e3Z=US9KmQ)5+M#xtWFZ%!oI5PR?r$V!h%6EjHa9#e;<>iQFcRo_Pm!6<>>+$3j5plo5t78A^wPq;BvXQ!`QfcHx8YnzeIW7g>ERF+Y6I^~f~_{#SvWjC=34Fsz?< zlegl?HpUA96H;Z5-TKT@y2O*)RB+5q-ce?ETgNqlc0t<4u6!>Z#^ zvs}bwh02kWBA1K57yqw~f4bb>>eTM#RzCtRbMr+A`;nSxFV`&V+w1}_SZ|24YwW%NSU`u=RhUf-yY-V<`rKy3cs26 z-zq8FV*cZNug0C0tc6#Sva06Y-JSMPuBw@5eWS_R$DuF2*+eS-NLYD%nu^gC;qK2) zvyQOnsBJsq+0x6SIE80Z&x3`w`zCMvCg-Eenqu9cwZcWEw=nJ5_s?(2~*s@@S^QY3_3|G0&sj*IU$IUCEx7 z^rUmq498_14k@jd*u9qX7#*$DU{26kHEoC3hJ)!%#muzh~YmDdm4YD4t$ z!V_Mt%P+Xz=RAecZKjcq%&Gt}XQk|p$uklIlX{nGOjWtZ^C}_afChJl!IyT+$cK`> zTy8U!Puog3%P^X7S{>Sb`&GlGo!=N&uP(OuZXwY73!nL1a5 z58wT*F7V*&^}554((?`9%yIpq#vpiM!p41HH0Re$_;CB4m2q)<<+qvg2`qlGFCH?t zD8#&-lCfby*T&h6wWS6-7aaL&HD#Vh%kJ-687h9S4d1!zi=_ATdy6+0iT&ZYxu(rr zOR-DaDkl0zM_qd7($nmbaeI!u+v!~M{fKc#$nNit|EE1!%GBiEp(Mb4jC-R-`}3fh z72Cd9*Vi^LJ%4`Fo*#;Tw|;)oELsrT^WyE&8ypH=1-5N>=hR$De0)n>r>?N0^=P+` z&zofzXFdC|G5JLr+u^VJ?9Uf`_%MC@|1%r*AKS3|%%i2>U#_34F1=>aQ?@pt>@UlV zN{kzBR;^KxD`j^3>$)kYdG%^>kF3jEmVet&@RRB6H<4pUSPWYjx*pY@T(SGy)~Cfh z=3+0_>IXf^ZrRkG(I?n$+Q8=Wjw9gYwxunr*twh}HER7VUrhKqJ#u$Z-->H2NiIBz zmz|rOPYW)6eJOr7)2v1@2^pn*lVX|Oo>b{?;C=97pJ4s&D{D>}aS1W>i#jf4Vbqmb zDjk$&sMTb6vGl(~!j0D<>3c0&)~@D?+xqTmU-iS6zuq!1?0v_!_S=tTE>mBJFn6tg z=PT-QB(&K}z@?>b{q~!WD_xkJR_JIgl*%+?7dHtJDF1Ze(XPi&F3u3Y|1$4eJKK>< za`RX4@!kB?e(80Y+5P(;dOMo3L~Dc>6;zopr09`mA9smFU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/forests_curse.png b/src/main/resources/assets/wizardry/textures/spells/forests_curse.png new file mode 100644 index 0000000000000000000000000000000000000000..c99e41661fbe173a17ed3046873d78d668a2489c GIT binary patch literal 2275 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/freezing_weapon.png b/src/main/resources/assets/wizardry/textures/spells/freezing_weapon.png new file mode 100644 index 0000000000000000000000000000000000000000..60cce3515e6fb32c4788218fe1467304c8db9328 GIT binary patch literal 2062 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 O1B0ilpUXO@geCx8ds^}U literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/glide.png b/src/main/resources/assets/wizardry/textures/spells/glide.png new file mode 100644 index 0000000000000000000000000000000000000000..d4890ccb220f1a9310f9b0110ccc1cfef364e1b1 GIT binary patch literal 2148 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 Va-Z_^GcYhPc)I$ztaD0e0syM;me&9P literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/greater_heal.png b/src/main/resources/assets/wizardry/textures/spells/greater_heal.png new file mode 100644 index 0000000000000000000000000000000000000000..9f51e42ff8ed63fdf8b13fbf7749ff03991192fd GIT binary patch literal 2371 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4%caKYZ?lNlHo zI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_WL{nq8bc;pB8>)VBomm>Eaj?aro%;ll`(+ zMcemVhwR;X|4Q@SyzdFy)pL?<6b=bYXmHVS67VXU=po|TH6`^E{}cWbcB^$ZbxvXJ z7VzfCQDiUZn8|bO#<9HHZ{O9eUv7TA`s=;b5AW&RI%2YA`x7tKsa~t9_x+lC-?DVw zkF%RKPya8>Z18&hJN-tm06zo6sVTvJ$7S);g?uqbXb z^H{3V-014%XcxaAKr48?>5UcUhHL_p(oR3VaO0bWzns>lE%#~}7(V=%bNDA~`)%Du z6}8D;lf1L5?lQP@F4?jp>VZaM5R)qF(V(U@V+RF`4f|b;Le==#O7@xs<`_C`obWVk zt+&MCem=|FBGcpV`-qu77mtb2y>RJKhUaqIgdCIB)e4hEo?Py7a+~Pw-4*GoxO#?! zci;)FW#!@(f4-Qk;}Bfte@RqDrt`?8BGsptIQoR<{66*1|6i`=jbH&ClY!`N! zgbM3NgS0g^O~SvPZ06k3bMcUZ$`r21XWzvte_oZJq#>>uU#6L2DtmvyQdh3S_ii%f z>MwbI^vAC5qjlkpE!r2jj3RwkK6tRbeaYlWF;PK!8B$k8=T-bNNi1$IGIU-X=e$bs z=tLc1_cYHl_T1j@jXs!Zq?tw?EvYg*?sqS$SJij1JC8*eI$OP*;OB9PvvU%YX4#6S z5VfQ4I*p#z%xdB3VAE~eEBE%R=rg|a6R(Nw(OUZVa!04KfuXaJp;M4t%ahXwR5R8D zp0k#zd?&hV>w1ggUmD@-LqGoEZ9Ba7-ovbe3U>}N2XRahP>DVJq+;UDm5?WDJ=oh_SwceSaOwA_tn+gCYw%j})1 zzE(AeD@HZb^wyl}&oaUC`%hO~O#Su5xZp+kfj4{%stS$~JDcP4H^<#xaIZ6?qU~!~ z%k}=qyDu)iaXlkfww?LQ9=$xn?kQZ24jhdenX(xb4UQ%CDu%TO9!xDrmtSx5me{QKs2j@d4Wxr$R~D|E?EX|ghX z{O6){gSgg{znST)b-By@pIO$_$a9D11;s`!*tE$jxpr=ip<~s%?cewRky-uzPp{7# zW&|$G;nLD8JLY77=-O$);Tg4;H%a7PrYbdW>Vu-Cat| zyVJRNnrCo7U%%m6#-@vJf>u|jEc3h2f9b&eMyU&lsY?&npWDy4^zxeeqV8|croX9v zlNmP6JhPHFwejp`Fps z^*5X}gaHs7I_ZiMTEE>DtY5%c4&Le-|#@^-P#$TA6i9u5QH+riqNH z2?C8$Q7qGT{tOHYGt2zS^UkBKEc~JStnBUAB3G_^RGPHtM$pRp$9Bdg<`gw)o3DGs z-lo6qPV&18d3L`FX5Ki)M{$HH*>X%UZ+hy!O@h_zVb)G zPX82^LLG@?(=3`!L@fK>U+^)h_1=L+LS0w4HgL3`U$3_zB=f>6sXhA^-Zo!zefOQn zI}Z+fm*3o-Kc_68JE?M~^K#>qlJHpuoA!KL@;jE5LFz2u(nlOl988Kc=1Z%02|e-l zJe1hnYAq`>b+LS;-L9I+Rk@Qbx<1y<*VuN1ElalF=bY+A?rk-x3O%}~Md$nYO+J;w z{c{0-$ZSD=kzBIG*|S$bFj9hL z?eFH61D~zFv@14eI4piF>=ymm&Z&X5`Dl~`i{Qpijozk-O$QC0h5M^AMnt{O3wEff swVF5YMBV!K%j+G#Y?rUO|9bzu1ce!Ie%#p3z`(%Z>FVdQ&MBb@0B6!z6#xJL literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/group_heal.png b/src/main/resources/assets/wizardry/textures/spells/group_heal.png new file mode 100644 index 0000000000000000000000000000000000000000..3c99c0335bd27eac9ad2618f388027af966fec9f GIT binary patch literal 2446 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)1&}7#RM)yLR~~ z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=kWoy8Ln+>)*@S_CQ`*zTF(l&f(dnN3 zve#?f&&y`jeXc$`Z+6P%C2FTWDOeXJaTp}%&na!FX{?!0)5{QdygR3dfm29*uG}`Rrox`#&$H+POdfXw1+cAG5vU{lv3}Hypgibp7&$D>tH) zT${uE<;rt9mmUa9nE3fx`8P>>t4GhWuX`@yT)eLJwPx7rS#SU5`b;cJu4hkV&8h!* zvG~}0rkt;)`|S%0N}8uJ-4Fj_C6+lSIeS9TgIhvU1v-sOSsK@G@M$#@eE;W%Y~TJJ zhc8^Wh@E|Js@~+y6H2~y1iEiL<$Ub1u@cj^>ebU3w^cWN_7Px_3ckuyZMJyf`7L@I zwm5J~e7WUuaY4%AuYaX=)Y`A4`U>%mQ-h0?dyEqNPxrSaHCmbC|*JJ`G%kqy8Vr*4+;LQ^~>+0OR{My;~|6iAHxcZr)@$-^((+pxF z`2|AxDi3W~{Bldouf+|kbUxH@uhre8k!VryQC2#BdQSZP!=FVR|F6F=t=oE+Z_z(@ z9iGK&v%hSQd%XSsH}8L69=>1kNotQckHxelPq}QQbG(|SJ-hXf?c!6*wGPIwwnoOp zT`08qb0B@@`VB5;Gm%MLvPeUz-@OPhwejXe-O^XkDwY zV+-CErRL7|X|aeq`Qn+~k z|Md3Gwpaf3)qYc0_J=TmR(**A)p@!ve{^j#dlP%xQPTOsyW~*iC6id1^Ai^tcWrX8 z$ekiICDZGo%8sDM2<4e}OYEaA9toatKe6mb_M)RLRi8v7rG#~rV(LE_HRN*U?X8^K z>nOe4;^4L%w%6+~>@5;~{_D1euI2wH(|0(wue+aQS?e<~#AAV`YVUHxqcfg9obus? z@~!auuDhIjHh4@{z5H{=&qYoeM{j$tNa+hTzqTy(9e=NMmD+2}ud2h>?(a9^u<2bB{Ht-ng{-8SnYYmYUmf zxM`ElOuy$P-}fE1>C<>UYggN*JPobSpVVxsDh|5L+hkc{`RhqI&-HDIB~x?$D4Li~ zTiU5_cT_|(;F3n`B(YN;Pi&fChJuQ1g?@#3jNCcOOifAh88PEau|oD_7ejqRh+ zfrkf^*>ZbVMeq6gcz>$N9W{REHRtrEm;Yz%;@ZC3(e7u%E#*;G1Jj(=GvUPp< zf^J7d8Sjs2Vp%ELcl}_I(H#fpn8YmR`nHOwradMpOA{-;vdQoLF5eQ!5>@==pnk+0 zyG0t@tCp$w8HKH$v?%8Umvf-0hpy&x&24v;IBIO}JDRAL<{5`b^e3EkL+FA3? zPjhaS&3r1>f6Q?8qLfW*R=hO}+ueNkRnxW))v;T)1^Tfo9>|Sfd`igYYC&rCe5*)7 zU*&J{dtG;RMd~HBOwgBJvDJHr&yJtB*d9N&%%08M$M^2yg$ZkdwyZtzSu|>=N?}Wo z(Eh87?%sBZ(w&pgvA=BcwR6@ie`Q;~o!IPs=Nem}jF6h)X@lf_Cpv@=hyCtsT+T3A zqD^`FF>PO}xp|J-`Hec$-(CCu(S3dL+P|z; zHyC&Gr@Bb#&YUa1!OO|-nD>;+hu&}dc#E%Y>V_E6^UD^jN!+F}!MFK#k%M?8Ia1FW>GdM!bKxo$ZNhpX9wmy=q%NTb};IxFN}C zo?&lRTH?`+>CcxdXiGgiE%i3)&VKu+UveCS4k&3wrnXhHf8V*Oym`TG^^?+qu z(8RDfN@TUu|A5MMn)HY$aotIaOkwh;f$E3CtsBLi>ZmZ zo6r7wJO5GEir)S}*>n5e^C$ z`+hXEv%kN1?=R!#4NBSxR=OImp9^2QtZ6Yf{LhnVPx#w8GovOvXLXHxWWl$LQQ(TH z2?twt?4%`69{zP+<)-A~w`InsA0LXRC3fW9mXYBgG={P>!;`;IMkU%uv3oBUfd znYqVHqQ89({!r@nXZHJ>41Yc^7v*g`9oex~Wt(b8(n;y{>py8J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JTg26+#7ktlNlJ;4Ln^OLn00zoqoDs zCS3Gb{quXPUcGxc@8!IY$uhSs3g;M9dQSAvnItgN!b$0-%c&;Yu1yWRNz5K=0{=0v zaI3H+icWA46k_?L^l0Jes&FeedrSuiI0xD)Eo}dX|LJ$D5xQEK#;*VOUq<&A@kFUFIdn`aStGG!r@`Iu!Zl zgvfK8_#%0*bM-vgw2yt9N_}U~+QrvysN+8O*!#0i{M}oM3nWYF`pA$ zleOc>ht7#h3YX5Dn9_BAic0tUnk0+$S7i&j{1;rF$!r)`m%nB1zi1VUOB1z<1jLm; z$sKX!oYQ{p&zrKaIqeS%ID{65@GfAg@L}cUVmlXlvtaw_vS_xtQpZL2^z@#u^4K#m z#bEyh6;JO=Ri1lSUWq>TPuZ7GCihZ?^Ip{}v)rPBCxv(#eejHVB=Y=#HN#`^^kcg@ zeM&_;A9#M<=$}}Z*cKIhGRp1q_VY%Y{WJ8OK2Nx`=d#6)D@#h-FJ!n2MIQDDI=Woy zsrP}(#dl|}HcHs7Dv)?PL9cVAzZO$u@QGP&R@~=hYp0a=?f3gVug8Yv&|aq1Zkr|= z+Qb{&H0aVT*csSkI?F^tt1Z&xqwf!M!5K}}1$>i23RX@!>#&#i&lkyg*1t5CTk_hs zg@>Q}bYSQHfe6Ga#{GfW1 zfA1EytzuWiTb@Pd7k+zZe^~R!k3aoC+-m35_TM?_uUGF<2m7G(F5FY;ynMJaZx$b)BkCN4=};nIJiyjVh7e1FBP z=gZ?NEvuIPxRt$QV#3vToYg`d6RqDD*iA_3Tf*lVTTzkOICEq2+xXWengF?Nz3yD8aha;+G1b=Q!t1XL zAMPppO>mho>-gRIn~u#`-7C~onEhC64#%=KW}B{HiOhtLk8b}^w&Th(JW#iPzwDbl zVWz+T#1uBxbjV+7@INhhJ)h@f@NpH6$A=81xc>6qcq6q~(ML_dt9|B%30EpUF0AI5 zo>Xrjyy{$B=^0xU2NuB>Uw^5Xt}vZ#AoRxH>-TBNe+8#LL@lrnxzwptE5XO)mtZ6G zNwCMuePYEs`)d!ke%AJQ#IabY$$72Tam~(HHIZ;$1*WVoW^5TsDaD%0`|qE$&(GPg z?ZwHXfpO;~dt1*Ok5y%nnBKQg<;t{Kb8beZZxPba*R(3i;M{xmpx%dQ6@#Q(zN|hM z7*g|ks!zSnUvG5VZ^y1LCL(V4R&AV@8slwzO(#`($r;($1z#iDpCuhTXtVf-d%~Wa zDLWS|4UrD~vwh=oc9{oCoW(5!;@3@ z@XrpPa_#&71KZ=8Ccod~-S|9az4zJ@o1%=yt7qqAKQ{dTFW|*|ZHbt$W3dY*4*lv? zlv0?oKvAm5pDC?rF;jSesFS9Mb8><6#X~3d{go1b-dc6KaE<-p&ZU-J(+X=#eR3mz zl%$?{@L1sB_JrEp4lx%_AA??_*KsUMR)rhi)s${cTC_rQm4T%8%V~>e1cq%tcIP7J zoZnxiesZYoJ&>Xx;=E8MbfUOG(*mswfddO4)`v89bTc#Sr71`_9?;<{7B=3}V$igS zZF1g&v;XfnoYmmIurXlTg4PSM@(UE*?9MKkxq8>aZo3_G4+tOkI=5y?LSfNG16c)D zukM?H&fFSB8bOD{tEWa@*>PPu>`D2TzVDf(M~x4EpEvjJ;g$o>+~$|1o5^XcI_cW^ zpegrz$#WLn&gU$JU#kDU^-a6|)^Sy2Le`$yd^**pi?#1g5}%jzVe|g4<$Usd&z?WO zAkg?|CZpM}zjF_t^sPOZ6XjdzxwLYMc~kxOnQEuQw_9wxacgelRo=&~>e38<{_K?z z*>zVgh*#&{dmiDBb3@Ks_ugA^>P$<)&pN7cNMz~X08tn2En7r`7)4z>9(`JIdx;_Ewqzmo!bk3JDstavf3w|OoNs^TR;9)K zms8Wqznyzy`@j0%^ZIv|j}Dw$@a(^ZPs7P8&-)kZD(NvY%J7AI#MUb4#U%rf2CoVt;x-o@TF2-i^-{a`rP=$J=EA<@-w4X@6B(ahHEQMzCP}=rQzH;J(=A{W;S)NW&LQpe1+C+9@+QH zO{AY^{AaLT|G#zPWc5I&3pa0ip1++x(OYH5+lBgpd{+aKZ-1%zVfeSXS!9z~_O-Q( z1!gb(x%|D(j{jT?xq^&sOZH~7#@9b<*U8RSEl(7=d7)XK{6lS7<=d0; zleZQ<;1}p|iQJsXoGdJSW1aW1l*?;X>f94TTQ6KyWGW536~5-l+Vr|(+4}n`U3GLA zD*o>1-&Xqi$G3ye4PHC(@bFBstdrOrvLyR$Ro3)v#h16;wlp?ve;3ugF5YRy!p>0X zJe3Q3L;{7~q}7(DOj~^1-gP%yUaj!ewWoJf|4&|XYX>LmiZw@1yRQpkWMKOC?mt^q zs`|>AmgoBW7A;+}c5(CXcRQMI^*#0RKQ19}+rE}@xkG8ParwY_`J*#us##ke>r9@+E?>u@9C7{)w>|s(`i<;7myd5-Z|7hc;=DCj?frU3 z&XYSAI-cvDcl=b!&)*j!f2lp+AZ)y4UChbv^C~CZ`ek({L6l{cKqJG-7eRS9_s!Lf zzLu<({Njj?_w3mVayGx(m9`}DLe=GEM;T(4ZV1ZUHTB7x&dWV>EPFXv1WmVIF*Q@{ zu6&auxIAP@si$%EyZzFOH}^W_PPnzq?U1i-hr@(EUh_@wJKZ(enI(MBa@030D=>X4 z9Uk~p_=M?f&m&3Qj0&ntZ|J!9%P#(Y_xr^%#+tfCv8yv)yip1YcP|ZPxURRc^z_*` z`?A%SZfZWi?W6nan;Vnav)8>(`+jz{=C&)7d1qX?$}({xTi&kcevd8+?7XG$^a#(< zl2=iN3Kjo8zBib?sbft(mNABTk*;M;@}pJ-@z9ttE8{$X3|t|)fX9h zmiM}A#O_6Nd#kq@rKk!VRchR25MB0m(cf#cEniPtAQY;jeK|I))dH#Nz~E&a97n~GWc8Xf=rjpLtTXK?1I2#2O4 z*OJ5qOAl_#jlQ|}xmnv96|33GK~Iy7B3Lh_tb5^fOfl)l#2|s|LV>Z~8{Y(MD*ECZ zv*7!QWip+}t_rSe}hhN#twT0oZ31jV2_7(w-Ooj)ae+n#flrvZ)n6;!ONHBEM z!7qxl} zu)C`{|NDgVqLH_5onh{`I})OHcGB7HAE&avJ09BQ;mkbu?rJe+0SB{WMFvflr6IF| zY>ukWpZmz(-A;AtHi32B1*dgZuUy2~UYaQXc3DbguYBU|jN^*)wq@k@Y)C)z;l1SjV;QSeM?@-hBtNk2DAK~4)RQCU>@YaFFZZs+I^PTD0#lz~ z44ZW2h{Vj3oGnEsx%KO^c$v8@FMYIl8+-c4zsJ8h*w-l@u6&%q8`W4ebM{>3Ps>5rc&4cyD!50vhF&0U^Y zwk_#;SgbNX$NP4cCD%CC3Y==)#9YQ1tF?&Ra$Cukg5%5byi(bfr>iD;omj##lkLgo zfD^$T=L2VXe>(Yqv+Dla#6NF1mQA_y@56M>_N)xEo@|zd-^%tU-1*wmy{Wmti(_}k z!zlvmHY=QuQdF3)YF*lR=#1+h4Gqy5vhwcp=RcUbyzY=ky}gF`^^KnDljAJEpYLD4 zlqq(hgQAuK&)Nxjl7SzaPCb{fFzrdLEPZ&gF}O$8wrh5mvNx;KLxU+?7CU9w{y zI|W0_R*{6~I*&GA=Gfj-7JJN1&uQnIiz`H&H0Rx}Z`e6gLWozpDV%vi##-&HfQ+X~ zE$z-6jR)A)&XAOL?(g~hJO1x1C%gUtDHD#h4%sb5Czk{**fZy$WVv9JvAOl*oqsl& zxyam*yz;r%^Sz5euLJjcr&%0_Klte%X2?|FX>R+)_Gsml?`tL<3Fyi>#&rE_Mo8Af z>UlxucRYGoz4vba@lDgOGB-^16JEF4`GKnHg^Z_q4q~F6YR}Uqa1@;G@cOjKY3_GF z)d^dfo}N7~J-y@T+M6}UixR3E#Q#tIb}r}PRgTh$8LfPbr=st8Ew!on+}(LH=O_WL{nqUuJQR@v-gVBoOwba4!cIDB-vXTI!l z(boOZS1(KdwCJ9!8aY|idgEFPIY#z^2YVZJ_MTAN{lopqaf{t79!*DPD>yJn_a!M$ zOYNPY(YeUQ>x%OID|grLjxP^Sy|^UB^UF2O1r758zF*n-{LVhr{k8kke%kY~CuDzk zoE-7;gfIic?Y~S7Pcz%6_Ib_zKjSu}OQ)CD3M zf>ONgA9t{@>|f?7=((Z_e|k1XXQ5f87g-|cU>j!$pea@l`XM;)~VRylZ1 zx}38^V`Bv$%esKiEcaV?sb8sCc(-WfPp7-$eL5^Z);+L%kWsLuVe5{l8Si`+vivJq zSmEVv~Ix#u77{#R?cG-bX?tKwdUx>rsp9g zS%n$fvu=1gJoqcZGE-(`GJ*}i!1ulWS&l)yy3*=Qih70jYj56j&0a>?UZvS*d{uh@Q; zJG*;I=KM6@%NZ4C&TcbsZh!I6%vHqj>V=BQUPtV0%jc{=cRwj8q)Er?Le!6aJXeGn z*nb^N%D34Iyq-56;4frkTEwz9U*6q$qHhPA?X>CQD|ZGQtM!`~lT?_`QbiChrMd~=mtKciv-aGORUg`{ga7|Pyn6>|1yd(3ekk>o; zQg$A^8nm`rf?=(QSExqp+JY?s>#cqKe^>OWy?J+Ov!ed~pNzM%q~1zKY1^yMuyfl~ z-u<$5%7VX2{O|wFw%FJE#ByG6r^Q*`zOX6FHkr3~e&`evxfZtd?i8_Poqg+P&dt5F zB6^d?5!K|Ecke$aITtXEEj0e(*dWu>auylXJiv)zI|-!nK@JPl8Ndhsk*yM z|7RSyw^#Pjzm|7#{f;3*YSSLxnDA`cyEqRc!-7pew{Rc2$kFYp*{g8%KJUSIuMbCT zIJT+cRqdUGwvYF6rwBc=P&=}K?hckM&z~2*w%gj~zxHL)#tsJ=SAUWJYk1dk z1WMTQWe8^R_8)!9cbQvu&H~Q5?)KO7jklICo#Hr@J>!R6GZ21`f?cKk29o|gcy$APp*B{SZAE2^f^Iq3!(R&U!K4)FJQQ|W*gNuk*_eQQ} z0awGxAv09?*6%Ch@;`j+mur^SkEibP8!P`x``8^??{6qo7HRWU@$Omu488s5wx0jr z`O$jKT&v#QmmeQH+y3R3;?kvFPrqkec;2^bKY#Fz&MS47H^vK2U37Wn=Bko;yx2)UW+9{Lh9chQ!Zy_TJH zz7FjF+B<-;e9t zUmSS)XnVM4QGZ^&({^#=9`Ck7&sm4B9AYZWl4w(XzW-0()nxY*+!B37r-UwD5omjw zsJCK;`L#s?T*@mpy=o8_n{D%oPcmI>z2Jujj`M|_B_!3%lqIFTn5$n~Tg9yq$so}RFlb?uJg<>&v@^nU%SR~V6` zqUg(07#YXr#Gm_M4xj`zzP2vQGKvaVn&I+bLEq4H2&Ib>GYDp5G}x zdVgQ!hd=gwyahM@{*k=4`cW`L!{R>1gtf~e*K_@QyH4qX+#Uzb&M5+Hj1ML{DJ*s2 zSP>%fcb_vy0iO-ibD3jSYd&)*zAUS*sSMt`;oRBRrr)Fv`!h29tI&R+F0Yv<-*`aK zoolJeIj<>GLRN`hIw`PLBv2Yu7aA z?-SdzU`NfjO<|Y+d|Bt_If033?TKOyQD&yK9$Zqcemf-$!!Mk1RXp9znsv1$$Z$an zPh@PThMHiZN{5rLOcqO%1=ou6*8_q+tlxgN_-8!F!K%=L-yB;eWvE{8Qkarr^C>6B zYetXF*Ql9UxpJO2+>UV_!xlWUwc9p_myIO%%!TIV}8 z%)dMPZJf5_g7itpC(dH@Jo+tdZjokUZSKUgrYFx{Kh?tOJBvGJ+QX@juDum23|Mkk z@}kAtNoms@B99$%ND~MWVC$Oy=i2A*r{^;YIN99Y>7wZ=qs3L|AjIyHI5RwM-;veV zPp#2uxwG?gNBz%_a?#hPOOzD*_21T6bLGW0>zdE{c^k?vJiPmzTSjK&O58Z6!ZT)Pk)pUXBYy3q=Atm{&bzsxL@xw%;3>Vr27lZu~vg&?B>CR83kf zlr9CVW0_;JY|mf$?U`nNKhABBfAnjs=(cU$XU@8+v@$GJjp91;zV(4+!zAOIhaH47 zJY}*bMQkojotgjtsnPbjy@&s{`z}&&xyg5Zo45v>V)p6MZR@TGtbF{bsOONOgx9~n z_U}KG*VoQGdW-34P>Vp9gJ#JB4(HN)%(G`J7RngCs-83T$i!uK@ej|=?%wnF8?)Qt zIg6%cBu2*Wb*fF|G`Cu|ZHtePh26g;C#UvG{hhebTw=qHeMhX{+dVovJN)O*+seD{ z_Sk&RSbCz>nt#Lo{0^szuUENlM}Mvm4(jn*qbFKfQST#BwaW9*r=XeMuS>Z+UBYfH z+f^VrG3VpdTeY{A^Pbu|Wmn{q%Wp5fUK+Fe)rzUB-Wa-QIWJ&YxkrI_sR##Sb-((T z=;b>4p+9Huzm+y6RU=e+$@y#EuT{K+-3^Pc`ig0F|`VK@rQ|Z%e;(`r7hj!!H6 z$!&0V@unS~3(Kai_@)&UUa-vFV*BAG`~Byo+EkQu`36tA@L=z=-r1jPek?egVByBe z_>W0A>a~N#k}nFf9vn=rLfl-euD>g$Pi}u-m~WoG?w?TLTQ;pY#}`amagO5K4_dF$ z__TEWowF*Ek$XReloZrZ& zU+!C^fB*TuJ6G;~nT73Kqq8zm|K-(W_+zP8f9Kk*uYGA1_(Z~Yna?rV zZ*q3eo_vfwv*mE)Sg`D1V7HM%}_TzbUT+g~0L>tXP;Wk=1- z_I|$$3zt`3Q7E-+?o3G4TypW#p5Lq0Z7M2`or?0&6_$~YFOaC@KUX=Y`HqE}@adP4 z?eTl>KYd+a*8Izfv;E0~1-{>Nrk{JMc)Zuly}iBXvf$ym$?DeZPl7JIOSz)eWncL? z^NVd}cB-D1oxF14)t4Xk%FBJ~wXbJYExNW& z@8T=zK51vG<|%ud)vWo;C7)i9IuKcW=2Foi^L_t}{{K0wTvuM-Uzp`#>^&=T&F3$_ z#kZtf`#F>8T5?bNEa?)Kx9?^=zO48EgTJ-T+W1GuzMgLJG6?r9a59idzq7Zv|4u|! z=+Wr>+KIhuU;lZ`&-e4ecI%Sg!pl}B&XVdWwRoQH`hK$XRF2Ylf8!{`ZxBy zuUT6V$g$w|+u*g+0y&n=bbrFPmZeT>gPOCZ>jG7|{%+H??`FKbVI8;{ z5_=9u_18+hzp0uk7We$<(b$iH$3LvSuDtL6Ydf!|s#^=LWr@yVd9Qk^GxDI+SI$2Vnv odR}~%I`8l$-M;4D<9f#HlJ!E*E_JpuFfcH9y85}Sb4q9e0QAyj(*OVf literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/healing_aura.png b/src/main/resources/assets/wizardry/textures/spells/healing_aura.png new file mode 100644 index 0000000000000000000000000000000000000000..7118ebab0eaa8556c301595eb86667954aa9e6d8 GIT binary patch literal 2344 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE({C|XBhtbe6ha9 zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||U=$Lyl=|{o=q>{T$5u}l$B>A_N2f=w zhz*xKUY~vAvgCKm=ku&pcV_0zT9TQ(K{2T{Xh~4KNR39vQVkAKk?cU0h5APs0}Bo` zE#R+R5%l$>m#kdK2S@oF=}BA6JdI6vo;*AE{LbfdYM|1nGlKz=+2QP>T3A@!R`s4SuU5h zzW0pbUE1WN&3NsRhNG&EGV7mzB~`Qk?PhqxrT#@r^McocC9c|z>t`FMK@sXFa@cY*YQCmoz_8z1g`zt?eAM2zl-SYO>QKTieoPb@y> zb6sl+w;j89_6w0`uR_JXi%4vDyW(YM9Beu7_oKjP%WL~&*Bie{6)BR+W=TBhsM#1) z&afi6dTxHX`-Ii(SC-4LG^uQ3S$Cw^G&r=sXyJ)Zy>>wrEv{z|-4QYV%GBsHBYH>w zqUn#a9ap}2Tq!qwy7im-4|Z0!l{fJiCC^-0Rr5XD{paod(Q%c-E6nlZ~lgT4e=U_n>pVB@aM;eBx%v3+ zaJG!=2hU!b%OJD%q_}O}kFUyqUM%&V(q%a(=ft;PT$yS&ia%%^b>h4nztE_dW3B9- zQ;c^OGzH&sw#rdzU0V29_SW?Ksf%wO=7_ixy(Emk;`g3Mzqabldu-74{$PUu(`3oI z50_N`97ruQOGq?J%e8e{l(|-4@vzj@n}0*fWR=DBl>SIgDLT1{#X4r;-cMFPFNu7& zuaT+!sg!;$=J*Z0;?Jz>SS(}Gd&*3L?lv#ifue3kQ=`&;LOGi5eH`pKAogGfBKJo4jheB-mpA)WtX_r z%TRv8XW2y>i>HTJ{GgXmeaTH11-2U;HONXhe%mEFyNCUD#Y3I6J1JFG?)u+uWGsuwtoS(f zv&3YDmYbXj7ENEzPFb<}V2SR63Hp=xl4PtOZJs~t`Kzo$UuvdCt#!EbdO}Iq2{!Q) zp?nvzbrkn%1@U>h>spyxMVR}q+&8^jeY(Z(b6Rub&O8fiw=nj|d^fd4C|S3!?S1{@ z#JGx&Dv_%MSoVDTK1Ja}M{q>+yNBJ1#=D;fY;3+5du*f9tsNfwr6*@j_ZByooY`}% z({!6u@;BKPo3GwTsWeSAFjBc`tM$;$U#V5$tj>R%jb4*dQdT;4OsTLrwuG}e(QEb1 zW&6_QqqWUDqGFGo6j)!>!M)tiz(h~{{Q3zmr}*3L>Mnl1JtDs+A}Xu+=ic13a`q{! zXPIoau~__mUCW;LT`#`z?$Z`DUw_@;O3gdt_8*_^^EPa~s&Zetg5=&-HJ=;-!evaZ*ySH`6mY%-d6IAipKDTXS z>i>5Q`t|=f_O13XG6)kWeP77c!+P{cL=^YR#-g~3@=|Hbisx8gPf7HjcUgV<5kK@tBuok&-U|qeOAI+;=!|by>mAx zZe3t+u%q$t)ukPUNuFy`t&LPxF0ejxBj?+XtE>S!ED+R#}~vNy>)AbMQco8;n!0Pnkx7ITxyr#Gv0Pv zIm}FG7qj!mS;;dZ>%M(ry|&G&q)PJf5x<7z+nf9!rF_?NIsWYUo~`ea*D7olyD#{q zy-jDUMU=o-9#5uB{l~5I_xs97pK>$mQnzJRN?v_);ce3;$0nstND;Qo|LKsd&QtUC zV}d$ELz%S_kGFYqB^21YE}w4TrL#A$f9h4=TY+wqjBc)+ zt8(Yb$=@%;t)n+b%bvd6U-9SJR}R&g5$c*8hcC^2GLdPv<7QDomRWWBs=HUd{dH}^ zzY9$>80MFFG9|yu$QQKvz2p4XUO8^#*10@uw&?oXKVtl_Ti8(SMxLwr+FcG_jRFg{ z9{8xn$u?Pf-CZxv)w9x!ch7yfy-7N`@|&}a|NRkm+kf0e Y4I0mQ%!KbVFfcH9y85}Sb4q9e0EZh;j{pDw literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/homing_spark.png b/src/main/resources/assets/wizardry/textures/spells/homing_spark.png new file mode 100644 index 0000000000000000000000000000000000000000..c3cf0ded7dbc2e71844058ae33c9b8840e641368 GIT binary patch literal 1727 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)1$5*!sZRoq>UY zv%n*=n1O*?7=#%aX3ddcU|?V`@$_|Nzt1BeXd!Gep=%if1DlVhi(^Q{;iJ=I^JT&% zkJmpxQ&E;4pZ4wU>+3hx37h*h83t$ub~`GBG(K1q&!BRGcRs^M(H#!2YBhsYyN-x1 zSQMwAmBGZc)OAIsmyDEk*`tc<+0}a=*M5C7@35=Y>)MaA;#!q^&&`~<`1$|(f6r~s z7x(ShnU?*p|18T5%c_4e%Y+_HVK{KPNV?(Vl9M4$A68p0nBtUux7N*6ktN8hVV~WP zca?JY|2gg8e|{`z(%Yo3Qy30-e@@=>x6vW{E^D|KV~>jB5o7-;K^%$!UW!ZKoVyzJ z*n;nU-4n&7PukbF{1TadFu^GE(`)`z`3(Key!mGqPTsjMzuAlReIqZ!_0o$`pP#)A z3;$=w6wGJ5>9*)dTAT!%Z_34!GUr}t9op8OGiPbSbcY9j7X&{3 zwYp>HX^XzgU#AsKEYtG;wDtYu-Bn+&RA}*^{HVB~!NcL%^m)Uqn3)Z_F2zW=e|`;4+Ow&R5p^kbZJ*DvNTTWND^VesmOX?hpuMZLLI8oS+E z&U3+Z5A(2cJ6DnI7u0pHJYkx9RCG(?MXfiN?^Jf}-^7+He@rK2E0egM{pVZOM`q1! zKd0|U2?I0t#_Y9%D{b7aFupb3Y2%)#-2Yx>V@i8>w*Kdm?LKP*56?RJ=>1#e zvl_eNT7RZ$*tUiAJ({1d{AlIo#&baq92dXF^_*X@+WpFGUAa9!#d)}^vfuGRMV|EsIhlA98n-8)6->kHwOGO4RM z3Q2lBH(i1vm+7Akd^hL8GrbFEmYht}Dck;SgI?T{y>;uJReJPlC-;gEoEM+6P70HAm)*Ftz~jYS`y`#S!O{QuZ%y6s z@#B9L1@@)WgBFEdQ?Tzo;iDjJ%5(Q%kK2rSvl}OzU0Yo}Wln0{hFzz^*ZTzQDx0}} zN8p->uBx4`x2FeGG3|V5Z2r}Q>8{hK3Rx#Xsawl7Zf0&{Obhqr}P*rp_cE@lNA|*BeD2eEZEhE84f`l3tW%(fwa)Z}&1?En3MPw=$&7 zW5(V$Hs=qQ#%lfF;cQ*cxOr25m)Zq&-zzg(SA|*b_@8eSzsKk2J1bHCKM{SsitRESTU{gPQ`rNeJ&&2H8W68GdL9K zH%oR^bicv(u84&!X=cYhJ`?`4m+AI#Q>){m2F?k63ymhvXgxborEQUeSErp$knM#T ztFueWwiigbPnhpK-CO2Y*WtNBNjfennZci(TfRO1vDIo(jmPquh7YwCIu1IGKc5`* z_}MPEGE|Zx%^H9dM4VN<4Ocnj|ty%Fy@nVG)%+2hR-kmJZ68w99e}FI(^M&BxLmjCvQEmF=0=DRoUn|<-D>1^|R@7F&( zSh-JpOVCOl`J}3A^0(U|%ic3DoV#O2v;4gB-}?NvYK8Wjr?fFJFfe$!`njxgN@xNANxwY+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/ice_age.png b/src/main/resources/assets/wizardry/textures/spells/ice_age.png new file mode 100644 index 0000000000000000000000000000000000000000..18c231af0975f94f70b5c3d0dc9c3fea3b6672a9 GIT binary patch literal 2496 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 Y5IbGqx>r~)0|Nttr>mdKI;Vst08TldUjP6A literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/ice_charge.png b/src/main/resources/assets/wizardry/textures/spells/ice_charge.png new file mode 100644 index 0000000000000000000000000000000000000000..128342d4848b3c18701823c802f508c2f2c5e52c GIT binary patch literal 2281 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 AUH||9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/ice_lance.png b/src/main/resources/assets/wizardry/textures/spells/ice_lance.png new file mode 100644 index 0000000000000000000000000000000000000000..1674a8fd81322493a055b74e7d39de5baa53ab68 GIT binary patch literal 1899 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}&M-I`I~Zp( zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KnM6goh1jy=gBTdtet5b#hD01bI{oze zlu*%Q_1W)h>|Rw zNrzm7dxd3BD1T&aT6%CR?@84C8rGjF(BEc24f{x>&EsEC+)gTmQf9XmB8 zkIy;J!iB@71iKs$s=q%K_U2A~b-%H=do=^YJKI?wKJVw^V&Od-DrjiHt|ZiJ-j?!n zUu3e2)PakQXV0naw>3P%Ve`>p+o2sZ@8^7#IlnJQ%+0WkLE+=7YfXh8w{SiR@|mQh zchh<;^J|VI2NuI=3mObdcFBrVJUe=`>EBcVnU`iOr1PK6V|VCr?Ol5LwVT=loAr*$v?vJeE#kbJz0NVFOHDFGa?;b1 zb=E%5cO9OwruS@-&$Q%AJTXm~5eIJ^{Vw1b`tzgr)2lpZ7OphwUVE^^aqZ&E)+~CC zYkK9k@fGqp3NYUdoBeP>!-K&1r|DAWR>^O_BO0?zj&PT3&r{9aF1f$ds4K+OO6=)g zeg|a%(dNt^?@39QWUgl=ellBjb(z?~ZPyAb`+S3ra7ax#$DXI~=e6&vhYas+Z~ju7 z|Kro-FQ2AN-e1vndAYx_q^Ne^J7$4MgKK)1JSU0Fe(qCqK+%Hdq+5GQF7x(neZEEl zJ6_KFz4PV0-VIo;_K!Qs{K4CF{Of-SzWeviTw}TMs)rvQ1lgGDsV$ox z(d{Xu;<+KS?R4>^GU@FX72ke2Vby+OSG$2HlVU)a=z81l!F@9O`Znx7n!fLYX5Nl{ zXSw(Pk)8kl9)E`Hy`*pF_KUOnd|_bgFWMWSb`#A}1hHechMYsa2uFUgipnQeRN zo#LIe>07^=-ZGba`faUVx$T!k51oGt`wgU~{`q$_cu#Fv`|13>2jA^9{&7?18o%JQ z%L$AQJ~{@+td?AC+{ib5$qpU$yKgS+e(D_a|6>2+U$GJj>5F+FR0ivclv4+{+8PHck`x<0To-dZEQZaoP14{$omR2A*A>GX6Dh!rtxq z=I7VT<`dJ!S6=b`RF4kJs)M3&miy1<^4p(VzyF)+sekp3hvmMm-WJX%(%f`5jz3#h zsmXAofTE!d|NU}v|GIC1YVFr5_DLBYGM3B<_EpPS@%YV^kGD>z&y2aZtnOp~3jU2I zr{lisbUln?-aU&^qs_VMdYbmz(tTf^C7XYIS9NUV$qApI@<{q-`Y$t(D=vHR^K<9t zAB6`~elu-8Egl%}{{DIUtI%WNj3x?fyP0#QUG_9~vCV!f)?fd$dyQ>@`16{xDuQNu zqA!k~o-*0+>6&Nu*7LF~7TmeJP^zC}vu0Fy#@mZlOoE{%CTnC^4oEl$99^)WF){GN ziN*aNuIAUu-p@2v6kt=%n>}sMZFvKkKFL{g_Rp8!Q22&#Rrvh{a_@xJ^>99&65w|+ zKvB^lfUTKv)0q=jOB3>EIWh~`L?6#fn-Z;dnRA&$;V1v~kJcpqzNGr^<2SR*HIpxX zV|}tUe8u{n504G&Vg!~6Z_!z}>SDlgHPJtD9{jIZmz@k06$qX8>)iI8ALs41tbD|B zkp16>H|s5azIwf7SL`0oq~E1_%Szvh$F;v?v7alDX6zIxw5n^-eRq>1KQkg{{B~W@ zkjd8l-u|zzM^Ke}pMg|QK_&O>?K>XXnw{so%(GF=YH`=K&?S3y7Js}cvNm1huk4lZ z72iEL)|53dyGSTMP?YHT&Z8gW5aX56=Cg-Aeqk9?l2pEvNX&{0M%$9tri)lxXT%=+ z&$53*;RcS`T7n^u_qIvwUgc!kcJ#M^?b=gq|CUNFT6eJ8xf=Sf+-p6}i&UW}nN{#9HJ!brDyF>ZwJWv?3I5D6k|o zPH;$K?BM0r;NTSC7F)y6=yKI$Vt{bx7SGvRuIQCbPB^~x`CiG}k1OBbJN;U)3=lUd2yu83R+lsq44u5{mi=>rei4rQP0 z^*5Qlz$BxWiz!54(IE~_rx1~gRwV+WZYvaAN&=b`)0qTILXtn7xWc#ku;Pv2yIzW? zq)RO&L|Hm6b%bTC^*+kJ*Y2F;9K!_Na}qAx5#0=HAAeU=TC-Ls{E)z#?1&@Mp;Akk zFWlO^K*Z|P6z#Qviv$|4P3)-H>np&vWcKVETh2e(E5E?(-h$uXO6BL>>5T2n@NoQj z%%;!E!Cg@6%a-rGj@R8e7Ii4_)Xr&aKK}l2Ol|L)+Xt6ues!CCIsPx(+KX1<^`DEM z{oj1znOpgLpNPOzJsI^!k0sl3zEx$gH)br_Xt-!%;G&C$O$IE2@9O^)*A#ry(f|LY zT_^sp__q7cXR4pSWP1D0kD2-gpWm*(>~DN2kEwOTccy@fzMvH`B~~0416?B43-|Q} zS{t16SbXxu!R8kVM5NY{hMWBTx(It1!!7I(` z6+gP;(`r5$@Ynq@3Ffcu2=1TvXv2~@HD6fjcYd;pul)5nW?xlnw6}N8vD|yVzn9K2 zOwGM9ol(%Svx2QCF>~$b#TqXRoLFbM_sKuqoo;`!%QU9*x_-p)4r+dnx!tguyBEBe>3eYv0A0cpWKvg;?O z)aGfPesMN+-TkmL`+t;IeU$qA|A)4j@q;&g*OiXET@rMlO`<{N<%L-}PnANZUP#cD zul&UMZ`t;nMh5QT8eB=B- zJ?-;mJna?NH@KJ;SbzU_roOI%__@h>Whbj_ee$_ye>*5)AohV_&ey65e@z0eaR=07iQMj zQ|46`lM_$&T6PClEiZV;XpvqR8P~`C_}Y{6I~o`7_2=jcTeGIEqAHMY`p;vRUmtqV z^(jhbbIjKVGgnKA?68J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JTkm;CcNt+T^ShIpLn`BhD01bIz75a zB~|oz{qx_e)?c>0YMhue5}ajo8<=V2mcaH#vp3V~#n$CC{WrFiyaBrW3K z_d@O0gI`Z{e;w#{^YQ6XY2cb2J3&L?`^>q&ef+~i<6nQ0m0wk!HchhUUH9CO@a4OA zoqPXh|7ZJByUHKuCVi@}sbugz`+wd;`&iBY&JSkJdc(w^ldsO;bKN#A>(F`qh&ftX zlVmw0nB(-iQ+On}Z|X}tKVZr8W)AC7hK2G4=Q-bZS!}-_k)F7AD>p;ItBk(*m<=m9 z_*{Dr@-nS9T=Cp-UxNr&g6#%5C8o@#ZY7n@!px>ZzEZxBz|d7&1?T-pZ&+YcVpZPy z$eQ7DX@7j&mjFigguOnEjs;w-Ch;y>p(#t+rko1UO4IsM<)Phh!2Nb^j8O6;3CF_B zF44ptampEHKVKRf^3Of@mVL&`)F5Rh4nG!~{0WtOUa6}t8)ww=?0jDr5vQU%<>NYg zx2k{ZkE}lZ;*;u)nD($4f9-t@lLAU3!;&1mi2H>g&hQhDds<`oOs74J((V4}Cw*was-r3CuNUs*anK5t zn0;iP=eZl+o z2o>d&cD|dvURZkJh4-H;Bov==m3`y*@_XiFlh>Rpnu=$Bxz=>KJf3NzSW%_MR0Czx zPuuUc`S~0=BNIPoW`bS%jFXZ3?%r6ibyEv-o3?0O!HPr2vrBUxBzMi5=lnfTZBhA3r0g5VxqPLshAAt!embRPX0yv)c@us>qS=@&U4{8$QOEOzclnZd z-d_3mbE1;{pR4O5_kEE0cS&jPTeh&4g36if`@ZphI-dVXo8Rul^srAiK6=K~vc|4o zaMo?v8pCG0!*#4KJQ4>ZxQ`|EIQF!vI9{G2yi_JRj3a#7jfjfb&wg3`HCQ6sW^(=d z2YuZO@v%>T#vQs_+^+C^;_gJbQ>iDO8%G;wlvFE}G4>pk;8vQ!xRT?6h_!9|e68q} zLM@7k0vFzwc`lL=SO2nG)@<7Jm#lXDVV_GLvjlCIzEE}Zug|n6jSP+gJkt&-H9vSH zqhgr%RLE_!`keO)js=q(xdqr1IWPDJGyMCr{ z6)9{e?Aj&rh$Hm4w77o3X;+I#t>6`W!E&oEbP69bSYTu2w$I8ZM(5)}dt2^6mrZ+n z*R55$%Xj2spDe3U^gdw+w){i^hdBlzE1f1Od3JRil(RpWe7SU9*1EvloP=ma-TTXp zf|9>nP*m%eTWVq4U7s_r_j-J57{gkIw_6OS=dRerUATZdL~zrY+xz-8r*2%^u<3bY zaZbsun(xNnjRUJ1{A<4zhrBLzX*s!5d5(4Uv^@vjM+^4vxzg^({o z?`6wkSxsigU9l|4EOV)Sv8D4~P4A(A*7+jqAMZWvB=v2jk55ocETbV$Z~y1TZ~4ln zezw`Qqw^SN$*mcA{GG}wz6!pA&jmtL&I`@hD__R(0@NWhHaAY;@hV@09Rc zi^Y0khOJ850veJ!j~{Edxc#PyNV`1N2Hq;)|4DnKOz1i%>6}(`;8BuY&P9< z%38cce~$Zfv56O!Z{EpR7{cDxAEvyzJJ6J55uWjOv@tUH1QU>ylEB?}2M- zHuZ9MW0r5<(U6_9a3TL&vq>%p5-ErDkh zwwYZ}|KD+^j4iH~^^Eq3v+6JR6bR<#J#KodQy`*PXg|3w;49nR(1iDSuO3=^@46B) zZM(3a?AgM1D>J@t%;Y)z)yj`$vi_o@Ogy|7{q9UX|Fw>Pm+Y47yNk{;#_Uqw&A6|! zd}8ZXG52L!zsudceV;xwu4Fi8E8HC1^w!PncpMT~gNHQ=rH=GoeJbka{`-y!U zuH9PCaA4xfQ=z#YJ5QZ`l`8OlZhXw!cMelvXexcui~ z1_lPs0*}aI1_o|n5N2eUHAjMhfq}im)7O>#A*-mUE=Sk*pE3*#92TA~jv*0;k50cm zSteBWxc&a(UFplJ)5_AnO*;GRSlfiv9V&(*LM>efm1Z?9;+nuDXz<3Z<5%8C{~ynU ze=V6Z?N`FoX+bs#oSOOz95_TyKHGINZc@%SqurN_U%vbNd0~3_=9Jo_!KJH~Rqs0g zzPj%I`}eo^D<9@(J@vn^g5hy-yiHrLXe1+pf#Gb14GUjw+^F>D(`3Cl99cSAY^Gw< zmVG@SA;7HBq_AkhGKta&Y7(Uq&kbHh%$WT&`u5|{!hPE|pSrR2s3-#i`?g?m^fmDH!g>3d9C##}b@r~|GCR1G^H^1e)Z(B zpC@QP=yA23zs`$Q^x^aWlb(KA&$MBq(h9=_n+9+2QduY`Rk}Itg;Q&Y6BVa{lzXFI-tV=b{8=2bQ0X*jM#<@+YI~ zSvtF>G{!I%F(&%UuTn`=1g<~?4|^Vn+k zq0fPae;(CVTQ{gSt~6Zn^}uPvKZhskRBW9tzW=+)<<8{a3u`krN?*V09rZ?SYD@V1 z`lgphHvaw)elf|MMfJnyjCBrLCyO2wEoHjqd~^-#fi)a!ly?Xpk7v?vf5!anezke} zVk_s{W{g-h zN-^p9^PcCz!?-^+ZTp-L##)@o#Q9Vfm|S^@``IOz%T(XsNRVC@1J9=NBXzJvx5AcD5w@Zn<6U z@&8}uzPe^$T-{uHd%JP%Gvf_nbC_N}H)>Ewn$UMTcGfJFqQ0-Tsq6aYx%-|v$!)54 z|3ilAsf)497CgNnodrFydk(Z}8?wKXd6E;7{(SnjPuJ?tZQgq6@YKzdpJ-q0J64mx z%PVo-*^0m8x!}$zO@=xV70({*^-=G0Dw(6V(neCtb^V$0Sg z+PXW-?pR&{Cu)m=j*)fT}`PBN^FK~hKKh3jbFI?mh)xDmd8IX zHqXg+dvh~r*@f%wH}0Q5`BCb1&b)HFIgc)T^SX(DdeW_UHEZI5D5=&p--11j{=J>V z5kC7O7elhau?CKQS<5q}*W>QRIw!x%^m5dh#eFio>c`y(7cI`^$AphPW!htmnqJG-}MyY%S;?(;0p++5+ebvgIPnpbDVX7pXKk7r$x zT$tGCwR865_q8r(H{U5aHM#xUq*q-x%1*MR-%{;+7j-^EIcdf5qE({7ao3MqCvT2f zd;W5m`&u*q$Ma^Ku&kC!z9U0Hfo-y%DM4qi&&bcuCWd4dYCh?Q2&aPoR zuwaXr*iO4DIn5~+-|w*>Q9Iu2{w?q{=SDS=-9;gL)IR!j2VGRpu#~cNyz=mo+2+Z? zGn^Wh6{KwNn8Vc@l3D4L8f$*>%hu3?;oSkEzDY5w4<1?BzrwfY^OeQyAH5his_}5N zBzhbacayuf*(+yvm5_@lV+gCETzh$bn$fv00RsJvja-ZLs`J+7H#!>Xz1G*16<*1z7Z^tRcpLa(l) z+G3SI8vmZz8ZNe;m2v8#<9)tu7e5;}6ug<}e1vJCVNRi({B`9yTQgR7J`k9`PSJ@m zV2-!((OoUKt{OgDt`?}z9>@1b<~y&wr}yQjNByrWn{d2*+qJ{1N5VU`mjCmtN#gF_ z!Ly7v-)OX(q>+@6!CgFEZ!M#PXlT3R0o4`86Ecp?EPm3&^eFn&Z1$Pq+p`L{?~~tY z=yg)-=smrEpSFMRT*MJo>XkHO#y-C!p7NSX^UcroCz&j|%~(@gJhy!Pw1B`XODAj* ze7*U|wLa$RmDj~8KKJKOtdLuKOQx|RW|yU}4BL#V?qgp>bG6hA(r@j3ih#oL5hUiCLO3U{u~KB{%~;T)z@>G}IS|9^YC=kslQfp1?XsJtxV z7T+4RMcQ|lmZ+Nj4|C7Wo-3mqW4e}To?Xc)Wxl*qJWJwvp8YJ{xe;yhA1ePosrmL) zDLY`7R%py|&HQ<`%*P%V*}mG6H~0G5vtDb80|W&ZowRZjjqwVW-68T=#=g=Z>CG*r zXg06y=?OJ{l6EuhR{ediX|dw$*)?B2pEmwnTqxI}u#VZmX!caU(1m)&Qqw=(YLkwm`TeI?zv_=T@3V6{uM6MKXJBAp@O1TaS?83{1ONpGFqZ%T literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/ice_statue.png b/src/main/resources/assets/wizardry/textures/spells/ice_statue.png new file mode 100644 index 0000000000000000000000000000000000000000..06f9189b4c8424568f78ca553a75b5ab7c7b5124 GIT binary patch literal 2062 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 A4gdfE literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/imbue_weapon.png b/src/main/resources/assets/wizardry/textures/spells/imbue_weapon.png new file mode 100644 index 0000000000000000000000000000000000000000..a17a39661dc3a89b5499c734c849153e98bc6a52 GIT binary patch literal 2073 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}&M-I`I~Zp( zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KnYo3Sh1{Y~9cEx)U*_rJ7!q-K@ATXi zsiCsR>i=*3cDr(C`TXkR7Z0xd*w(ZByTWCkOZPlf4Gn%xN$6k=tnFE{fWMKYaiSor zpxUCvkpdl@U78b<0*xa@4jLwX=`%iK@pw-4_sYBa*=z0A)PA!xe*9%4Z~JD8^1FX+ zUjMiGKV3C`*T$ziUMOp8hw6*`|6F*jJ~6z0&x>yi4}SFR=GfsJ;K96W*FKJY!Uve7 zp19c~D zXZEN6+t|!;=j+86b2`kA@2F9JFx|a`d7Y}m9H$E!oELv~#_E?~_ z-@iShlcTihnxNO8|KF>m8$LYfb`}0tta9Ui@K;XO)=w%S4@%t?7u~#knrtq`A>=*7xS40(T7;m&ql4A2XUB0p^;cPR z9$wy?PJZEe86eP`jE_w5dj>4Hwg3^0^+pP1G z=4Kk{Mm*Wk;WVdd>f~(BKp}xu5-V#3R!FRM+QK!w6W+6Cno!4zwifp9ZqYMzc!ahb$>_WwB=D-m;dqOqhsf59?Yl~D zy*?7y&L6Y$=-m7J8xJNNnb`i%)!I|i|NNq(lfPPc|7Y*!TJEAKw16W(=*l`i&Qd3t z5{}Yt2lpLb6J25-ZE&4blBp_d_15&-b+gXs{0~>`aaHpZk`~< zX{%PQJDAlPtT9D{>20vy6~n>{$3zw=w+3;py(YD`qPJ|1+wQG?%lGl|SCtLSXnAEMGXHQf+EOuF_>d@)Nu9zqx?5=CIcFJnL7^lRd zTMwU>?pj+|@Iqdn1WCi|*SWFn_madfhKpwaJ2) zZ_bFcTdKu9XRCH;S|I1n2@caz8TL)-S}uf=bA?N6p`I-N3W;&b6sMSZ1g+nMI|Zc2T*&w%MrhRrJHtqEDPzrEft z=T7a^Cc{e8R0D~N@4s7oS!=)W?(P{r?mlUfn<^Zw;Sor{B$K z*T~pdzPLMR)z1!xJ9Z~F@BgnW|NDn}#hdDWAy(b0z1cIK=Np|q?(l9h&P`s!1z_MCba5#DH_)24GfcBW*Q?E@R*|Hp6jcnP*C7G7C) z_0=Mk2QM~OTUI>K*;hC z>o;wEez_xKUhT(1rMVYEW7AyS;`$7?eK~tvEM!}P`R#+9tnS4(j;@i|ag;%m?>UbW z-<10bUORN|KH5Bg_f&U2+cRI^|2Il+JFc->XpVDdl7ES5>P+KVa}#I1511wCYPxjO zyaRb=M{Wo`){;4v-nQe|jmG&Yxp&n*O0PXQW748ooAURb=l1_Uv-YLv97(xkv-tsG zmglN$SzC_=gcWxcxy9)nY`;1Ct4m5j#2Vv{D{b*E2?tXY86&j9gJwuRzBxg8{T?5g z(gTixVpCH6QoZcg=&2-*Wv&*|Ad;M_4)=L6fubt!Ruf`X^C z)OnOxdJRR7g`BoN{7UvQFNuV2BrpAMZ)S2b0YBGM&#H(6cJUi-Sda=zu9A3eLDUn>h<&~)|n<#+G+ zGH)GD3gDR5v}e@?tuM8QelA<+vN#|jeEJQY=)&)Z64I6m=^eC9FHcmpFB`0hi~?2DUr>85;{b$izw{R8`d&J?@7{Fuy+HPv-2e`G(t zlb-yHDRFLM`u7}L^%cufnRo1p(|Ps#C(9g*HJf{%b#KU@FE#(RwAl8?tc$txkDdOf zJLmT4`@bUhPPldK?Q`>`tP>ynk^gu9`se>lvcX%vaLfGxH3AqsUHx3vIVCg!0Ch3* A761SM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/intimidate.png b/src/main/resources/assets/wizardry/textures/spells/intimidate.png new file mode 100644 index 0000000000000000000000000000000000000000..2981d430ce860942266c38f9fb609cd46c648eb3 GIT binary patch literal 1464 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 SZCMNq3=E#GelF{r5}E+C<42AF literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/invoke_weather.png b/src/main/resources/assets/wizardry/textures/spells/invoke_weather.png new file mode 100644 index 0000000000000000000000000000000000000000..696fa95af6d0b533940a391d6a79b0489b0c9627 GIT binary patch literal 2319 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/levitation.png b/src/main/resources/assets/wizardry/textures/spells/levitation.png new file mode 100644 index 0000000000000000000000000000000000000000..f49b2809e41f652750130c5c49c84009b879eb07 GIT binary patch literal 2188 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 HQ$iB}$w$Uy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/lightning_bolt.png b/src/main/resources/assets/wizardry/textures/spells/lightning_bolt.png new file mode 100644 index 0000000000000000000000000000000000000000..7ad6746e73589c4879f3a2df498aa893f6063f34 GIT binary patch literal 1865 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4%caKYZ?lNlHo zI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_J^$EJaQbzlg>miFtAzRsP0?#>(IQdT;OXqqU(|=ay{yc<`y6T{*$H!&_T^YCa6F4{efEYm$^`;OIzN z$|Yle^3wZyZjR6M|0%tb&v)M5e3-%6RltFD+bmzXp9QUs%gWXmK1XiJLjbeJ&6Z?JWaK zwq4o(pBCsoJY}87(5Jz8(1ml+47C|nJ~D0%Q*WQKDHLQ3tNUbQ_Mah4?x0EMe*KQN zrY}dXh_L;6vo=TJ|2&a1{;n$nTNydUgB7?I_4xX@iH2|{l}Jl7^h^&v6v6B1)$y9q zjYIBmL2K1V!3lfgBs2=1&Q)nrJZjS;<0~?X$MD(OwAl$E{@PeH{W?W2)u3nE~??)tg5<)bJnyCpEP9VG@s1evi`-v!v>%2 zKFDo5Sai_9hbQrZ&o_y}aCr@lRnkx5CW%ZEx_hTt!lE;6b2=$ z0xR~EOr0oRFYFmpCnWbrLuSt5Q_6-4S2Ol4nv*>1y@JB3jwAA`yalEovGkl^GHJpo z3z=EX?EV|79tH}`*jXVuO)TN1{h2=xw62;w{B>0Q!HM>SBsTBU3V9qlo9g8SL|sJR zY6t8H|Lrwp^^Gq&GPN^$-`CFj7MiJpb)uM#q3q8yDd&g}>8gO?!Ai(c+h5*!lX#jaNh~#SMBzjf{?MO}9V&@pSlt zs|%(--R&dZ__&0hKPT7pG5hmJ%ha1zHF!@rDYfUnVpx0)Ps63``ktS4zk&^{#EN59 z8JGq&l}YF66uinluRQy-#|ie(YqzpQ*Kewq+_r6-#A?}&2TB#fOQs}UF1}Oqb2WoZ z)lV&!#aBOv2)71pJmS|rHH|%rcga@Hw`?WR862&T%vkRGGdfOaa#?=W$>0iSkZgOW z)LfnC7nZI*@kyyDdt$SFO|##-g(gD9yEYy>nZLJd&0VK$(HYmeFV0?mBT*8*)!Z||zOqZ0 z_L^PFTx=by@_wPByHnpR_cii6U7g+(D+CILJYwJ45aqBbHzMxAlbh-f_h#2T*}cB- z?Vst%_pav~6+aX&*(9SGe$h*k({j@L1(o`fK3M*kQ?}WV;rO9>B5$+~Kb)4(Fw^~W z&xW0RbM-=wD|o*AT6LmK{MG9XJN-;cb87w@F5ADcbBmP6_QogH9sOJ-v(Bza`LO%S zU31orzTK=#Cirry*d2bm$I&`p=Vj&Qg467$H5)vFWNZQ zx-E}vpCF!nY+(^UQ|(XX0+w*@z_9rXZ<_7e*mLiX`lSfhNg^vlUZz-1<=&r?ySn$w zt`+A6?k~Q)qWS#92i<}Plexa#>?O$+P?u2&pB<>Tk4^|a@zq+PA*|L1snb-AMe0dHX28Ncd z5>L)Dq-H-hdtxbX{n;`j&tZG#kBT1>4dVL_9dalOeQ4d^vth@bMH=O_6Mx&{DRhLn%$2W7&!7gT^vIq4j-LfT@ZRz z^jLlN{Ni`o)Auk7DF|>VG;!^l(5|q6V_U>lK9P$?T%}v)W?FB1y!q(1R}s34WfvMZ zxn_&5y0-9E*cPLZzy(Tn4H+9XCVlYWm{4&4eDSw;^5*6zdB4Q(PJj2N_IvG`{QB3{ z*|pKr&T~lp>p#q9A@%c@AX`GrP+HNJZmw`bquOwoB_q_#58OaVhJw~hoQU<#W7FRQ6trZm9 zqW4CWQ94;eU;laUUc)ItcdYKlAKIa%_iA;HSxrvj5hrcdZLuAxkr}s-S=9BsJ^Ul5 z=V^k@!Hx%C6Ic9rb$Z4%sfMmDt{y|1&APXp>pi*JLb%*?K5#C$kYUio*z>sIseoJn zW1QS4%Oj_S?L`@{yJm|&mYiZ_dqtf2d-~$~UsVh_H{K@5EHCi7eT?B&L!j7?+B^G7 zG#eMpH`V_qxhYa*w%QwRCo^BAORa@>op$|V(c@cdIxY2ULq%D2AN#uZ)0w95_BHdh zRz7^WmF0E2qp$3hD}lDZa`tVnP`s=^w<$c_|LTjviqhsn?bR1WLt9?6H9uy*-7d&| zx%O0&RoCmTuC94sGkFqjOT;rAN?aCW(b=uPyXV<@zCt6xsv+5Sk* z?Mhhjn%5$)|846$8-2euMJ7gkvY(S(_eH7m5+Vy+ycoXvJIk|)SnvtyBtNg;m-4vT zKKb2K;{}VRZMXZ~WSe_@XF-WD^Xk37 zn$1CVcD_%Srj=VV>Up|BBc4>}>sbxb4Fm>)Sgjzgq1Q^7K0*Jm+@6`HdMpub0Pr znY`b)`>DaB&yETWKbk!hI&PTV;9A-eW7aM)!&J|~WTtkiL(hi&Uj_F6JlX&A!)mc- zc3)W3=DJ+++#r%-Y{K%_M@Hbm&hWU0{eAuV(PA6kXIP(Y@7s|5bbW-?d#-(d4;(hR z5^`CzGvL|g&N*)uy}lvnqs98s;>mdhCsv8Yp38&Q+}|`+)Lh@Ghy50_xxd=HXVZR% z8EjlBcu~soUf+*e8M}&xqsID=_eqOw`1ExDhA*ouxBPnuy# z$hOMASFhjLQfd5%-!QL4czD<<<%S$A zDJ?&6I(eqdq|+ZSHiqTRwwx-zcT?xF#?m``KUBTjUu(&7I$#^W4EItNK}E@aXS?o{ zOIL0kntT0B`l}Oc%hpu%%z1rr<1fKSH)Yo6-DR70;d|zrwagMi%auIz+E1nJ_|@oc za3HvQ|IuJ;JEfWBo)QboGMIT*I5;J0a2tP{Q>-B2@~7^IL%KV=wp{$tgV(}TCO=!p zEB$lHQ-k~S&D%4d&+qOCjjHo9X>eckS!LxqVGlLmikow5igxtQKR55xKjFD1*Z7wO zM+U?)i<+v0Hbibt-~4+0dZYAjGAaTNIjnKh#P3%Ke~O&Nzs(>q!d5@Gdj7hMDYI4; zap|s;XILtd(VO9$8`<%Zd38qJ54o_vk7e2Je%H9{W>(;NnPb|Sxz4xZ-Ly;?UaJt zIjEUY#UQ}oPT13h^M;1 zbzPAim$@c#oZ>iU%z9Yy(%qzBiPMaN8*?!3; zX5)X-%&eR9w?zJA#hk7B`7J3to$eD|SWcz{tm~e0l3zr&C!J?e>B6X;dTP^OzKu&# z>}&q`Goa5|<<`mSc7COUMgRVNyZzwvP zMQIGjB-Xr}mtey@kJ0@4-JVcKjmp+jR;_mLH*@=)nC{@@_~Ex?*;Ugej{;AmOz`3I zRGnDE_B6{t?%MxPEtjP~=j4B!x+6MykCSyc*NbhBqRM~ovpKbyThw6o(It;njCMA0 z8nT^yK4DMylg%0?Nk0A`s`pFUZC30&nlxql^yv}H_WfJyuHRrNSHX7CN#|lH!^)f^ zn*vzGgTixb1ZDe3zVDNPHb6Mw<&;$UvA~O>J literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/lightning_hammer.png b/src/main/resources/assets/wizardry/textures/spells/lightning_hammer.png new file mode 100644 index 0000000000000000000000000000000000000000..913323318debbce0c21f573cd699de6c536f1253 GIT binary patch literal 2361 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(~%E8Vov0qA%4M z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JOW}?`Z{e*Y77h<$2?seLn00zonBcG zdR6wg{qsB3_h)^t;51ZRt)P2jq{KLhvS;xCg#_cef|_+(F8tfBv-o?*`8%t?ck&db*@QCg2j&W#&r@ zKA-q45`O(tTCnsX&*JYQ+Wv(%>jUF5HZ9#b%jI~XjK9D`$u_eX1(gLFvm*R|FTBeU z&%xzo;H3Pa%_~sql-6pE_3M_cSic(i~1<+wKAIgQiU zQi3@SA9=6oklo(7`Te4g`LhGP3SZA!zBA)ZhFC{CL&eS?%X9YDvx=XOcaHaGN!)eN zB=FLSMhUT~Y_qqgKis&pUYAj;djj7Ioj$gQl5HQvm7A9S=sqnlkBLWohR`yd9n<5i zy){G@EXrX?KK86_<(f4rt6B8wIWCK{Oy_^g)nMIGCMuw#>Aqu6#$l;747VJYTuxAt zs5|L%sMmU86R@MJ_)Ka z99b;LFw1{V(vuFSTZip}V)?8ls%GEp+50fB@7=97%>$DHD*hcg$S@ z8hzyOv-0!5X>=sDqX|U4-v(+P#At z>-RMj76%Y}3YZjluqgC&V4}P^@@bav|s#c%$5I zc;3mT=KS3~pXWF0#Qs*9#(2qZ!6i>G_v?ytzC2K!aLaMgig{(y$M4-aar}0D>vas) ze)r(h;_y$`mZ@8=*Ki5VEWCH%@5%F;4C#j++K4ig?JZ|GJ%Ph{!BS71sf?$cc(!sD z8XehnsAp%1mC?=Sr%QI$ex3a1%{|vCBCQpr7xVId6+Cq)YB?3BdYqdIf3G3M3l6Bh6Ex69%owE4~t`M=rt*rd3^>0V*bA_3)yq8bDsVaYPNB*yXcf7Q_jZ|XT-&7NyoidD9?(C4UzQ(%I zPr&&Hqay1JwFtc_4*!U!#H~er(4DaR7Q!2hay}t8t<8lKP zi<>+P1f8C&{bR{+xcA{F<-3k8Po245yng%i$x1P~nC~w4cz!GHlbRX(p3la*_$r^6 z-rnhp&z^O$ikeyQ*2!?|4DJ`jqU0D{PtTX9$hV;{Aua*f(IAcW&Zy$SbKK9!Y@DLqE|Im|G#QY z?7yc_Rq}u5x6MoLt&XlXdEerG;d&jDyYq`fY)dZe@bO)-pkd--w~x<#_a7Ac@OJfU z#)?Eg;g6a5#cG#Mzx0^%Euv{E_wx;JE~dZ8vv=LHxb@q$$1_%%i2h^hOVQoM|30ze z?$#GBE$-_qrsjJsE#nC5I~{2_^Y)a!mVG7i@e6iTe$+bFGxx-t)a=OG+dA`Ze+pOn zZTFxgT|9Q9$iyj!yIPBX?D;7%(?i=fSN(+AqKxBevw9jIF0A;n{lGaT-4!JzA7`-_^7G@cX>wuQo+ac;mMG*8xA}5H^`s0j?=-3mmoOX1$eu zl+5zws|yDU6UPb5q_+**4xU_Olo?Pf!SrZu?gU?h#3JSlU!92ug%$+IPUunEQ7jXBd7^;g~j$-$_A6I)rV@sk`3Fm5zjKOOuW@M>eS3Uxb`ht4*^y5o0)Oj| o|8=<^@}+r3eEkRCmdKI;Vst06FSjq5uE@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/lightning_pulse.png b/src/main/resources/assets/wizardry/textures/spells/lightning_pulse.png new file mode 100644 index 0000000000000000000000000000000000000000..967ba43a87e7912b2864749dbb08650a02897a9b GIT binary patch literal 1965 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/lightning_sigil.png b/src/main/resources/assets/wizardry/textures/spells/lightning_sigil.png new file mode 100644 index 0000000000000000000000000000000000000000..961bc7aeb496d2d6f333abdb6443b8232450b397 GIT binary patch literal 2133 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 P7#KWV{an^LB{Ts5;UQ-Y literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/magic_missile.png b/src/main/resources/assets/wizardry/textures/spells/magic_missile.png new file mode 100644 index 0000000000000000000000000000000000000000..e176fbe59aed35dafb7a45041c39b211c8be27df GIT binary patch literal 2088 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/meteor.png b/src/main/resources/assets/wizardry/textures/spells/meteor.png new file mode 100644 index 0000000000000000000000000000000000000000..09c1f47a5bb34db77825d97d64b9f106173b1e92 GIT binary patch literal 2003 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4%caKYZ?lNlHo zI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_WL|CV!Dj`S+^W#U|>)1ba4!cIDB+^c28`m z=<)jOx5e+O+p5!VWm;bjx*eo$!@~8|d8z8r1O+q2C860JDpI}tizJ+ad=DIH;Xl@* zU)Rubf&T}?A~By?TRJ(_E{XAMxe_=hXv5O7W&Bo$_q;z-J9qPR`Ezrvi>-sdOn&!7 z<@=oKYjOX--hci7{_hjp-<^~Ce_W6uX3n4c$uG1|F)=iF3kx#rUD~j3(T7)s{t5H^ z48yFGi%;E{WLj4c%Vf4s^v?Ch?G616*BfUiewgxM`X-}*(m8n=(`ybKU1@YX-!oZh zt(NQg5^?K*{6Einv%3G8G1MMa*~!er_}n(L zagBs)D?69L(nC`x3HUI#H_9Hke1M}sIiT5%qnvG??ahwmU8P|b{?le$=wT=b|LVkj zK;DllsV!-RB%@o0x_&@O0LRoV&HJXZ&2B7qV6$Lb!}N~v(uQ4puN!(5WmZ{vaY@?v zO?q^sXZrm$x~vO)OV0Hiu#s$C2oRC&D^@-yJo)g+rm?Bori`8r6xxqD|G(ogk*S_6N zwEiK7&wsf}mM5+=cCx(u{2@;#MP`Yz2j`VN4|57{o;JMjX7v^>OLo^**_AVP{uH16 z;HkF4KX-xtgBemgSMnq~$Upf!f$g22WM=D@hU{Q`_aShnW*n>o>sKHBQ5>h$y-`Z(pows4U@kz$L%e!(LHyhS0+|)aImj*4z2yUk~20uV&LvsvGI;JQB*xcy-#;EzC2XFS9ZBt}NpVOmvwV>^HHL z`)Ykeq0B#vsdvgt3xfUo&Odo|r_|Y;VgHZxPw)86oxic|(Esx0%#oCsMMi68W_t>+ zdc=7D&7`QMUVCpTytNhYS7Dr8WSFk)Ok((3s4mkl>%7=YswfmD0M^%s@Q#SG(EaA>d>j& zzpr=1`2KSI&-cIJ5Nq%&wuuemnamqG8j==O1S(DG((w1u+Wy$mQes;u&xXyL51l*5 z75{eL!wV^W{fk-sXQUtcen|G-j8#`wGVuy4G5717Z*cDj$kMnx(Ll~I=fmH#rfl2z zw>NEjw))R%v4Vs>2j(v;uGyTv>*%p0f#q@6r=^G3x^Ni2YPV^{zK0bXwmUvHu-TB?mu_#r>qrxSk9ftW zg`EF(<U- zwTL&<3vIdBW+0p0&8UAUdAHTHM1~o2<}JK&v$4bZ%!+Qq*SzwMSEVl-_L$mCXMTFm z;8B0zteq!*Jl#0szSTi@x1D^+rHNbge2zLuN4<$sHD%HhYx04|E?FdM>3uJ#c=5=gucfL`?JrqcgO8?`XRT?NxS>+oQFun_Er6nmNNYI Vto>o?Lk0#022WQ%mvv4FO#nT5lkxxn literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/mind_control.png b/src/main/resources/assets/wizardry/textures/spells/mind_control.png new file mode 100644 index 0000000000000000000000000000000000000000..01ac6671cd8e1e7babe706edd06dd886392b5419 GIT binary patch literal 2320 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/mind_trick.png b/src/main/resources/assets/wizardry/textures/spells/mind_trick.png new file mode 100644 index 0000000000000000000000000000000000000000..f2eb8fbdbfe2983ace5c3080cb76e161fc279b60 GIT binary patch literal 2269 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 SLKqkr7(8A5T-G@yGywo6I&l{O literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/oakflesh.png b/src/main/resources/assets/wizardry/textures/spells/oakflesh.png new file mode 100644 index 0000000000000000000000000000000000000000..95080a21e4ef66587e740b32b7a42d4f8afd7845 GIT binary patch literal 2106 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4%caKYZ?lNlHo zI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_J=G?q6}PHYFj)R7}$?{x;TbJ96mbzWWLOC z(PQJz2EnK_uBKfd%=_cJ7gO6Ui9xz zT&(<#nc;?f7Q?mOeA2Q9h^syG^sfHH&(&AmneMYL(DB}~QA2Y@CEu-x76A>-h!wkA3LC9l z6LL5?mNXm+IS_V>QU0Fi2Gu{mM8ESqE)Ku8o9}&H<$Z5OmdtgL99jZvceTIPcxB3d zej>}fq{4-6yB|Kb6uKY$W1iB7kgspTcIzGtZMy0wtNGyk{27*i)15Y46s)OR@1(bM ziH>)RK+obHZ*AX6XExj^3kbRplQ$`CmfM3xOA=;1NnerADtG)biz;jB{e>6UG#9+H z&d5Hmu4vG|bISL}t5aMzZ~buN7865MblC1vw!~AyuVs65CEITPnR`e=Ms?*+zI8%N zT3t0A&#vvWnz>}p=k=5B@Bb;lpvt;#@dTzV8$Ch;UuZQx_lRnApCZaqD(>zX7R4B@ zzwJf8(7H8dGmlvIP0}&Tmf=x~D(yG9Uh+z=_kik2-p3lwUKJBqo*&HFcI^^JOjA^E z;*8Mt-Jxgt)j9QJqtj+(MKvBbIQ7EBW=ZR0gQK^)9<4Fh(Z`gq^5y0mt1e2b$@Cto zTx4g&Vl3d9=fQn?@^ovFWhpYLCQQ@Q&OZDdcVg>Svp(g@hp&vRwy)8>ZaH(ANj9JN z+J?X>#TGr8*JSkc%qqSwet+>;Sdpn}-xLq`dEp0jeoqxC5wDqaN1^fcZSfDXt`By{ zyfK@hVtM+ll;eU7^O~+bE(#S@#S`5gJhJY3`_*iJ)k7}%J2#FO%gU%0E=gG`yx|Jh zIfI8bF&R@tL|PMtp4*fqGAgq6=WqEa+sb;)x^!JkoU@gjtBuiPE$g?1fi{+c(};_{uhz8%K3QQC4$3NEUSs;uu;wz&uT?G9x4@a373_glSV zX&%R&-Ge7tJiZs$;w$_sxc}=@tMY!eo|EM}2( z=LcGii=Rj;l-_q_TB@tL<)GBrOV2*fuu+`j_Qzm`k!-K!OqbB9Aye)3bJuU&dQZuV zdl$FedfVcO*W-5`I(Uq=lRP5gP-HL`I5w?#)}})Smbz=J)dky|XC%(}cwYa#Qmp6M(jPxR`(KXz@G-mV zHoNkgt$TKCJ@kF=1Z(!>J~u=Em{%8KKNxPCv;C($tHJE7O?MK!wKUaO3)giPpS|YR z{nW4b>r=7C8tNZn7HxU(dM@Lsz&)S;rO)9Bj@z;A%smCAQ(SrP_+~Dfbu{el8H;kh z138k>b_|DtB%H$}?$!J>s{frdzwGeyzvs(1E;Hrox<8)s(ByH7%;fCT_IYoLv-8gs zhflxp{kant&;Up=u0V?CbBj&irk@qxJ=ngr&)UAO`p?6|DR#5?oebGkS{9i5 ztlDSjS#d?hboYiMGw1!U+wejq@?ie`j7_&^7d>_QY{Oi=c+&QD;m(KW+i4ky@wFRz zaj6yhon#Kzb1AKeyjz#{Jml5J<<+VA-lyN+TXF2y-Fshh&YjIWZtP-zbrxfx+`q@m cmdKI;Vst0C*eaf&c&j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/petrify.png b/src/main/resources/assets/wizardry/textures/spells/petrify.png new file mode 100644 index 0000000000000000000000000000000000000000..4315bb91cc33548e1868a5c51a48fcb4172aafa5 GIT binary patch literal 1816 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(|3M3=C%ljyTsc zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL-|c|`dQRcbn4tzckaTk7fJ7!q;#==9rt z(vhNV`?qF=-@IE^^GZc_*JQ=D3a&keSbGGdGC9gQ6z4IWwN|*tDqwzi53_m4Vv{5# z#f6M5MlUB!cz5IFw}mw?wyn<6*DKq(Ywo+9ywh}UhpyZE@9Y2UwSV(}{`ffUV||Tf zL-^zJ{>1&t;tULZZk7zyvB&G&e>_>AkhY>J<43<+Q%6g-($yrTqLkRg8 z2H{vDSY&dfMJYGlY1bC#8Iaw3PmliH!fI}QF;HU zlL+U;%UoNu_wROj`ORv@q4oc^ta)*NLc)IK>6`d&s(QA3mlJhVUU)ZCS%|6gP|`*Q z4M*=2w^(8-?r}M)9IC#c;gOL)HTvj*<^EeP1uHwAX5GDg+o=b-bAqGp&aeo4gTzaJr;eN*ZgpHrH2!*&j+r(aqSl~4y8(Iv4x!0y3Vbz z%InD#b9YUC`L`E$Jk;Pif45rpQN+r8Yk?PAw%@q@`clTVl~-kMYORlmy6*a8PN zL&k|ce@gU3BIalmuCb}V_WWRT?KWw{&o8^KZc14Ho6)!YKvrf?oA)^}Nq+fzOT)@n za0Tk9Y+a$1BG_oOQCrC4=6gL(^XzD^iPdwu1H?B~{QAQ2`OxqCKPLQ*-Vn8xVMq0E zW`?*l{|Z})iK(o5eGUqTSL7Z&vs^N5o`>j_c-93{8eUm~Yv)QOH6`BJ5tv?KI^>1gU_8mzw-L)JGXfq{(XG<-tfV*vtr#xCtduYb7Vrd)b4E@rb3_2 zc=%60(pmIAq5au6GyeVmY8m+W`B(cf-nf0+IaIR$c*Xmhw{9^#_{(n3@F4&HA6W^L zZNg%cHXfQj`HK|8#Nd!q8>6Njdzo-7;`xi~Z45FpGBGn>mcP5RGQ!f%F3m#b();h8 zlUkmY&E5Q2b@iG9e_S{I-fq5FOPkYVt?J2Q|F~^Fvz9H%^jdv&(e>A{jFVJ2T>~Hd zJ^E?$(MpX2n|5rT#2C0+&S43oOM-KU(ozkZ$Z3T|MNO+NWo?zqI6u#Jwb++? z;X<|+Hx`G9FY8vl{H4dlHoeeH{rsoZ49hNSn&)rzeAVY6dRSR4!9ap1!$j)MyLXq~ ze}DP4>PX?40*e$Ix%d>D*`f2#rcFLLTk&kz+^0oHllDFO@l^BXsd`tzS%y-}N~&dJ zWXzN&8*KUZ{ky(gLEq-h#*ZxSO-L}CU079h>fAX$)yVaXfB&^88E=}(Uwy2!P2~vx z(do-H&$U|ipJa<_usPrPc!r6u`6jj-H*YSynZtA;$86@3^PMJ#RGlVD?%R=7W2Tnq zAfe~0794ikxF_jxW8C`V6*lW^4kvAV@Zv?s=g*(DemvcK^h|`F&EZ6bH)nT*ET1lE zFk!1a$L8vdCki$`zdC#W=K9ysqFYZtom93v);4_g)paRmvt$=dOuDC0)c@UX%OcKD z|GW~$sK9r&A~O}a%HM6PES@vT&+c&bhbLEB zzT|QBNIJfM-=8^YtHWlA%vi4dY_sCpYi8~K{VVgW_k0&=eaP*=^4|8|>2OAk)DI7i zPO#xoVqUg5HT9%2`=W!qKM!f_;b*?r^xXS-aMvAU>Ge(TDp%IOJN-Y#xXa$^#E;LP zRkloL_b)i!WFVco)YRNz!x;u=<-@-htnZlM=d}8zi^r?Jqb94P&WRtKCEEJ&^L&%_ z_xrBT?v>9MQZ zb5#G|grb|OUw6gYw5m z_MTG*R&V_H@o|Dy-OuC21`>S74=$K?`;}F5LCR%swxg>S->^!4-@WOgUPk@J`MCxP ruP=X;y12V)ZR3vZ`g>kq|Ie^WK6JjeLVFPd0|SGntDnm{r-UW|JKb(G literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/phase_step.png b/src/main/resources/assets/wizardry/textures/spells/phase_step.png new file mode 100644 index 0000000000000000000000000000000000000000..e58a26f58408c8371c1b10462073d6478503e046 GIT binary patch literal 2023 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/pocket_workbench.png b/src/main/resources/assets/wizardry/textures/spells/pocket_workbench.png new file mode 100644 index 0000000000000000000000000000000000000000..3cc8f8cddb7b7a66c7775f03a9188f67fb67aafe GIT binary patch literal 1871 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(~Ds(|LD20|NtR zfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=kWoyCUvPB@M>qom+Z|6A$B>A_N2kZGhzS=x zUZ4H;v#I>|)#l&t&A2ixz%ejKL_|j=aCOF1r-{FmR&=n)_gsC@9OW(FA`%$DqqJ1& z-4soaf%Z}V>c z{vZGU>(+i5`)daO`u$l7DnFkqw%DO@n}uQBojD8z37U@{Ec)6g=iOjnm zPx%$=6L7W4b9>#abV{^Tzk4{7PLso?~k--Z$ zL>34N9E`45KdVVvB8^E)!mT=Sp8dXi%)x!~p6Md@H$6WPbY%1TEQYUgA~r2Mt8~O7 z`VLlhFtS%w2-@!H2;UH4kba}6ssF&7+_{a1?)+iuD15dw$@`zAxJ(RBSW-@Y&jGQd z49gvH2K5=N_U|UwWQb08i>ZId%W!M{4tD!>68lP8Q|g85*Dkp=Kgs!UZjYgUOEYgs zT2i8SV|x5m$@{x7qnFJ~+7#!C^|$$lRyIz)<(-FXz$yV0GeC6Zz5QI$WMK~eIR)-U&o*@;bh zDrP6TsaE%$b)|^6tX=56!cQD$x3Zp?l2gj(eYieaet-38f#}YUn%j3O?CR}mdLsPA z)>~z@F5C0<2ZH!!Ub=C8nOARj`uS$zd;gy}FF16+?vG87q{)-`?F{z{txF*@ z7+RI1x$=Yx7aV&qb@dAt6{bHXd?ox$4W=URygIH)sbuGFx@vawmCVhe?wpmK*~erm zUu{0pJH?{6Fp!05-=`m*M>7nT$n;d)7v>NA(k3#O@#t5^qrG!3Zk>}=%VF2%w{<&r z3DdT~pi=L=y*HKp4;URaV&{E&Vx@cKPxa>$(nQ*VLs)GxGJDL5`f6Vr$5?!2-?G8L zt*y`TSX-FG{#k{MdDRZip}_&mJA_TjGGrF6bl%*tWG3r_G8SL<-1e*Q`Rm_zUno)O z6$xVB*dW}IqJ6lm^^Xpt;7Z+~07qr7~bQV(eN?Ib>IwQmFLf3}2$DjS{T8o$0 zbI(-nN>&k5DN=ltolv+b{N7uI2d~-|1q&?*3~*|3SQh4%)as&GJg4H%>p8Z6wcRE& z&3O=Gq5NjzEEfiGQHO73j{C2(9=JMttD2HhM~1CavQVglMd7Dxo7!LLQ&Iz?8O5qD zZ(H@%#pT8K-?w?+Z0q^rbnm@lsf~u>jw4LPtZR&}G;I9XnqM<>dHsjrQ||=4_=TOd z4u;EZlsXW7!(O*$-hp%PL)l#pOsQMX-+5_Yww&vS3=M^;0ln%TnKqy9p8q&|d7WeA zRnyuekB1Wv1@|5|_|~z$v1W((8{S2VVfe&>~@`f z%Kxb4d*&Q|CUJAdo3#xhZL!kH(zc(>tG*;36lx7o4Cbrh!&51SyVsJ5+pF1LD3JT>8CNbB9q46%0wby~AoIMo*y-%qDCt${#@->RQA6qo7e2GaQ{uS_>3P82Us@#f664Tr#hqMz~utdO`HqdE}p!2 zNO>yTG%2Q6vFdhb?)%%ehZ(%$*>=#{c7{X_<8`m_ZQHq>o^cq79&Zl)T6(JI(JuyF zorqxZnbrHhFzWq#ao%z3DUG}*j^EDy(<^W;eDJr2dmE>~nsCDpU7>7?9yU}Re&N<9 z(zav4iBpT;KeIm{v!d8GBI2F|%lzt_Z0mWxay>h|_3ryX&VE^`>#QEmHX)aLg&rMn z-f73Nw>D>s{Epe@-v4Wywr%UQ@?AN5cJc{xI!5L;v$HbY5$50ieINgmyK-+^D_Iyh z#o0e^-M=R&R(g@>iP~H@{XL=6qh6F(M^DYKDQ&1YWFRn`^?K~xjAy4`{J6-L9{1*K z%=u?x(>I(FaLDr$;Qz}VUS7I&7pKAnP3Kj<`=>42bp1hp{jQTszs{+?c5AzKLFHwO zx-E`u9?m-QotH{e8=O-d!

    #(%%Xzg+xUlMSjEJzf1=);T3K0RZg1U{?SD literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/poison.png b/src/main/resources/assets/wizardry/textures/spells/poison.png new file mode 100644 index 0000000000000000000000000000000000000000..85f147b6efde74c3bba3ee4d09d94060d8755c13 GIT binary patch literal 1737 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(|gZf(&xIcbMK_ zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=k_^N4X-N+tRW@G&s3g?YL-hD01bIz4uU zY`Ez0`t0{JEsej=xl?_4NoVGnsUaS-lbRPeCV%}kRr-QbmtD6j^U;2-ACJ0~Tmu4h zLcBJ5T>P=>nd2JP+g^qfLzZ6ZVCmX;>BU~pGgp7to}2UY#_9IG>E|q8X39TqOyo1J ze*ZQ8|Nmc7mV0Mt{y!eivSCl%YeShi(*+qCrf%hGur70#nInEKW<>z+fs{XaYV#Ra zB&_w35a3x+Kkd1tyyY~%8rZuaigE7>#$v5m+N0qkjs7jaYlOPEG0G{7BjIP(M@q)*S!C3K9P{@xTZdxDI=N3!@_?_>O)f= zg)W613wCzg@6gDcwslH3hlIhyzAA;(zy*987MzP;u%g(}Y~k#*FWZY(EHhAexL(#h zpH*0LedUGgM;_Vw9#CVuEm-f*qh`1^=4`4`b7!l?W*Hkh_bIbFZ*(3r{hDda<>X>; zjd`L+lz`bZhx8LHf;p1{o`|kk#J4JFueXv!a)(g;%@YsSTuP}h(baNcNoMKH`1eu)E9Pn~}4BEvpgr%?A} zxfgD7CGkw1b|q->HZ?!q!nDqGp2F*sz9=m^BeYyFQ$O)z%Bhvg-g`boA3y0|dh(g@ zv%X_4+pjAes{gmId9^5~NKXyN6tgY2PE-g?Ja}xH#H-A~bZRtGc@9&;{IHYrU?WF&4I+d?;S-;m>9GiM;#%@iH<}f9@sRx!% z;GK2*27B}rse7eL&#p{V)myK&=dZ+T1G0nLvp)lKPU+AYR{%kg1J}@!d|9R^4Wk#NM=SyoIH%b_= z+5MWiv+QBKzU!O4=F2o>q(YCVEz-;WmM{KCxqpQj@7I8x)eFxr4Oe1|cJ9hH{d&Rp z=Kpvwx&FMu-mZggZ?~(8-v9r!SmbY)R{0fIhJc@S3I}f( zoWH+Ay30pta#Y2enV)lFV4>~KjBkf8ZJ=u*b-Lv^|7hkuV>K> zk_>e}_NMyiCa#2A^BQ6&3bklljy9-HN>QQiRh-<7n6CwD)RPz-M~k1s-P4cxs~ug>^dI@RAiT)T87&$ePV>*i^#g^wQx)jk&fe0h_? zl*cBy)(cntm*9BQ>Ja*VUz=b=iqY}e5gE3!pa1l}I&doL=*y!$Hs?>WJGWK(8Or=h zViIn=vPSZYyPUbtjsr1|zp}hN_*?t>_T|PK_N|>J*5Bu literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/poison_bomb.png b/src/main/resources/assets/wizardry/textures/spells/poison_bomb.png new file mode 100644 index 0000000000000000000000000000000000000000..116b079e148303f57e4fdab713d61ecd8eca4d07 GIT binary patch literal 2071 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)0_xCNpThPYOK6 zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||;AG)p(EjVs7BmFP}X>y82JI@ywgq z-`4EiSHAcD_IqFTe!iRjd&>XEr`aXe*ME~()ojGe@ZiKsk%o(k^It9aaAmh-m(xF8 zjULhnh z;yTlT9jhm13g}HJwOw;ig7K;hhlqD=&h4oU9OW^gGmh?qlBxA#?)?wQ^NV%mcN)kwdvJ@ z9g*GD3|D-Eb>^v8Fi!d1{ezX`SIe5!TW00{3E=Q%>%KHM;8Nd*snO5RnCL|3zSuUk_J7Xi zS6!8Retz<_;(cK<_3M54XRYp85)Li_Q_kjZ{rQyl=}pZEe{y^LEzj-uB%Yy|M$o3Pe8@XkHUXm98~Ra z*co)@=GqZ|T6it&(1ov&H8X$z zZ#-MC^n!WzuHVO)XKT8pEl<3rC9r*-!J>}$pX5Xia6fFe6|O10>%{PF+3}g*UHMI$ z@)rgOS&1nrtc(0-_C@KhvRtPA>?lqN)@%XhS!Wp!c${luG;DgVnK(Z{;)_J&L&2%7 z<$N-WKUL0Ok#4~MojIXVOrhMIBdlb`{_Q@GUCtc6E`H;0(d^lI(MKllw{H2!_&RLn z3`+)|t{%fjEBY7YAGlDzPH~M!qGS%o%Y5x64dwF}mihOemVbSza`CBi_fxJkzG$9xxDyS#Pss_Je=3wAO5}VLcGbGTP7#==h+@>T6O*+f7O-aI&mDwgl#4-uViCR zvtn(k@Vn}B?_$)Aou&(Irv-kKeeYj!Pm{%`JoxjJ!zKUZ7uY%PWs zWw|b+Jy)LJnJO3P$-&iB@nn@1JHy03j~hR>E=c&$9P`>W!`AM=MqW;a+vT!Pq-UR7 z{w0x1Ij^H~wsz0eq+?lz*6&-(7Mb{`Olh}mnO4GDvy8$&+Z7=Ms+*EqJ)8Zqd}(MN?z_wj1}=?VA5~H{Yhm=O#GspU+ow zF;;T=y-QCI$om(llsrDVd}>bo5m2h!oZlq9fAfU0Nj`>EVS-VuWtWx-iC*-vaQ8Cd z(!I9yHRF#7^#c1%PRyD<%^<8eVfFqnHlb9Dwg)xyWw*{S&Aq{=^4FSAmb;gTux$bkCfxZi;A3AtgbG_|@ zwp;&VP8@1)>2$bJzv<-G_*F)?WYSI_>%Vx$S7hSOt_urZY1zNEYWb=x`|kc1ok;%| z(uO@(lcvR8e|AVXR&V$H=P%lf#OIsOKOC*Bw|D93ujQ7V#`4Qpc31c4n7*;8>Uloz z=L|R9LaT-|d$|G}@62mm_2K&2;}M^~3a)YT>e4UxtpDuu#cfQx%`5iof2}fqcV*Ms z^7&6L$uD_xL+I0VUb*WwDl>K+ech;^$M4Xp6S{`=%7bmUjHe1X9+{~>NAuCubo+#?B4Zi&edavRk9tgIWzrFRwWn*n9h*w zt2}p>LnQRM#FbrjeOBQVLB@?2LU19V*8oA9gbhFqbi-S=oHhHSCX2%v>om0ha zzq>9W&wa`kp{}J#>q3r&wgmUBEK57E;&XoHs}xhusJv~Je-}LB(qmt1#=ov;n!1Ux zzgv0CU3cxgi(SG|YsCtU9p5f-;LM7Zdz99lws>lMa+U4eMfaCIDzfw3KX=|vg*(5u za<%uHKTk{8v+hn|sXT-Ko{0>v73&o`|`NYSRiBX4=Tk q-@o9`OgTUG#vkeTeyoZA&w8>v;a_dp(oGBu3=E#GelF{r5}E*CVaO-| literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/replenish_hunger.png b/src/main/resources/assets/wizardry/textures/spells/replenish_hunger.png new file mode 100644 index 0000000000000000000000000000000000000000..6a75b319333bf403db9d3d647e09bbf7f883346d GIT binary patch literal 2198 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)266m>8J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JTkn3oR{J_XEQKxD0{j%hD01bI^DA; z#$EPU{r^=}(dGX7my^#|9NYN#h?<2O-@(of<|IKD!6TfCOhUIAJ2@106g*~%nINF9 zA|PZwA%Hy9M$B8FC*2}OxDEfc*`G!l=X0tHddnL-CQ_iEE`*5YWXp{3CXU@$#e@zk+ zU|D-W=uDMZO(QjH+Hi={}C%2cKy+876v(s2Opn!wps*Oh$vWy zG zO!#y~JJ;UqNGQ0nRX`&{Vg|p7?|lIcj;#V32ZI+RZWFuWb1-jrtJsgb#Xos}=5rqO ziq7X6`$uQmV6c zwu&bc*Rq|5!@E4Jy%e_c1$MQTb-Z_-W3}J!Bk0{Lb$N}$pN6gXW_WPVT>(;heHe%&p{E))w2dvE@1!SF%oseidc>JiA8M=EFWw zmWaJli|@5<^kr0y_Ke7_^7_E~Xi3V>)sa!}3|{tM%xu)sd2hR;Y2GuP(pf1J-3>h= zqhc0Zlir}`G$&2w{|CW;HIGbYGB0j96z2J^%*$!(RA!|gZjZGOUhbL|_~kk~&$_%# zdu}X|m6&zzqF}^@4b|(;dYygzqPG0fu^@B1yStuEJYPRY{QpO(iD43q@tpf6N&Du^ zW@7LPl{aIWckKt4(qhiuMej1-JnPu~-mby^Md6$5`$vD+z1IIT`PuUFi81eukGn2v zwR-q4c}~SEmW5(o3gukg&S#~rFS)Z&Fmq{uQih<-+KXNsy=n%tcBN;ywv|0l%$C0M zf3AGtPyc>ntG`CS?LJ0IJT;jf7GYN;9yh7z=gjoZ9wj3wWvA_;moh8Pw9Y!zRJtjc zgGIIJ;;K{3OAWjPU%bj}Yn!^1jlb^w?>!%XtbZYA!m;%ec7XpU`G3z%I(@A`9py|CC;+~9i8hR&rO#@}S@ z&)r#={G(i6nZtR@wG}^EpPX{d;aV6Lv;W%SZCkn*SCUb3RSJ(?X}ZE3SO4j{%+FWbJ=@{LaSHmVC)1)kZ>Loz;bHf(B71mK)y9o9&?;^RUC|=%bn=|E5-o ziQg(Hb@+bIIi~vG`ZxdYgmWC4pmSP+w|&N<1?A6F_5T0X_c>O3F8*zC=8Vhdz1w!C zhD4dMDXWQ1I`k>rJz4n|hn)HqbQ=uJRdhl1A!Ti3+_B!11_mRsy*TZL~33uh3Sg2n+cmLl<%VR9cI}_(jir^Q%HY3II zu!{0Y*+nd6SuSqcHL58~lPxqeD!PvPHQ&ygt)6x5W&GVIQ=j`Q|7CnFu2=kfqO*#$ zw9EB#!f#d(0jRoaC#VojfyJ)4yN zp!MlAt{Y{>zaBX=?yoN^cpPy}X-l-POu%Z%bzheG==!)hOEsq1c+N;s?J&?gXtlv$ z^YeUWca8K1{kAe2c8P7y-?%Zh@pSER@jiBjKM!}xs9%uo3$S=qu}3oeUp&Kkt7WZ6 zqsli=K9}d5m$v)Oo45e0ybUhkMGL;XKwadoXK$T So(ls51B0ilpUXO@geCyR%lsbz literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/ring_of_fire.png b/src/main/resources/assets/wizardry/textures/spells/ring_of_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..19fca40a4cfacc7afd467796cf1d51de398dea98 GIT binary patch literal 2248 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(|gZf(&xIcbMK_ zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=k_^GJ&*iS7}Zu!wz~_{KRfs4+`Dsm@nyG@GMV4ra%yZ~b-d+NY3{*dc&x>RS@fWbW2bG8kCQVldcko!}Q(@vQX2z2tk% zl1Xh`8e7U3%|8Z;`b@cU;PNfOqb>rWr>1h5&zWwmdT#08yD~DX<}oltSlJ)moX?SF zCKSuC)HX?ywtZS9hj-qp`5=gAkOC_Q#?mdKV$ z?hG<^KWnqnVwaV*=G4=F^1P3{o!-8j`Hbc^qvJe`M{E{4IQHygc-D4o>(L4NUXy!& z^0=n!yy}&d44szJbIT_29{ar5+=4B6d%}$Sju$9;HY0n;dF~{9` zsdj(+VUD9OO6J{+{88chl#T0SCjPq!R1IuoYjnAO3pTI7drMd)f7m z##0{TI8Q&*G+SzideDxKMkOh_-(GxO(w}qSoMGPmi3XFJuj(nVUOMu4x0R&U)Q|W4 zk6k&ryi<#xwTkJ*c}a2chtnianR=f2w6ye6l*2dk{Y;FzvsJgmI(_>3dBdhexfhKe z)bB5OyNYEu%csbPtM)wqv&Yc5L1tcp(#6YJ3*l&93?_HIr=8>N+SZ=vrWcw{OBYyj|bH`=FI}9gO zoq8q_7pbtM?6C=w?W~JdiU?$CPT*cJL%eE}SGc}O zeqqY`nB%+kpH!Mjf4CQLsNkxE|CAFp6#-K&Fn+XP-)*e(`diGmCGFM=UiZacD!pwR zv)T8?tkNgUD~`!8c39waPV?=;Lbv(q-?up4PtMu@S#jHud9uxhzmEkSQ(E}amaRiW z%k7xt#|o#tFHcsSID5V*+i>A?{qKv?51wFjS8UwIVDwUi!EdUA?Lw)a4xHbmPkuJP zaAxn3-|j{^t4%C|jQXy&L@{+rb}YcDscN3VJ;?(wZ>KK+buop2@Lgo z^5%SAVO&r%L2%Yzfm-=E8SWeAdL0c4lO6ltKP}psdS7XUhEi9j(X8`9@Ax(E-C6Rb zZIeNl$C|IZFEj9Hgs(oL^oCQ$nRV&Eo(Z+=w|rj+C_bKYK+}(9d6!Sa=_A@aE+;s) zq|3~;T>78s;hW?3?$6F-d+wTYy-zs9sYIrJJ%o_7r-}PL$nHDp(duING`ggl;Oy2+C#j}Q&&78Yu1$=jE@_E|QCB8V% z;7-eSrR1M8j_WgDXMBEtuF=1c1KZYYux|1ay|in&d28{<4vxK!UNeOC-gtZVFTHVk zwd4(9qoA&v?-C7!PH6@+D>SjsVslTv5p8&l-}>2qnv;nBKGI@t)mNH|nLn z7e2M+z>UepI=V|!)~0$LwNgoU{@~&DYwh7Tc0vbseEhVdNJDUy{OSg+8G^|nLdp5D z6)RP0lznf0o$LE0Wy(GF^~!%A-=A6gpDXQbr2DQAjW>KRqBE}iV!Guflp__g-QlNS zV&1_W1qu&uwtetp?px}lQgvvLpB?L}t`(02rIz&^>tha0^*#HsjyI+7%tZ~A?}yUB zJAKmA)gQ^sn8+0(tn4V!+q;m#ib;Y`cD8n({!+p9*IM^(ZHbvPbYv`|7Cz`PXWetuB`#x@ zK;`0>t!nD5Tc@2gEG)PA@Y9TsFLdVZXp6n-G7`pNy62fce9`7*@OtW%9cGcK!_DG# zsmPJprfK@Mt8dhGWChRorTlr&+v<7qX9h3BWS9S?vhrFk|DHemV&U=OqQ2eBuksa( XzuaTr6&T3Cz`)??>gTe~DWM4fP2L;e literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/shadow_ward.png b/src/main/resources/assets/wizardry/textures/spells/shadow_ward.png new file mode 100644 index 0000000000000000000000000000000000000000..c8350a6f50565c5073b0c2c1f9ce23b26741d7a4 GIT binary patch literal 1784 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE({C|XBhtbe6ha9 zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||U=$K#HP!2Xp~S$z*6Qiv7!q;#=yczF zm2lCv`Ni+n_P<+~xBIy9#~xW#ABR(1EfXRXTyHl25Y_n4_%Z%R1fzYU?S#-nOlBUA zj>gVvlKpSD?Y=WV^!vTTi;m|`U#{N5E3-0m`|j26e$V?}b7kkJi|w|L|7XZO`1!Q{ z;6V}N!!PWVIbN}B{?fb6^4@f5CWiPp7KXlK^B&he+&gB`)4;#zG-7Pz%QTv=Uwo@Gus|$O2rv5H8#ne zGn&L|#AT!z7#Jnha2Ya=Nl8EW?A?ju9z_=}g1B>$KA5Yi(kJV$he zCcBJK@_~n)hE6HF|L5Ko+VL&!W{k1dl_{6BzQvr}{Zx_vP41qjGS;aImfA&bk@KC{ zcuIPe-OpM~sJ0NUdJ}lTee!XGITdGm?$_KYS^Z#Jt3W_;h0!k_!J@QBmQxtT*UV^X zk~EFq@?4@bR4el4l=fK~FCTx9sjQIXmRjBE8Tp#aMd%QefOAVkt_UsV`9ivpREsFgUdM_ z%y))~Sv;M8r`Yz`EMrdH;MvYyUsiUo97&nZ)TX{%U6gsHN7|F1f;9adIrEaUUsvqm z{5z~*gt^U9+C#lC)7ax3uhum3^ccD#Ro z@w%j>rIMG*-Z<8;p}Yt9PYM3s^&s=dq+`=$&%dv#uU-4Pin}7bGjdjeRNSRm1)Kh4 z3D*{`7ZzwdS##+4YvXfkmM-6P_E)Us2el8c)AOpL6BL}MO}jk3%Q9T$&|EEt4j}{I zE2lZ1XD6;u-m_ya%f54;vp>A9zIUF#LYx20ikZc&f}JW~roNYRa198&!ZO)q9k-Jg z&q|KZ9ujd0X>%j)_kCW+e;}jw%oXkM#B-Y>gS-5o4U}8|2dK!o8vB)tA|x6InFrzVqrVMEF}mO%GO+k~C!&8HcftgyOv=A*^6%tpx? z^ZNE;QN5t`>Xq)LfqtH|3!U-HFzSG&pIdY+$^)Smq*^7ex-lT5i?SkHX;ckJ`+*iTz0Uv!uM_T#Di>vO!-hims# zH02&!u`|YKrGKFXm!!eNo-eN$l#*PSvZEhdnXICqCHrCi|0U-)PnLWy6SiLa!=Fn( zUL2NV*#GNt*5Xq+zp`Ely4>IqQj(abF@1LL(fzYN=Pg^dWZ~nFTi=}bOS>ES=vPV2 z*%$V+g@SLDZJK>}<-RO~`)>-We2?7!`>;OuKbu{j;)CyhF4izGFfe$!`njxgN@xNA D`dLD0 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/shield.png b/src/main/resources/assets/wizardry/textures/spells/shield.png new file mode 100644 index 0000000000000000000000000000000000000000..0b1588b4e2604498b7c2676290dcb6e3341b5dcc GIT binary patch literal 2370 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)2&Q4l?{#s@(dI zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_z$hT5EBhu-?I!~R$9Yc|$B>A_N2lM; z7r8Eb-2VBQGxzq2SLfC|OiDh$!lXFCTalAuRTdKRP&l$tHb>?_!ke#Cx0aWey}f&L?#y`kG{ZKF^)LOc zq+WUypZi`@zyJOFMSgOssT8PmG%+qBKwvWu4?VcP?y3v&%$dTRgsxbl#=Bg=xH zpG z1bZ=eJqQsH@yecJbn(^^lS4lme(=^520l{S{x8feMH51*O-D>f1~0YyN1; za947&xxH}{_r;9EP6mMsB{Y~n)&_7Hi?9Z^tYPVwwK$c!`_$Q)fv;A3SJW}zFAn&j zpm(ZVaDQKzlhNE|F<8BcO%&pJ zofiD8>P>8U`SzA`_Up7X8}6(7dviP=yC!`}Gy8mKa({B!w?(UT*XX(L{GMR`^XA<* z*7H(+m!5roQZH-S(I-dCU&>hc6_(A2%4B;Q8gPr@{?qmHSATxxf6v6g<@osLte-)h z^7fyLiv%Y>ndXf0gZJv^;{g?ZyEsuYF7k5jlP)b+vQrqco&7NV)wiT`UFHm3qS6oB6 z<^8o;hT9k!0yI(=^cd*QwGKQP_AgXoso|6-GY@O7i#uK1$J9SNcgglIAFj#Qxo@5E zTzGB3LEArI^pwQW@8*RS{%yheb02SC|F`#V?(K+qyE@)qWiW73Jh%U=`c8ftf5@48 zC5d~wHFuA=UQ+AhD{BlM&C*C^_$S5i_<`AL^QTfi(-&nZJ6X(1y}$0UjCD~{$a%Ft zjUvz6{0o0w;g~$X-l6cH(e>r+nOC?fdb#S7S?zQ-o-*2W^}S*Z0lB3ZJVwp`S1Dc5N^voQIdtLJFaI0 zX=<>1D9l>T;j}Z$*wEH_MXB+=+g|rVRg7vaN)s#7WIn#OF-*97vLT4;{`VaQHC)%{ zJf6rL$oIBulE>XAuiVpD-ZKAa%YMZ5h_kYW;D=fl8v%Wflf6=TwXIW&CT@B=A@_U4 zjJTviL;mee1&dvl2nftS`E&J&^uyQm>%TuNc*lY>Q=}PsS^q|PJeQuWG z*SX3w78=~TqH%Xm$jYs$(@$%NYItTdr$!zr-*S0g?n0^clPXrsjo2l;JA~zE4NfD_4Jkry!JKTy?FM&=3JS5Mf!)|&tH0F#Y64Z z$0Cj`9iq!kcQ-F)k5Bo%EsRTbcI->vnAn+*A0PBz5uWoQMu7iospE_8?&s@1e7s=I z(>Fgk_`TvUv-hbbpG^8?EBhMn&ONhr`-ex~`o+5T2P5)k9zA08?~j(d(d?Zzvybz) zdWai&WY3UJ=Kk{K$cy@JI2Fe^yy{U6Tw z@ah4_`7LrPmt@s8*YHC(eH(v=U$)uWfeZeu0mfQc7Jb6QF{r->gyMD`@FMrrWy7FPX` zUG^!xV2)7UUWqR)mpF=!?P_zGYa=x^I``AelLAVY=CIG=?J~P))njxxB8+>H&lEwm z%UfrM7@gjhBR`+-|Llk>Dnh0+=gm`}^kRXDeP4xX&3VpWY=zA(Du>qZo6hj#RZPNd zvy&;CW(qq@VaS`XJ68PqYUQ@ZFvV%hy+yV<`bkge^6vQ5G`({})SkxorVcS5Y!7fJ z`LN{H_!`dA-7&{T>goCAx!1O5o($nqmD6xM;#@f^$nw5Sl!+JTiUl(`H>nx6uGuTW z>&0aL|IIg>#@$i*{g`>~f9B*=qidI#=BqO>Ffe$!`njxgN@xNA#^7et literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/shockwave.png b/src/main/resources/assets/wizardry/textures/spells/shockwave.png new file mode 100644 index 0000000000000000000000000000000000000000..49f649990e58e6f8693e7fc8ecb8cdb0e3987c7d GIT binary patch literal 2448 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(}f#-3(8k6$Bk% zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifu<~>3icQ*~7tO%HDeLLt7!q;#==AKK z*ig~q_0LPs*Y1CIwerr)%=ET0FU^vSOihk$9Gd(W1x%!POd?zqm~Kt+pY-FTgOAH% z&L({Y#~wjx&KqW2Oe=M_aWLn;EME3`k8%0C$9JmF*WNEa_wDf9nPtmX+%Hg7SHJl@ z<^TWezt`_&>t1uyBwkg|LxnOb2e!TCmTx&=z_ZU_h0ej9Wu+~hE)SU)8+^4*<7}U`c}_@` zRN?f^{j=z`Rq5$N@;r}Xx zF~`G#_hPx8N5nZxTtfbp+-cVF?)d4e;^}nNWP(b~M2&kH#%p5@nKs6C&FWJZahg$i zCS+1oRbP-%qviAiCOvK{8zwF}RyQ%DWliFTM~U6P*M;hFqn`J!^PM(+4F z!9$T#Tmz@5Uea{7y~TfqYmeol>;`SFO^X(+(mJ>-Eo{whA-ResFSX8}=NMlt?^Be{ zED9FpFz(Jx@tAAt`|yh4Ds_9Ok}m>(jyao1ZoctUXcfyQmE>r%tx>XyEb{)`cH5)W z!`H-i9AH|ZEs^wg+w6<6R(}5SFApl7s;^-bD*QB)CrYK|)#pnd2i=T*m5OH`UJz&S zF+}^uR-uP;`wc4!kgNnC`xIy%rO*w@`WFvNX5z{g*^~lb#i+Jbxw-CcFQg()6&frJ*2`t4 zyoa;2*=L^pp7hjr4zF|196Q&dGB(d?Gi2s3h*~?ra1+ZF{ttE8=CjRXe0A*(O50br zF}w3`{MDAql6Uj7%B>4&CA+;czwjih_dRyqkapLqD*Wq1UUts5**lURt8FVYdB|MV zEXPqL#rNgw!>>OtyejRR|AWQ%dSRxPsdDqwj>je67xKj&wPkMJv*~%D!tN;tx>mPU zynh=1_+!P4LY0u?ZVDFWR$b;I&t{oscYgi4u}-dLXKp_4XEULX7XzIZDqKxsoIYuB zly309>x#?T7wVl{v*)qiwzri+|F-Qe{3T}QF~{2Z;}L^(4jfy<7>_SZv)-{c?o3c; ziQegia`D{%OAkyj_T;(jQu=br>d>yMT7AkJ&f2gXO1W1({ZV|p`lajjnS2_tcX!;f zTCv+Uq{}tytJSP!i&kkhCJ5YJI$2BPW&e+V%8k+2zX<2XI;uQaZYp%lW2we;uNNER z7HyPRd-nUHynAhyhEAu8n6@T$>h6|17Ob0m?#Rk&n-#0Nj=xou;S=Oy-+1)D-tF0o z>lSUlckE?^xbXAyhBHkxj{f?%E~Yg~!=Y%_-}|)kelH=3xlkZl6{I)yudN)PxS zEP1{{*78L5{+ek{3mHC_zf98Y5HAUmmvephX5ocPj^*L%dGQT5c4=>jvRa|3$FT>m;CJ7!d zym95N&RW)u5j}e{C)Gb^xOJg)&*$0CSExP;$u?zrXfW{`->>lX&z`+rx13d9FH-eM z*hj|W#%k(rZYQNB-RvySbtWG_nRZE|%WJ{v*$V=T&U90&1O(9LQ z%ibl0eJ#j)|335o=hG_AftQZAX{PYn{A0LSBbOK%vWZRmR``WGH+#J=7gXDbd{%3} z|JQm_!78EdPePR@;^p`p1ER&?lqyIK1K5RZ8;B)4~jk3y2Ln|xc1JZpPitbj0)%?sZ zS+jG_uG`*kA1k*wB~HoUUKF=@+0F^4U0+RN@`woIz5D$5(};le!Uel0o^sWRTz2Ko zxgXm42B|5Q|EKT0vMMy^^r1qTedU|Ctx*?gS~c_enTdyc>OR=z*8bhHM*h&Q&vHwG z^gI@-}C6> zE2~0fj?ZlWHDz7^M`56H=42cDu28K@Q~VD8?GKi>^Lcs4GcD~=z}mzV-lCl`k0pNX z`SO*2f&1*jt=}K*dRew6{_l*N55F5e6WYL_!Llv4-imPnBj1U>=G@4X=R#LjhbHZ> z=vsFAdhq_IdW&X?yyWk9sOfUZww|s|1#Pv*KmGsVd(+RI=y5i_M!@m0o>n eJ%8&TukFfG_kagtmlzlr7(8A5T-G@yGywn`B9Pwz literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/silverfish_swarm.png b/src/main/resources/assets/wizardry/textures/spells/silverfish_swarm.png new file mode 100644 index 0000000000000000000000000000000000000000..a776fab7afa4c045af6109f161760392c11ee151 GIT binary patch literal 2517 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4k~ShIY!IRgU& zXMsm#F#`j)FbFd;%$g&?z`(#>;_2(k{(y^(-^4KFvD1162F@f;7srr@!$+sz&X;*! zd91$p&dr;5ZwgOeazgRt(v*|a-e?pqIZ>pv^wV7KoGym9t=(~74rTmrj{6?}BDE@5 zghNQ7Ac%4Ht=@|&8by?5 zbLUsf-o4IE22RslKmC+x3tSR%>12>ZugxKiq;-L*_4Qt>uQDb4-EMDXdj70;XxXmG z%NZE1&*sX%7p!r!@=U7aWfMlfV@sE+@>TU~OfmUl;=XW&v3YcA;zGZzHIk<{&6xlG z(p%n@*ScbMf79B1d$x|Ae(}e1_a|Tfr1S5({oJ6KKcCVTYJGlYJJm_CJ?@O6!Xu09 zntwm77^bBrTK5Ya>8aX#H6ynp8kyXIev`u#a{n!E3SGeaBR7qJ1uOM$D*dx z$R0IeyBFu@o~Y+a*r+t&vWnJLr9cJc(@ftkJly$QPtculS*B5`ZAfV91@9fd4#_@R zP-nDpN@v70*VR{*mY=MccYN)8`|i}plt{0oQXlO9|IT(>{83YX4#S?xc*W(KS5_Sp zmp}QiXW5(Y?}{(Hee82>LpxuhOwmiP-g_6-&&>>-7%c5PX zyrIG~cgQ(zJNMIDXwsrh`?j51Ywa5pl=eKU=EJ?@Ng4CD|NEQV<=PvywMplc$ED!c zp89Jw{#$%YoFR9;bZcdA*3vEwsT7`%HU0PNE94hzEq<0Fc9w1BeviGEmRL;|IBGa~ z<>@Q06}0r+4+~nl9+aF?@pS6+jXK@$@9a4FL4)Do;qSGdW}Wixe&BO>IoA~4xvfX7 zX3vgh;Njz6d3|+C${L&1!pjApcAeY(KIg-kE>8jXntzdJEWf5^ZDq2IRrOMOq{66~ zT$(D`@bhP-hp^A(B>`s)t;3(T+y8jISye;Is`nRnOvN`QhSSf*CPcb~ran?p6E^zP zDzi4MySMlFlN8p=CNHaNui5nlF6O@TJELJuT1#NVlIWbAJcZLnci+hs?&?+PJaaDW z=H1)2+zJfI={+A>R|a`LSzyh;_~(K$N6eoC_V=PrpB4VxtELy8cVbCv>AvE0w#aEG zJS2VHVl4L;?U|7_x$*6URLQebUx%DJ7Rhj(d&BY9clK6KUwTaFZQ1N!cUTZqfJUe z>V}0v%3Mm8kk$*K*eXersrb_hc~Z zzc*L+J4|A2`!-{-GP~=bw8tObvX0UiaHMOzOK_U{hB3cf!XLPZR1L_Dz^~w{4w)^THW|ZHldn+9sInD15AT z`}Xaa+K*cO@}-8eD?>sbuAQIv@zPn=x^L(EHC~F}h~-`xvP$AuVQ%|gx$F7+e5QO0 z+%jXLv1*r)h^vzTi;Lp}FWW;i+x)#R?D<-LV$zw(Z}|g5IE&v!cT6hLGMjpe&5Q5O zyUHxzZjFzOoVL@K|Ni;sWW4Z#yLq4QhEIP{!d7uv!Zk2Zh4b)*$hbXjweQuJdr!E& z;POp1Utt@4g~{a`bzUENd$rhhQ;5U$t~Kk|PYf<nD<{MF?&tHE|l z<=gh@Gj`cU#ii!0JCs%2D6YT1X~x<4QCB=U@9p32zfvgawzAEA<@L`k&423@P7BZs z?|8ZJgwWx4GR9vc7kM&k-cL7?Gb~%~b4+gX#_k1tf+_6>4;=jLBv<>U;PbW)GBDoqMh^S`5mfqR{f&Pv)E;6%(1x@Eic)2-`;(qRW`<4Y5w(_w`~~`l9Od) zwVkwts|??nC~!DUvQYIkx)h?|{oqn}=r!|u>dW~ru+C-Ymp4$esa0V%@M4`dJ>Aet z{N~M<7c*|KIJ$iP<63pse!&x$D(g_6&p)Q#Y<1<^&f>DuTd3>ABB!Mh>7N&#Y5lx< zig@|UZ#iw>SdJIItYmCH%x}oU8+-8_+ePm1eaBB+?4O)nIqm+R=gBOLx60oq-R66z zl3*b5fKNSQTB{aU#I)A;t|}87mc82Z^|R@-=ch!9Sif0u^?ovsurTk|ahjy^=Kc4I z4+XQg*MH4VXJnXH|ITRP^Ub^WpN{`~_Vtd-9ZRp;?ETkqxUtzV`Sa`hf5k4FR6e)A zmzbB@RBLi@u3Lx3mMGn}!%&!Fw_r-naI+>DB-I%r z)2+7c=1fVoZ#Mk)A5R7~9_apfcfv~Pq8swXudiNxye3>kY`TkG^$)$*uVsJzRdf_k z=44u;8L2kM^x-$Z=?jgQh1_wUrrOu%HX1?-DbPwKHR(|+{eb(XRPYm&->2Lh3lxzI&p!vgORN3B+S^^&8&B` zzj;?u*d{mkuIBmpKYIVZSR_5qGCgGQXu;)$SF;vsaIKniSVQW{>d=tLgR_72%t_Ag zahHqaa@**z`s$(>y@gs@|35@MTy1;dy{zF(7N3~;FRv_*nY#1;&EHQxDNoW_T3u37 z#Fe-GHcMU8yz48j^T^fRTE4TU`768onX~5>WJ+z)S)6Uzv#BvPa!OaFiSGBSo;%Wy zZ&~;3$A^n82foj&l1o0W>X~3v#(7vdElsq@OZN1p73M+TteI5;k7$_ftotl=&96QC z`g+5;DL)#W1yrVVRqp$G_IH=O_J>T2BBlmDn zjL-44e76f!P+ZiZ(Ge8l#M8x)^zC;KtFP0|s3eB_%~~96(Gs6@9{+hQYF{5>H~qPI zzRu4_i+=MlJV;+}`R|M1pT|)f^(H>`k`O-DVA!?Q>n7Ji|NBfLTOY7zq+PhH@`)*g zSHiW&=u2aB>goG(w@f-@2LD%yz5NG`{aWWM{luk9n-4ho$39gHA&^-nbti4 zpPW`^EuF=APIXr6QjPD0)78`3**v=pt8W}WEV-_w++J$m)c=;;=lELc?`a)t;&4#% zJM~C3@s36$+h^CqIf*MbH*0@)iPm5R9}LPTG;1Sa0O6Wqd3 z|1ad*mPHbaC3Y{LZ}s%Wm4^k@sXSxyUO zoibLl*(<~*^m>K5T7=B;bIY=>re7$2^g`T57?&TXbW!AX1XJ+I_E z5OvhjbxlyHmu+(qUum+1T@Z&YfBb5W%hP<^KFv&==G)@7Qp@|kd)exiiH(~)Za7!$ zSW)@M)BmQ_8qXC{a(m}(e*2CwBWeTREK3EaVC~dpXZm?dnNxF5-nev*^}5P5_r6Ub z0^VG0UwhMor?;F;zTWxC@$}QP)5~^Mpd&X?{qvY%}Gs9>zpUV!nN=2@gpIy1;{Y&Pzj8nE=GRe$8+9<@tbKB#l$e$Nq znZ>%Z<0>nh?rNke@3_ODY-rJSCtx>w&7Yr^>fMu+Ok?i$mS{WQS3PyAxJvCvX8u=i zhUM#7dz!vCbre-6YG@yw>f|-?Zo$#j?5ga(oL9Sc*(4sk%^~^vkE~nuxvV#qwv`>6 z%;DRw_tYwBdg!gWK5dzwPXEIrnl(R}4qTA@<@ha@yOHOON<+|-&d6j9qr?v8wVOkJ zX=nX3UBo(X{mdt_uXZha?{@0woNaGEdUF`2o4b_dro6G4H_zhkW%gr+57sCvc`&&I zin=Il|1Hg@u!J*&^ONP|x{j`+pEYOc7^(@)`}$NoCtP{9^}=XQXZ<4zYs`e*4&JEF zN~q*{J#~43WY{<9o?sV+P6M9@?irhtmpyD-``7y5Jmr)xm(4R)eNfH`6W$%`B%0RE z`gM=OqMY5GMOTemJw9-5(`RVm2xUIT_KB%2*DW;qRHR#+#ILV?t9N&P`qg&$vCw_z zQ+bBRCM2D`q5ZeYsa^8Xw2s;{JMM1S6(zWL0oO!_sm@!zi#&WTFY!s~VOGUcMv+j5 zO$~j@weL0fjf;v;y{&TXVg6j{92$CL%i{aFAA%jXo6VVTzc8A!&`V@#V%dxj!AZAN zAMy1Zdi6|>J8XN?S>CftmUwD&YcBsSK5VJ?x_`K;}XC{OaD z-8-M;rQTR0eE5Oq#e}7aQaX+g%ZxYe?8y-N<#=Ep!-l=aH=HIe$p{E)*;BM)T8wSn z!%wys@{)HN3D@m9`h?9ly6mr5ji3G39h;V&DAtqv-r@Jgtn10NSaqIzM!jD9g)HhA z7rbY+Zd7p;Nn5U3`~K&fzr3Z&Q@#c(WWH?IP3~#g-Ir#U9MQaW;sx%%FC_OKOj9j? z-njefi6^{=GYZaaidNtDow27m!8q~Xfk|82*8ejN2=lrtRTHquN_lnkr1Lv(t(|G6 z9QN&Q!FJOpp}qW_SHGSxP;;4@$W>Cl;q{ajqpzJacpTqr9$K>{qin?mIKp=kN)aMe&w5T;>#ik?!w5boT9mZ+usz%A#i+`}@U) zZ^ELT=?Z~~(_+t^LZVL zjfF9>C10XB96J*K`(AvocY&wJOF7niCzRj+<_T1FW8E+BSDIa@D^hwk{{JVznT**i zDi7J4x1Tz>xF=7yC)3HWBuaz-ADs z^kv#xwTJ45O&kNI51AfG_`q3ntKgrn|IH{T51++~Zi>HZ4?Sp|@{K{^yZ_Pqci8H_ zryZ65cQ^4(UEXFfF?QoL^=YU5ZOn`%nD@T_SnI;FiBIl{@v=aUKu+Zj;bnmrG%EBL zR0{~)t6TlFySq<*pM|J>wer7j%S9RL|K$7MP3y@#{d2m(I^mhOokNXJn>2J7^j=u| zeYu})hu{_Nx|&y8rGg$s-`v0B#k^pLd3*cj3)aTJmh||R^x${gf97*Pb)r?Wt}}pu Mr>mdKI;Vst0GB}5!vFvP literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/slime.png b/src/main/resources/assets/wizardry/textures/spells/slime.png new file mode 100644 index 0000000000000000000000000000000000000000..1ada6603acdbd9cade55d84163072b0330af81af GIT binary patch literal 1944 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/snare.png b/src/main/resources/assets/wizardry/textures/spells/snare.png new file mode 100644 index 0000000000000000000000000000000000000000..ce5a1f4aba983840b1c6d944ba8339711d2c3734 GIT binary patch literal 1816 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 K=d#Wzp$P!-)inkH literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/spark_bomb.png b/src/main/resources/assets/wizardry/textures/spells/spark_bomb.png new file mode 100644 index 0000000000000000000000000000000000000000..1ea4084ba99421b526fb3a60221f833b219eae21 GIT binary patch literal 2166 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 L`njxgN@xNA&jy^> literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/static_aura.png b/src/main/resources/assets/wizardry/textures/spells/static_aura.png new file mode 100644 index 0000000000000000000000000000000000000000..eea54a25e477703cf8be8b4e780cba75aeeea30c GIT binary patch literal 2177 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)266m>8J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JTknh%A3v`?_yx!;PZ5G42d{=bb5AA zY^dn*`t0|`@3NoWoB2{?`I#ki`L;Afw4893(`0p7A}TRKP-RBL!Y18>gX~gQIymGz zI1`k*nw~aicrbf41g(g;*U$0vqL{`OG2<;uFVB2=ruJ;@oZ@ev4)6TTX7|W1tZ07v z-|O{%zt^wV)%N$*{(t-_;~UApZwyPeo>F0G*sH9_FgI5&cI~0RvvtpDcKNhO@Xz*1 zUc;}nL*qy*qf)}!b_wRd1~WI;=m)p@43X|$+JnP&K;ESUK^yeCfp$D!ygqTfw1nDsY>hO7)4x9K8w1sVQoW4 z(NWERCdb}R-}QHPSLlgly#0G0n@?gsc6jB2q=P?hgczTER#qg-{qrXO`n03r{?D(< z{`NH4e(}mZ&uq1TZig#pb8|IeI_td!WP71ri}TSv5IY?rDDNvbNq9H776r z`TRBZ%bE8MdsOOge$m^%W7G8S-+Deg-hHk3^4`}k-^F!YztT28)A^5zgnT<=^1%p^ zh~Gsf(he~@J6YAmK2DmE(w6dBrqA|cO5K)UMtVPP8C8j$Nk6>W+Vb-b*AOkyytv;i z6T3MMO*p{0e145i?enz<(l$L<9`LyNW8lUoQBjX&tdgaVG59d|Gky%%c*8|Xe{yoZ z-4p-*++*HmAMY0XKX~UJugs&&wNz-U!J~uEw_mQlBp8t$`Tb3F&C~8!k42nYE3dFM zbl)uHikRTftRQwINl0@~NuNuwbez@cPr-c;XO^??%)k3M=IdAC9c5=tXRK)ZXguNV zgZRVIk+na!TWncA`}qIAdOtEh1PQQx%pdMU{NwbN4sp z{I-d^G4c7c)Bec`@0GUY)Jlg;d}QZi(Z;i{x8&Q$gZC8I{eQO7=2y(L-||upe@vvV zILfZ*{@k^6;fa}21`2G3VjJxqse76{t*E-~E>nDiNvy1{ujJD6a{inr6M6j;*|sTu z6SxYYY{&_Oz zu)^)eB}Kwl`k6I(-Zj?VKCx_aOzF3YIrnY5I_4IHxja(xef;-~mId=XP>j5XFcy`KTGnA4Mw(=3k5b`+&snSP{H|NYl)vPn46+ROE>!gXU%JJW#N)YkR%+q_;Ds z&bju}V_mlfkL8yIB8vn!ZnSoJ+#&orM0pNNf=Zdj#2@U*ON9~zE)*A7hfUcK_U!uW zxaZZ^|225)?VRGY(=2i)$K1Q!mY=xY6<6)KZ+~JI_r9KkiGe%;S|SYQx<5^Ld;IlR z@fAd5f3P`SUNv2C!h`d(@3|k=Ixb&oasB=-&Xc7IKkrH;2h4uZbT3Y(SfT>WIBboTvM(ML1UrglYEj9OcXUBEC+hEpdy&?)d*a5ce+XyGXk1<)feOaYt6%S~{a7TE{MVLW=RyJ4xrP zvo-hE{}7#5lgTY~RkN3`akaAE9D&7xb~{-YSjaRn^D3?gJk1{@;4N~cqM&(keZrK` z+T|aQ9b?Tn{@n2Q{m!*N?j-L_eJdPObWEtp%X<6WpE6P*0^-O1mJ7Ox#C-8&V9C`G zlX-Qh!fcJmN~XZQhoY5#e-M(aEB@YoX7>J$`SG=yb7kM&`FukAOtx>Z+^-3{ujM6{ z{Fl@E$+*RiE$~c(qTQrkpYM#3m03~8k3SLrWz5?vwZ*Wj-`!@;vPU0k{`hd;{8qVS zQ*lJ?#hG_1?>qCn|JmSGIAeuf+v?thiM)#xu8Hzp7I@gJ9mKHtJ?qh$c{$$PO1CWZ zWmYL#xH`9Yzsd-3w3Tn-T3XPvz~G2}e(mI65fig2TUJCdi8pdfH5CglGdp(Fw*!@vh;(UHj45QwPs*ze(EBV+t1~)E;sB$nu_fqG)|IgN4=n z=4a{fCF&XTccuI(v*~-WIqI>)o|*DB*Iw5zWk1CCm*LG$1_lNOPgg&ebxsLQ0JtIg A>i_@% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/summon_blaze.png b/src/main/resources/assets/wizardry/textures/spells/summon_blaze.png new file mode 100644 index 0000000000000000000000000000000000000000..aa657ab9e01192532642c693e956305b27f4cd3a GIT binary patch literal 1873 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)266m>8J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JTkmGrqgfQE@EI{yXWcR7!q;#=yd;_ zm~hc!_0R8^&--{o?sliFc>4|uPLs@A9SRq+;| zgy*1uvB-rVa!GEU3DHdF`K6T(tz5OZ*Jz4F{OSrGimA3mOBO8+OPuFfLjtmE>4S4Bl#!9krvUzd|rP^hQq(aku4WyTL9EGMl9`StUy z{c9G{KKrm+OMXZ-etg(suE&wY=%gTMAn&+hZ5m&r9N z&KyaYDafA8X%p8rzlT+=im93N&K}(_`V!~AmA(-5I8%_cB9~#$pW}DUm7YFr=(dllE3p6e)H&AG-zVi7{ z!0eAlBtnzVNFLS;C~vA2xYhai;g;6gpRZG_)hn3Jm;b)CXXDm&jL>9ZCruevK+3gQ5wD&BLKjzM5b2Zag$mZmE zo^LjtbE<{y+->v^oV>?$IqsxN)LNxjkqBkQFDou^=M*1WA$7QJW@6*{ZwGGM9(tqk zrtVh8Hm;t(JNdtNHfK~zz5cCa^mQ&rjlF^B^L3RGd=n%S7I>92`L(F{@0ldbH}yfg z^0Aq0GBX-x^SPbf7;QA8;mse3$yY`GUa8&i{pH#R;*V-S$2+N?kg6!>4ha-waSrux znZbJ~#Mkl~|LM{Qm!Aae=IfPTCN+puVuY=Ku5oPSENFd zuxr!t&P6OPt@%@!Z>nrLr`=rqz>j4Glkw()_w(Luvgi0WHNyA$^j0_b4~e!OFPAy2 z4P!oF$*wemW2T1wI*}QfmbacNoqX5eYu6|{uj!w5?7_DTcYd+&32zm*<}|XBjb7z9^Ft2Q3$s-} z{3@4P<{0^cqnBakQ5d82@RPtH*$0y&pvH&|KXj#k3YOrKPc}IS5>+C&F%#2 z085s1eeLPfT4w7me7Dd!Wb?FZoSP(TCNs4)XfPhW;vw=&_~GxPVtb6+?JK#i@7opn zZGF?+w$+zE{GL{{Q}2v<>nic6Whsj)Som9ZZ10LF*AlR9c^0PeY6}1K2Vw?)FD|kE z5%_?A!w#W?`b!UO6uVm|yl&em^hm=6;{|IlR`PKV=-3}8CczciinV7Mk z%*&_CpI~eW>&KCj$cmgQu&X%Q~loCIIa}J`(@{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/summon_ice_giant.png b/src/main/resources/assets/wizardry/textures/spells/summon_ice_giant.png new file mode 100644 index 0000000000000000000000000000000000000000..e8ef025bcda3dfbc00d99d13fcf124078ae22d7b GIT binary patch literal 2080 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}R2Ud|k|&*K zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifuuBLCOLJ|s^kHCNU+d}O7!q;#==9V5 zGVZd+?PLGWn>p|Lxjy;q_f>N(*e0ErkT6kzseMkdv!kL-i^HP>-cC+3mI9si3_Dx| zjyMZ8E%0!0nd8LdB_piLA^oW!Y5nz^U-Qz^%jE7F|6Q@}(FWVsk^SeFEeYDbYxl43 zZ}V&S-(O|6?_*^A=lUG618)DnB}c51HfLbSdFRE@XQngl6`TGHe!)_!jKriFVr{v~ zIntMnHhPQ7oOg{-<7hlp{K>@mm|@vkH!G=ymqjG|R$R-rX6S7DytxNnR9E<}SUWGJpq4xFcEr4X;gEu6hV?=ZLbW3LdKFoAp7DGnF;nG% zMa9}F2XE&q=d^1`37gE`bLFyx*T)~PelZ^V&M1=`VY7R0*TWk(&a!SvPPXFvI#u+M z#v$IUDYJaFxU2WZtp0fC`u-*+yZ>MEJyQCv&6=y7oe(a0efElqCK-2yg|~79`PgkX zmo^>eUw@W4VwLoTtp+*ll5HXW^W9F(Il45t#LR4^OxESN$b}d4KEIhR=gcV2WcK0p z`r4TcKc3m23tV??$ERca3&h1de$}>Id!f^+!+P3H;@BPz#(!6ATN7_8u*?uU-0RzS zuik#|T)E|PKSY9_+5G&Q|2g5~9!4DorVa+qKYxt*Kd?U#Z)W^7Nhw^a#i37`Co$

    2!Ebbj&I_mhUYmq-rWWMoYXgjb$ z*5^LE^PMKf?DMZ5$MvgBo?}xz%_O|Ti*>uuh1n{5n7(v7@rxfX@6wcD;+(*I==+9K zsebp$+qTF5RgavM$i}$yj6n|j!(E?wBn}-Zh-rD9SYa1!ZJTrbY2VYw9LJw7|32ps z!zotg_2TYb>(6mJF!-rHc%1$&tvFfw^!Jr(*Cb5SzVVeUY-^X|nM#JRojosiaNKs| z5H{`f{A*OJnQ5N2hbxBV9;?^U1I5N=vl!wT^u8;-i?TZN)NlUN$?6$$(TBd(?D1-~ z@!V)5zdCB}e5S-%7QJkF#f;V*7q+^GcBCwAy6>zobPOK4zW#7wQ`rxw2pAFt5GnW#}2)wozrnH#uqX zrr_2G@ASCVizd8dJjeWhX4b({i;Y!t5|tA!tTEhC)@#xm_^?3kfQ2W=E45{h8-ix6 zb5|=?D?Fp&x4>g}?Xj*(^RzcJ{H{+uBzno@<~`X9vC--`UmEP$ecQ|OGKXg}>#j$xW2-Q}Xvz9etoB<}TuB4h25X*|?@A^nc6bEoEEQR?Y)}3r zE&auQhufvM3Mp+H-bSk|ymmxBZ!%ANhnMK?u;o|me9ZbXrv3TLD9&{&_`zc1hBuPD zSGuyjyh>&*NNwvH&%WK+J^g$53Gw;= zwG)>++sI7lcP^Qva6I`$af#k@$sZ|o6S==ByJUw4R`xxt(pdaqyMagSbnXAO+>a-= ze`o(~yp37nUCGarKd(!cRafhsFq(8X_KAi|uQJb0^&{`s?yKh(WV-7;{lsy>CzdIk zR`V7-mJsbd!B)G-uU)yqo&e?BfYD7 zMPKi%vfZSSv}tqi%Na{DnIgLun%=jqocZY{MIG z6M5Qi%=0&qFnASauq92%?Z&?2ll^UdpYQ#isjq)|=NGw3J_@gMv3<$Xohi?Xen08J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JThX8g0q{?^D;27zxH%-42d{=bh>ws zjJxFV`p~O)FMq!C_GbI_-I3PW)}5b~jveH*@bd`paBz9T@uQ_hUq*n7y+uhuP-a4r zlVyQ}SkM&qM@<5ZEkaXRR9WU|YDR7f>qZ1GT2V5mH7d~3n4`Jzo}YmYrH*EqsENB_>V!rYx(6&W5Jm~-~@aZxu8 z6E?J&>5d(ITX=G@wC5h_z>lOx*4bUDpiV`EJdYi5E9`8@Z?G z&>@Zs45z$gUL4-IW*>K!bBoUdHr(jsb9SP17da^`o8~<>%XYC3h{q!xsUf>%-MQjs?q+R;RiPR*EtZk+~&T_%@%?Q>Dw2 zA!^=Q@d+u{<34H5=2knMBl7WWyL^h$+YhIYnmuq(ewM8)wDr5(rQQ9D&&_pQ@vMNu z>;cylryG37wkbYMiV=Ujqr->olH{5{9Pd^f|HjOpyj}Xu$4_t0bG`|g*JZY6&y8mv zN*EiK`<*G?{C1+|^bJL*`NuRb= z7syDj-!ZvH?`-Ym$rXK%X09&f^B2DnUhwl_t0==hyO~d)yb{@U-PL<%oNaWQ!wQv` z8**H{@7-t+fj=%Y(Yfya+?Tr0oe%d})lhUP`1m4%5nPi*NvlUBgB z*ynC-L(Ik#5pRt5<#rukZqpL*=A_l1q}By*V0UDRgj#xw zr^|_6EuSRiDNZ-c!mOGnpL_V^Q_5b$OD;>ggJtI2Ja@S|J(4F$EjY{j$L8&R9~`&# zicH!bHv7d>p{vvDU0;8yED>QyyUUWjm_sEztH&B_v;2?c>9@)O~?si$LRw$CR?G~qWFWb!| z!PA=p{kjg_(G}VDULluh)Al<@55DAlcVf3l&dDJ2CqG-S3H)K-?o*JV(rehZOeEqg zS9Z95V0_eq>uWBrS(CIS&fd~oU6F17%@mc{&X!{DR=6JvyHk6A@f-QG7rK*q52qzFSmry;XO`Fbem;(BV4@>*18|G~&hJJ#w6Yqmf4KD^C-bGfvu_l8TnI|Ei4 zX(x4ACH%DSz7jT_vsPZX?ME-0gl&oSErA4{AkQhAPTZ?fH%)w)=JxYkL|0d%__W*3 z9~S>k+tidPo=h2%?-EvqyDyNX36l0U{H4`Db&{&s_HS;tFMXr*Lxa_1*6Rh5{1m!6;}_H)Rb&yyvw)f`qB94W{nmNFPDto139s*N_`janq}wznfc~U-mRtC zKicIOA57dI&+_1C?PZ(tZAXq4FQ57Ud+MxSt;Fr^oXjORoWD%cY?iBA$`shpq11Ab zW9`Jh1^n#{28Aszzg;Mk4*k%vr*PV-)NSpyeEk+ShTG@H&);$2>d*e2W#2@4uZlLs zi6`}TI=M(FmG*EP{&(v42Mf0&hL`oLDvaz*MF--f9T?Byku%cnR> z_i|Rb)EVF0eKAFC*@oxqKO8z|YjVEc|mB8vq{$0uiLV1 z8-HKpdsQ=`;6=sVGR{9QwDqn}i+*!snsiyh!ZeGb6O0dD>{fJhzoPy0$-WgLNf(yz zRPAfL;OKqrd_kg5P?q_TnuOn5pI%dAKeE7DPUF{>V-6i(Pm0g~_CtT$oG(ulvtv&) QFfcH9y85}Sb4q9e07fPIljX+klo10 zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||VCCQwmk+(T=?Vh_r@g0(V@Sl|qtm@} zVy;&nuYbNT{n@?B0vA5dK>tfieDDu|`n%tAbTl*hK6*%nMaCbmcEu))Vz+oy|9;Kick<1l&^-Nn%LBC=pHA5Ec+T%T^DphJo}6`b z(S6>PS8OjObfj8OS*>bz?Y2nH?8F%xb}s*XCD8Ne)(`BQx87er!XNZ1wEgYdhN`tk z{=_s-N)9gczT$rB&aeIEo>PupHde39FBSI={&QYB|HEYY{}ZCFCMRt=_2*FV8r^lt z8BH&jt3|}$T9WdLgL9eMhLXY?Ee!A1?~+hje)W~Hwe6v_%g+xjz5HU8??Jss*=qN$ z34QmHE8KrN`u(2MzL#A%c{!(e>$Of=5VrC{Zr&pCE*>jJ)9Z_F`)??5T)JSg;?C~} zo>e5kw|T6||6e!JB4(_Yb{{jPR5l;6Hr4B>Ow z8sYR!<=-hi*2|Ah91+}fZ-R|iAnV59)@!Z|s8M`_!`IsDbxNP!n?u8lu&n(aE39~4!WUSxWx=h6N zcFL<2-aAtSzZB*8CS*M_IFNDlfc6UssT*y5xi50;?;O;gUa)nF`SjZs^Y@>4ZU2Yy z*?IB8y<9WQl-?yDvD5#1@N~(dIfq_;e)6`VYN^lB!WlE?AGlEZ=PpO|Weda5#CIWY z4ICyp?M*5yI^`_Rbo;^vp56spkGKDmJ=Q<>P*L`pFQVyjJNX*YUoLU$4FC7%e8u~F z>@u@=pV+vw`_GoUhf29(cGU6JpH1H&ZfF+w@MU)}M?&sd`Gz+VmEU{% z#vhIQUP1rttomL@_~_1Av~}0nUwe70>KgQpBr=>gRh;^QY1_40w%vm1`u@hHuT-j| z6*kY1HlL^7>vT!u!L6_2FUx2B`Eo!1KtM?x3HjY1bzoOxBR7vn$pY0qQXI@$U^W?hj zi~r*F{9~Lhdxy9k&y<<{V2AFFtlSM{^}SEoXZ!fpEMYmis54nAV%LEyB`E^R#hjJr zrvG~-TK2bL%}?ni+823+MW4M{bJtzox_6@bf^3&&x${-rd(2~&O^}lCoA_!Y+r*xZ z-_9vUM~p;;dBtDIvQ+HY<9oMQQ$otsJAFyUWPYbbd-?8qu9zXYKjT|vT2J8W!#o4(pb^TYur!yGwFMa>{=57s~yiC8ispEQHZMXQO=__Vf&UQT4Cx2l@n*W^IV{YZ#i%VJY^vmNJ zX~pdJ9hu*S)6(pV1Qc0<8dLsrwkhshc*1w?#pKH~9&c7)iQmuXxWE0PR-)|82e-Q8 z6aKv_uKD`@UsFl-%y+-qW2A2?$+4BluQPtpy2R6M{cTmQ!*Ku!>xx`asQuTL&-|qeI1&xDV|Jkdm>{JSVmF)AQ zLucymrz`rVz4)aVbh>iK4!7g)KhAw$C;$IC6n#1qn0G%?d1}}5^)+V#xCGjq zm#M8TX=XWZ__4XgawOB<=<{!rFU#qX(-TOad)ef?f9{ZkcQcJ0$uA_6_q4UX{dx^n#V8{OQEo9->Vs8Rg4 zE2&ibLB(O)H4d9s&#;}y@ZsL1&UKvMst!(0yn3bdkHc|o%aoZ1xSX3BPjY`Y)?m54 zd-sw^uSrW>JiX?qTq!KnHhb>J$2kA$+6N6xk3PQrVR%tpwBNC(f8UQKkGC67F63`e TnPAPpz`)??>gTe~DWM4fpSZk` literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/summon_lightning_wraith.png b/src/main/resources/assets/wizardry/textures/spells/summon_lightning_wraith.png new file mode 100644 index 0000000000000000000000000000000000000000..1464dba61532da8540dd3a87a01d073a51f365ab GIT binary patch literal 2127 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)266m>8J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JThWzJll_$3NtXU-|=*D42d{=bb5Br zl&g}*>(5u}7vG&5IZakfYE4&re|Tp`8MFH?uEi`2w{FXrz29cQaZ92{V+&_P z?+QZ|rvgD0mT$dIN_xjO2F6Lgohl%b;IT~lMx8>t#Qdq^){jNj3(dHeu=%O2G;;>C zhIN1fi~CIpM_ru4F<`B7?PDa}euF5l>b1iErN~9X{u1 zrN3zv%at2*LX<B(2ThBJU*=9Y%>a)&<#aq=_ZhV^8+^CSG-1sLc@d(q?2|lI| zR)5$XA#q#rW(Av8od3e_7RSEds9w_k&WUq*p_TM?ormj|Z`=H>Z}tfl*>^FYwT1e) z4=kH&m%XoS5>sQJpmGs8qm~YaeOrJD1{q^-Tp6uk_u&hq- zc<1KtAD;iIdC7EXBS&UzVpi=G^|&AG%f4IO6u!H_wr8e8ExFF?%8 z^@359=VQ@;tA7^j94R|kbg(aJj)n!Nk4~$+=VNuX#jlNCM93cPdiGM3dqw^{r`jVA zkL>$?(r3PF+Akfps=m)>w5@l1mJUx=D%=no@JfVb3hOC19rh{0F0Wk_gV;}s`0bK3 z(!CLUYl4sV>UCM^hu9ld`xx9?Xei z3=DHPP$Xc@RMs@9@Z;;*A7}4Bz@Hy|>N5YD2Tk1PlK;+=n^*Z1+Y@KFM!8pU;df@iDg9_-(7yhu8Uk&1BuF;# zuHVEt`K@EP*8-lNl}x5lt&Ziv3puAgZ4h=;65O)!!n|i~pO=05wd&`R)EO_EkH5GT z%567g*1=u5?+c$QM^`@l>px>>nRMOt=P&ljeb`%2cY=jwic@6R)Rsb-Hz{1&cROyF zEem<}NxkgDH}|_+rtDtv+B$@}?&v1blBH3aLI>q_KDF1sdwlhMOxJwd#&uHy)aHa4 zF*e5Nu{Wf$*52Bdd?t7P@%i$<^d>ILywRz0JAB*bmq)`_zP1Wrw!2ZLD86m}`R48M zt*3mPRWIAzue7{>`-hR$_4W{(Pd{r`Z1YKQ;%SYUx63ndiqMuHH6K2vZ}IW__;-E0 zOSbcz#zvX1$G=@~*six{mZ-Ph<7?0PH$9Cm{_$Yp>xlo)6xq0%-`w0Q9{S?=k5rCj zyvflEZMO+8Zo1hUtoBZA;f3>Cv(1aYf0fOtc&QsS|J~}dm9K54>F?~BJ>RxL^U02f z8{b9*rG*~P$*caMU+~EI%m)QAH5RjE8G~(HE(?1dk0h|PZEaVcAa?fZ^DQ5aO*^|a zFaGAqgc>95?Qf1h`F-K<-5Eh*`(vJ%OMh2rjnnwHu%_QhkNrjAgU7xSdHP8vJH);% z;rV{AQaC#N{+WLHiX~>B+9cOh|1}7oSI*Ya?#gQZFu^ruNsP<$-v)#U zS@$m7lx0dl>|&XXGs?e3))XJyd1w2sZHIZywq2ZjBB1NYkKYF$?HEtmu~*tqbk_Ps4ganguDs#_ zQx&^z#$8BtspgQ9j0{s>#Uy%#U8+}AZduT>2UB0}_@;HFbJNGOe`Vfj8(g`5_Ptr& zv%>hr?4N%ecGk#sm@crs>FIRA{X%YXP15og?Yww0>XTTfaIgu_a$4*=bCLOpUE%lA zZa2@JW4Ufk6mky{fko)1^lh+*1b;t-B1!IWvrb2 zsZaUig~eRCH&=wPo!qi8iSvTpE{lefUms8R>JU5o(tD|Zp~hmvpK@mcVewsMKUk7E?B8ne$wH%*D;s7`D*3iXi0RbDvAr literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/summon_phoenix.png b/src/main/resources/assets/wizardry/textures/spells/summon_phoenix.png new file mode 100644 index 0000000000000000000000000000000000000000..d6d7a5c95dee42a22c7d31197b36fcca119de951 GIT binary patch literal 2295 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 gzaH@~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/summon_shadow_wraith.png b/src/main/resources/assets/wizardry/textures/spells/summon_shadow_wraith.png new file mode 100644 index 0000000000000000000000000000000000000000..1c6313d150863e9c0f240e1cdfdbae44ab170462 GIT binary patch literal 2289 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 WyExC|yzC4N3=E#GelF{r5}E*70p&>m literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/summon_skeleton_legion.png b/src/main/resources/assets/wizardry/textures/spells/summon_skeleton_legion.png new file mode 100644 index 0000000000000000000000000000000000000000..7e10c45f8d35e755aab4a026ad422bbc5092e9e2 GIT binary patch literal 2080 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE({C|>ljX+klo10 zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||VCCTB5&jxzn##byzSh&lF(l&f)ae)V zWx_>|)jz*uZEP)FeZ4RxXt`#m@+*ObD>5^MqXIc{y{6hIEc6iNIKuo?mp`P@e!+hy z<F;c9ddh{jyT-mdJ+a{9?l^RS$&z=GlyR`}pMPihmQJbpfBNRMF8`mWX6O+g3 z^*U}(?{h7Peb0OLgvsH@AD?}ARk)}_Bl6yXrJ5^?R|NOfefQk=^KibfjzF@*T!F<8 zbzBQqXiABu^YwbIlU(U-usfLX`-OQ=e%`LFc)I9O;gVU8R!&}}>BW4}V_Mn_*Hsap z9+>YtayZ`l(3>|pk<$u4Y-ImnZM1Ih-VT?8EJ~sWnUtJ*CWf?Xg+z$li&$0h$HA?< zHsE~2%!R8`Qd0C>&ldkz{+^t6L}KT+W4@;>9;|#ncftMlo72zBO;VAZtK=!fCu4Eo z++1tTuBPz1kJ3`JHh#X47xKDs@6TtU%a)Z1gjq+VF4pR4Gf-3v+B_b&t*ETf;`=17CCP! ze5BFEI5RC}iO#;VnU9b6Z_dAOCnhFlQTxl}oMl|?*U)9lm!JGRCwhBc;p1bxYU=8l z+i!PpD6;s?w>x|25Yz8(Zy*2o__*ZX&K`M-nhzD81+TK&q$bVkGPrreZ4qaum6T`m z9rK+(kA?cpvpM=!GaY9Z%6%UPLz#wTC?%bpp$-0x!E_Q@uJ{u0{N1h|7lYO6w_G~JIA#|M>IOv~4Zd%6@XQ$={e3@_6j}IW zt&V(seSPMP83|cgU01J$ZqiwN`DMYsKb7+;pGl^rrTuv8U)Ot`XN`mAiY@$7g^r4D zECu}cp3jSaf3W>^uti~q z=Px&MEWiA+;Po|KK6yKvus=Je|7)4aEPL^Q8Uy23&eWHMamUnUp6_@*uliUY|3-d} ziw9iZonc5@A?{=LBK)e@p_Qw;!dAQXOq@DZG^uAxlmU;J9k=sdw175tR_*q zB1k~CQ&e`_0u8QTf90MokeOY;ur6k&QCUro+mx}r6?N!LhS_Wx>$0A!S3|4z%H6yEP+D5LMc{`|HoHRd z@ztyI4|?b(2<$ADW@EZ%Cd%LAYBBkw*&Vgjy~6tI{*~#Rp4jo#S&NTlksHs`N3Gih z8qeFB{O@cj{&?tqX6ocEpTy)AZojbbc6@qO-E;M0`~U5>U%aaHym9}sJe4W6Yjb#o z7f)&k>OSux`~KfoqqdJf-S<0ezy0*S_`O9F&1RfYyYcRJ#mR!C4))Vi-W}rlyGWrr zqc3m!Y5Q}3dD|bDG8#6ynRW59nK>L$JS@iZv{XUhXrjp$ZCKgrzY{mO#A%r^?M_O6H6SID0K;POxdU+q`B7VNWQ2_|J#-SrI@|6 zw0xMJ$t-#>SN){)k_r_O;9azcZH;*6st(Z=E~^}$l9+&>}g+F%A>fe)hw8&1r+;P7xL{*xt^4^1Qw{qvCaR?gB zI=3+}G$OX3$773!%B6m0FE6dE)<28aFW0#j@p!Yf`Zgwssw3(0`3xUEe^x!nq@68W zk~=jd_|q20^{;}D3Z*k16c9YcF|{FAt=C0s^=UZ{7VgEH^zTL7ek7RsqOZNf?yPKn z;j!}SsGF}Q*q@c8J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JTkmun#&6JPhntSclUI042d{=bh>ws zYN+J#`ump4U)lY(+m)X2l8>1=(V=&8gW(aD4(_uqkKBZresr|)%u?VEUleGTb>%^{ z(BnhyJ%Y}Q)bdokZt(C(J0$iviuL)NKQp)P?z`&O`(9tOJbrX#b#>LQn~yxTLbt!V z_VfS#|KI2S|LNs-Kl;-j`F6$~cPgJ-t}#pLXK=_iXHHm}8IjAezglumamD-R>`}}L zQOz7mi9$1DtNWSueAjp{C^#iZ#q*H6zu5POH6OOAWlR6HWnz%Gko)*WyXku!-@7^7 z2fP|REZkW)NY=5<5msauXPk5RdGVDj(|NYj7fgBda5wjFk?_skQBC?d!ABOw{L*ddR}q4n-31X{Q6Vnxmd(AZV&!4j@4`k10?|j4{*IvH& zQsayulUck0S@SPFi(;DO{+8R7rTPUuB7EJc8GhM#G}=B@vO4P%AP!vz_YGhTdf$*|2fR`;nPnBJ7t!F)1AUIyhLMH zF47VW+1n}7t;l*z;aJPm5(&nWOU2g;W)~i|n>tnWRIl21+b^8=im%5q*c7zSo4lj! z&bNQokug?Isijj->25z%GKqb;K;UNvexVbK!;dZSX%RWCu~u`LaGph-^2@1a=WE|v z7qiOkaF+Laz}|0j##a8PLHWI6b5@yMF`StJQif82RrB-DtUU9t$V*0UeKd@WT`|k3^`93mXZzx|*z$+lrDPkwmD9Svuqpd&>~IN;xOD5m+}rB^O<5eKaOExY zEwEWS(TTAkGfhzN+P3X0r+ew>>IC#8i+QPDvzB$6%z4hzr6o;Q=k%+Is$%|g5-z-- z_^xc`yDfo>7rbj!@~Ns7aFm|AzP|aA)|!ViJs>)QjnoJ0b( zL^7^vNhEhDoxOBQtF@JN%C!!ms=t98uRbWX#9dlkm%=&qeT~wgt4*C8^>zP#?o^st zZ1H@3ep2@4D?~&0WY7*mM3;t>a4D4|^60 z2-xgBIN{$pzT0cVZpf}>Zv5>(SLyWkN?oTk*}VrlE~a=b4OtMTw|VdE3orRs-Y*g^ zENy)G&1|>$^$9O68h$(fVmv9$d66x2)dJ;X+N{d&DaPb^Zp7d|R`+wie=ls6?`OCFy8ZrBuGUa#=YU&7VKd(z&|0+x*@SbIs!VD{gT;xaz@Z*$7{QMHf?UU=q?wVx$GeKJwL`h^P691wZ3>^boY9k z>!TSV3vzYWJ~sdO;(Ps(v*v3)J#CjelG-=_&qw~4tnD}7l}LQ8<}o*y^a;*c$Z}aE z|E-MzYvU0{?J%xA{63+KbCRoG>RynV-}WyctMuIdifNxtaY;Wv|2g6{*UJi@-KDMn z3Of3evrb=scwKM8n>PncT*IYPtfdojGp^={U9szFIM3~}N#y?fbJ7BWj>|O5j1Kbt z>amh_Yi4wwJ@ISRj>wj4n`)OHbun2Yyk~35U9+SlkIMpczPJBAaQFD~Iknn+whzzz zHFD(X5ba31bB!&dH#Wa9sOO`>$?w(AU#N0gxYvA%{gGp(-m1QS{e-slb!)122&#HI ztqtSWN&lLVTX6Iv$3?CW9oHAWfB#+Zy~m`u9sU*ice55g5~`c+7ORl0P0=saf*^kz^KDC^G ya^JR#_wTcu-`AJkb8n@ga?-lJAN~6OGfrS#>9f#gYbXN)1B0ilpUXO@geCwUU8u+a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/summon_spirit_horse.png b/src/main/resources/assets/wizardry/textures/spells/summon_spirit_horse.png new file mode 100644 index 0000000000000000000000000000000000000000..4517129751691a0f08f405ad652c627c0fe30aef GIT binary patch literal 2211 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 Q1_lNOPgg&ebxsLQ0520I?*IS* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/summon_storm_elemental.png b/src/main/resources/assets/wizardry/textures/spells/summon_storm_elemental.png new file mode 100644 index 0000000000000000000000000000000000000000..2e758158a982c3be2316a7bb4c0273d9c4b458fa GIT binary patch literal 2452 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}&M-I`I~Zp( zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KnK-ztOfQ(WwJF%BmVkCcN2;>Op zC~@dGIEgr_bWOjnwygQ>E1FJIiNF6rNQ|7ZR3 zn)wxPnk5hazi4ux>h;<58Csp@3=COkB^t6KjYEb0m{y9vU7H&qrr@ACfs4iBsnODt zo@H^nH81c7l{+VUfJi zW5qc-ej9tDXEG=j?zwYM;x_A2L9bvLS@ztI-A`9uf4X0jC0Lb_x%GmWN2}nZYkqTU z+xd-e+&J`!Yeye<)Z?_z5{jCAy%%!63NpQ^5xjn_=e*pLPcw@b5OpWwn7C?KRNDKwLDW^!>d`|-e*vuuU6vXbpCH*IpSC(e*oohJ3RG9u_Q zM^cKwWC`|}>zn)njGSIfX)Zr|Idl8X*yz?rx?CqT)H1ggxVvw7!}K@X+vB?G71u=* zxfTY!P;opaSaji#hHH?FvaWwpm#Wh7hd=(+-Z7o^`1<)ja#!CZPGVW8yg~cU-*1n< z{I(4fU!Sz-!8d^$UK6}L@4RfBoKPvrHdANw_j|{`@B3ouX4`*%Z^fkdwg20f)b(4m zo+#V#z4rY>Y5v+N=L`}ui`!3gcOUs{H%%fbx+zKTaD`#&&pVb$$pT)=K2_EZd3kcW zs?GcS_rIU)_xAWUZ<~tqwtpUb_3odu&td;ICn1)O1MJroC-V8%JvzLj@95m#J@*BFGH?4DCEqU?XwG)2t zoUK&@X65YkkxI*BpWv0;a`e~X8)G6&#qoC$muP5m2sLWUD`dm zLq+9Q9OG%nBbtFshZ?t7^v2Iz9I-Yj((q`H!q;}5+ofgGrW-W!Kiii5@maTz z+|0!W=BJOH;a3olDfx^|T;ahi2f@mFlf?WQu} zhrhQo=jiJ`o_cIzt3a@fqJ3b>mKUE^CSSHG&1$@FQ$J04+3{01KWivUtPU&O;^yTl z!MfrS$JFh2&zJA}!|K&)6TXYlKlaX(wNH8G&!3;L`0iu&daHw-XGL4Cm0NHc>uvNn zQEhf(R-(X%7at|}{XUib;I~bH?8E!&et{P+=!0w$N7uRdVW0W4$r(^e&Pt{@ppD!JA#{@ot(|Miaotxugpy+LF@2@-NGNg z%%86utR;Na{AFCU8*lQgxr!EISCfw`&Q32ZmA!h)^=kHvrKcl$W8IFs?@W4H@o1^* zydC9jyVthdkJ;(9t3-0=-nPu^iNC~Huj%PFYzvU&fB5v`QKQ7=uIvS$7F(P;_D=Wm ztF0gJ2JZXz(!Xef)yc5@1I5qvK7Hx0@5<3j_MX3XYp%?8r^xW1*SMemJdrZ7`m~;U z{9DB)2I1q|+aG+rd~!*LMcYA!>!%lPIok29W9hQ0`|J@GUzz$gRsLByU$7^n;>X|b zhJiYhrR@)RtaJ*K{$=cbamk)PkL)=Q3-p~^FxAD)xg(k786U%=U7t-HCn!x_U}br5 z;!bCmTZxOMH{9``vFEvS&fGe&tV*kaG^|HBo2 zZqD9$*7p`MWHM!*`f^9d?^<&0-eX73@aWt9wz*X1`CFDL^u9|B=zkf)fxL)7sT9cpM3gqt_jCd zmuNomc)Oj`|HuAcF8F1Jbm*RfH16Gxn+12=S`;I3m`mECwwdR;VcfjBx|ZPU(=5#F zPyf7}ZV=euA$&nA?yIDUUq5j$(cTJPx{zimB|TxKav;#kBW%(t`PoBbB1 z`M+*yDSa_abTE-=n#9A-%(j>B@U!o*Qc@#BU1 z+Q8YbCugo(8@Q(DFnGH9xvX27;9U literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/summon_wither_skeleton.png b/src/main/resources/assets/wizardry/textures/spells/summon_wither_skeleton.png new file mode 100644 index 0000000000000000000000000000000000000000..9453859c866e6466c07a46343e7420ead731e3b3 GIT binary patch literal 2147 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 N@O1TaS?83{1OOa}x%2=4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/telekinesis.png b/src/main/resources/assets/wizardry/textures/spells/telekinesis.png new file mode 100644 index 0000000000000000000000000000000000000000..ff6d24623230d676a48b51260a550d521928416a GIT binary patch literal 1844 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/thunderbolt.png b/src/main/resources/assets/wizardry/textures/spells/thunderbolt.png new file mode 100644 index 0000000000000000000000000000000000000000..c063eb6679df8ba36fd7ff120a3c7ef24022f59c GIT binary patch literal 1565 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}7#J9g)oVU8 zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KSXo64*f`T{Y#A6>S9!WPhD01bI{j?F z%u&f>^2ncQe%RJ!+^9~_R^&^eU z9o|bkCI&2uso_?d(BM+k;m9&m;-~WNjeGBH+-$n`1x4fF~&Wo zIiqCH&6Q``P`K@G!XB&Ay~~dui+!Bh!lKyie7t&UxsyrH)NIjg(`|>&DKX^N&j|Zs zzHULpoIOwGtj^Hm=eG9dWk{P6;LLsR;Y8ntpwQpa^qT9}mQ3+j8ffM4YQqdK<*8~pr56I*%k8Aj8U@^aC~}s;vAR(0M@z`j`c{>w zh+|8tuf}BtFgUfdtmWHj`Xth8({5w!!@urcb)2$b)m|wMMHZ*lR!7Z`fy>?YraV0G zx91z1###XFQ}1cLxAnVR`sPEN>77>G z9%~IVo65zqH?=8qG|o|9*;cr6f|bil2H9-^jxBuAEP=B(TuuCYLF)YeJ&rrdrd(az zzqpBGX;YJ=?1LUvbLCAB%J1rRW@#*#d$%UCS?>+s#v-C5Y_3ha|?kFtPadPJ>DEKfj z_{-wbn)>c*?^Hu>ByHH-c{ZphdzR3=VE{K}uXb%o!|^oE zohJ*-Sf@W;v$Xt;%KAMYbnGn(=P0~N@NGJ+>*Td0#I;JkI`7inzl>KL89FXLDHqV4 z5ZzqP_ugnvc?HYf#m6P@>^OCNdRgVi*5{Fxk22?&R%B0fQdq*0HFcv;$?sJTTANhd zUNS6Yo>RPKmp0G4FB9*YmKZ2(Z##M~Yh&F57JHk|$$IxBKJ31~@0{#juFR&hL34^H zud1^JsdhJv0 zrMKQEy5%R#7S!9``fTrNB|Gm&yO}di92S3(J8ja|u+01aCH((CQmx{*=`z;5t+r_I zjwavl5xJgnKmYabD1NhiMqtzCoBL+X&x=Xx3QVqOKdoE&pDX(RokwT8|GV94Ir?5! z@w|}To>`wiG&;xZ-*$3-{eQDlQghC7z0aOI<@>&_wLz1-YEkSG}F{u4n&FoojxwA!o1;+0HwE;92hZV>in_GJf2i5+l#nEB7w1axvGlSwYJ(*GsbtJiY$$ nqVwJAUxiUj7cX;vuc~4G7pNza8uVEVRLXn0`njxgN@xNA(JK4W literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/thunderstorm.png b/src/main/resources/assets/wizardry/textures/spells/thunderstorm.png new file mode 100644 index 0000000000000000000000000000000000000000..28920c9a59cc80951f11a3fc598f6fe9408fdb5a GIT binary patch literal 2815 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/tornado.png b/src/main/resources/assets/wizardry/textures/spells/tornado.png new file mode 100644 index 0000000000000000000000000000000000000000..dffc70b2028e3e04a33546f43cb07c8bd832099a GIT binary patch literal 2178 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE({C|n;HHKM~dub zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFbeSVskhq*TxDS3;P-TK42d{=bo$AB znd73z>O-%-*0JSIcj=1K@w%2|c~AC4U+<43=97vXpTt=Vi_U9WKCSnhP&^@+&oM!v z;6X+3n-fNBPfU}zEaF)x?f3o5n!B-~mL{H_V#TFW86^uFSAF06zWV)Yt&gYW+ot`0 z{Fou<$bH+kVBe1n3LT0Q6<%QyGU^NV@9$+eb}jYm zz1l4|oE3iDwNLx=$n<|9!}3{7+A3^^Z|&vX zywO_X^XmC?({eATPs-ePYh~ffPr*FDcCT4;Cv8sVyZS;|ZVv~|2#eaj-m9U1G#)+D zmaBUru#$Vn>*yyDEd>*tl63w&Jlu5u-W{eKL?hZnx8MQIkY}x?SB<0>6F~vW&Oex75n@} zLIoS$*Is=%`>mYyNsb=1xqbp-EYr41Gp;@z`spHrvFyQ;jxAD>*Brf;SoAS!I_&Z| ze|)>-u?)N0A3iWo|LPMo-~Qy5`^vMk;`V)GYyLQ8b^g87b*~q1zn4<`maoj{kjBwC zD+Rf}fO-CL8C{2hGP*aWE^14@72wr5g=wkEq1A#rxUPq`EM(ue=tOZ=FNgk`2VqXP zxXnA2=1X5M*Le4TZpoGO9oHYPd>*&tX6EEb=9dzhwknn$j)561Q#i8araN#nh6p{? zm@;X{yl&m1w3h@dHbHSK2M%RfRFJKlaBT;^(~B=M<=obdHyj_xy~la zBC>hTzi)bf=gMu*zjKhA>C;IT{Vbz-K9(2rF1*~ff|c)3@x@yYLbXhG#YS;+Yp526 z%$y@&!}KVSZHkuU1R?Ve8RtwnocYg(yL{DRI(+EoWuHki?maX6y5i_l@p$DmAvf>c zdU)>{+xK^Gi*_0=(-NJox9#WWxeItSTsR%P433LDOfXn*HBWIVlOo@f2^!azhOHOc z`ufT$#^wI!h4YtI{ELlIPcfTo)FI4P*gt)pZU4<53;{Z2+BJKBD?}@@WX_tF+?U9p zAj|WjDcW&)uL(uEtoQMr-TfRj9ld!EFKrHA8T(Ua`jm@*Cu^Kf z-*-FJ=;Vx^^o(4CV@X>MMii?YH8fS|yLXt=b>Yd)b8c=i5oCF@Hh*HerFZ%>&#LM@ z-?x{~xPK*P$BhHFyN|v*CYg4*=cS7BX|7Lu7ToVQT*g!LqgLiXqg{K|%R>`RFZ$BD zGGz|WhMPSLgapEzj%9iYeXmG*Df9TOp|;wyOUAkH*5?Iex;*&tB+{?m-c4L;t*P5| z9-E#Ag`7P{Bf8DlR;s$@2`qB(Y~M3ODSeiW{GxQpyFbk$yq6a@t^NJsU|M7R+KJ*~ z*+t)~4P6(?i!9nY<@ZxV1_7ou6)mjEI+bw=Yma`G`I9EB`au2slP^h!qyCAMu6KH1 z9k6oq{AC%*C%Jw1T({>~ck$SQuZ=9f9`60{P)|VB$nhp`lyu95{w=*5m!{VL`Dqq@ zetYDJ{ZB4OcO9L)d`9M3ozoZD9$9EIi!bAeo3Z$afXw@r_4DR_d|1W7-pZuPAs`~b zw{$X7Seszvw&RzQTxRk7D3^JBZT6DLzH6zB*}<3M(&}C?Kb6}5v+!w!y3eB)x6O?f zFRnYQy>YC6a&205>x4DSboc$RSa?GHM_=Cdz8zkK>dpyTsf`TJi#$4i}?XMOz0WkUuA1_n=8KbLh* G2~7acJ_@4% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/transience.png b/src/main/resources/assets/wizardry/textures/spells/transience.png new file mode 100644 index 0000000000000000000000000000000000000000..572777e2efc61c39fbad630bbd61d3d2a607fe49 GIT binary patch literal 2480 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 OhL@+SpUXO@geCw30=4o0 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/transportation.png b/src/main/resources/assets/wizardry/textures/spells/transportation.png new file mode 100644 index 0000000000000000000000000000000000000000..d3452080823259a034002203925473dd655846fd GIT binary patch literal 2280 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(}f#-3(8k6$Bk% zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifu<~;o3cgzXY$*c+N2#ZaV@Sl|qtl~% zVnZbx_HX@mt9t(4^K)+Bxpj`mhx@A7QkC8X5<5FO4aIyMk~}<~Otb5lwBlmM2O+&c zVMDf7iROokG=3!TggSY+Dl$r)UdlObTD0!oGd|0W=gzZye#SCA{(6+%oOzng?csms zf4di1{rCR=_5ZgW`F5J=^#4GS13r%rr%SBwy3D|ET&$SkSXS4^RS!0XACPF?Dwb;+ z7NMeG+j^3Bm4c(!r@X!mVk0F&|Igh9Mfng6fC_qXokik5t*)J*K4sB2R}>;Y%}9k z6s=I@7hRR=do4=t=G1wd7sRu5!?Jz&PEAgk+vB9=`E1vY!*;Ek+&{h%I;uGTP8LNLv2KSsoCyXVs)4Mnp2dfE0kH6Xh&3h%JoWCe0Rj) z-vPxro4wckKezM;H`iT{o8M0q^Q@D7_TiuT$;C3lkuAv+FGcPZm|NC(aEXFUqp+7t z@P>zTLB509KQJG;^>@4=&aYLqrq%i6!6n62rTz7Hf4Z;Q$|Z67(Z0tsjw}l9_T=?othy>;5TWaF zOEBoroqL&0j{V;GcaH6Q9{=Re`uMXqUPyI4<&r++Dfjzo|IWA7-#@jx*B_adFsc6C zj_JQPiUoH|=3RXH_4xe5>vv7r)?@s?-?=55-D9?4;3d^=y93Oto;;i;duZZ>ihYNF z>E|qx-NL~ZYbN4;bMxc%I~tSn9~f;~d2EMNN`mi!qglq*!H0df-#xqU8Drm-<&~es zts_3q{QT0-bR|2V>h>cW(qo( z*H1CM?|Lb{!B2GzTl{#RpDJZB?YFlr5WiHqqwMx}ORF7|H9Rc-eR5nPUpc2osyi?_*?$3+OrV7?dif(KJ55>ntzk> z-NTpd|7+GiuhdCsJs{=$vMKS=O^Majni-e=_%s|lq$C>cTFJMr;ABaQK$DG;hs?8g zH(hU?yHWo8v4}gDlM?@aO6d+M{cLyy#JnL?EQCXWzHpTo9$25$Fa9;<50}l8g-)Wh%w*d z`LgO3yL}25`B<3wd|r9o!hT+gTg0(XTH!hS`>o&Yn;HM_N%WL!Z83#s*X~)!lJEMy zVe6Xxzmi_Lr@ipo?&0U6V>bKr$8BCxr=D)UICJ667Z++@O+AYTTI>+n*V(e7fhDh1JzJ zEBE_-PdQex*iBAy)qE-C8xhLypS{pHp4E8uQOSh;;trmyd(HgHw{@Rf`0*BJiEPO# z%MTBs7ZB|F!9F2CR+8vEraXQA_Cxvq<{hhI#6Ui4|EvyZ%;L-wxIoxkH9pNqM3ZD{&c z!`yu|O>FMXxUEyOzA8)!`WDT^*8E8&?xHgrpQGlI-4~QB1t*&XMY&J+h?bnYSohMl zWyMQc&lUNk8Lm9a(Y==Qk5_}QZsfcPuX{v4Zj)-*YU|bMqCQQ-Q=m^Ft|MTc(yZ=| z=|ySt|LSX%bf)h<(#uo7?eKwJf|n*rTs}MV=XsuaA3a`iT5XQVt)8arC;h9g!P_k5 zjnx}n{(iUlS~B~(bv&l%drE0qo#RyZdf@r!aqOkEb0=-N6vD3|h z&#CLFHPeB&;k;|?CTxk)J@vFG|Km!QlaFO)I_aqfeLJ@GTgdc%icTC>OC~fw)?9KS zrSRJ9o{1jH;Tr!P_+_Hc+^mZ{(0qP-n9hsypT)R?zU5iH6;m@^5iqg*^Su{yZ#=ci zU+a*@^!y6Px45VG?~4_ctUG%%o9*0}13rg0{oTaS&>q(@eeb3DNxu&!zuf!UWB#e! zVy*3}3IUfQ<9^p|m!F%x-XP#h{_)yH{NBG5Uj3D~%lRqqK0#AvQnvpD1_lNOPgg&e IbxsLQ02`e@lmGw# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/vanishing_box.png b/src/main/resources/assets/wizardry/textures/spells/vanishing_box.png new file mode 100644 index 0000000000000000000000000000000000000000..535c2833514491a4231bfe5a2540fec0dcf8553e GIT binary patch literal 1945 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(`}5W-&0_-Q;e> zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||WML6Cl=Av>#+iYEUCq|)jtmly`H>l_3q>So@qJiW^(o&g+h}&BvknX#27a^C@jno&}h+(KGG%npS7R$ z(MCr{C$4S}4%LrL6ImWhIC{uf9_xI5_p0gN70+#Ts+PT-xlMVBtH#Q!OK*pN{rhY8 zecSI-_7oU~{Oh02{lW3mNn@STCuR%>+V^rb99?%h$oejO;N^wz##xaRYCQr4WH``i?`<3t9Xtjfv;lq)_{`mcRE3{S|>}c<3Pp;|t z7{Ge)V8V)=)}uy0<+(JDX?XP-iiIDT#kHdI@eKPoPs3v${!IQScYHZRckJ~0dlCag zJ`~&)n85t{Acn%odYSpEZ12q)DD$KvD8VQ&o&k>>D;3iD6uJ)=Yy`xV$*BYs{_&(h`9*r zC|$^6QK@Xwa9|c}4qB+yaYwa&8{F5Mfzx(2?r5jdnd8~H3xg}5H zag}LwGp|iLpR+@zag1^Vm(|>6mA|GTuOr!IgdbJs9(o|~_FD6w>Ze?e8y#=NF4<8! z*>`e5-AkR9I}$F(K6fdfxvF8y7K^CB3cjUW{kCOo=KqRjzBO{(s#GM!vx) zlg$k4gdgnkW!isu>yy|;@04z~zkfVK;QZSMGbX&f^uRLqj$6CNuKrzZXA66;Da+Xx z&Z*ni=-e*De?3!h=b;rZE*mf|Wi@Ov?6u{a@v_%Mps-*LgEDVU+-1988uM-+E1gx5 zH~s9whgX`HOQh!|y4X81n94c8SgV?BXw4hs)j-|N3FX`=4R0!83=;uBQb* zb9)J#G1Ss+pVj7}t+)5T)iteSKO(XP3k5$iSig1%yW?UQQtCRfpL33wFK?#aoTR#U z9IY-gIeMG6N(#7nmqaOE3!QaQNZh`Dl19ve>E{dIJy~A)qVe*d+|=F^vzI^IV(>_L zSz||ghjV1^Su2K9-+pLK-Fq^qW}3U${3Mfm2X^^-MK8Rhn6*Vh#PH%Bn>b^Iyvj9e zp66VCaII=`ak{_IsgCLKyAK8ZX4(6&UZb?fxo<5O+fC79KbI(-W9ZPh78VkEY-{iR zVh{g|ob!%}&iB`yzr?Y*Jpbn$>x~XpC6?QAGPcLWTvvU^H1E^BXi@3Tr!O9+Ui$ZY zNhSaKtWDGQa73iki{5(8(6DsPu_vzc-yY;jte9#aU)`C%t6u$#a5)dap{5&CJ`znNb?5IeTRnq9I2z|AT@@Timt9Zp9|rG+FR@{+<>nSXg@J`P2Hp z4LQYA+r{M7^@Cnj`Q+;UtutaSJTAoXx6W(%<%3y{aeOB~wdi;=Xt+D?`#*U(gU9_! z;b`q+g3o3ZJe$L8QS)>6c^{^|JGmSLj+pG3u;;^uD8JHouNqD~S@7cfZ;QV6`VF43 z&qKaeSnZVIW$c)4Z_Rr1owobDik$urUmoUlNQeuv3m%>uWz2AF#@xMDHw80q9XG6v zDsGr1=m&tnfqHRZQZ?7scSt7^(?&t1XRm&r1 zmIMe-e|nE^h1ROBo2(bQHp$e!*|&bpv5->7{qrA4Y|#21*L3&b$?XfWR=)1h@wYQ` znD*Us5^u=sm79Od8vLG~VC2|1Yt=c4)Y)_1&3SmJ`TW20hvF^%%kbM5G+zDsTI8v~ z>Z?nVcR4>^=gpAt_Q`@9r3ohQ7On~@J*NDbUxc}(q?#fiMOql>ZvcPsO7Y+iIsqVC7l4(Zj*eYz&;vOg38<90|eeb^kn zd8PKQ&vM(Y&&-O7TYlImI_KN%y5!RQhm-DZe;m8W|J5zl!teYwm#)_{Hij1X-uZmO RgMop8!PC{xWt~$(69Drsmihny literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/wall_of_frost.png b/src/main/resources/assets/wizardry/textures/spells/wall_of_frost.png new file mode 100644 index 0000000000000000000000000000000000000000..308cda1f200066fcbf05eb67cd9da9d4308695c3 GIT binary patch literal 2521 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)0SU3=EP7R;=x1 zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifu=DV9i+jqR+|9tinda%@7!q;#==8`n zv7wR;`?oⅆ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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/whirlwind.png b/src/main/resources/assets/wizardry/textures/spells/whirlwind.png new file mode 100644 index 0000000000000000000000000000000000000000..096840b310e31cf1f83ebbcfc4b60d8a804a870a GIT binary patch literal 2292 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)266m>8J)>kWGt z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~JTg2Mtn+d<CM*YjC^`E*3ovMoz5iRpys=xbcyxR}Ay*{P(s@5SmpGk-K(G(T*= zfW@@yNXDK$Czu62GkLa5zSj_R%V_TFnKO&O*`?nU)E+yqO~-4h(o`=&)*rI- zE&5ItvqmYj-1xCD#-6(|h^x`z^}pidpMTs+te!mAeYx}*z2D^w3^spQyY1&q=g{1! z)4VXMRhj?Y^D8UeXU6Y2y8Hjk#KgK*owL8(mfT@+Vu)&bfcedO9hv3$#R)sf-;yO9Uk8SbIxqW04 zkIv}>+kAaaA2H$Oapv3BIDzS~!HVmzITS0t=4^8OuO{wujg`ZIw>fB~!`{HBtJCEc zifh;X`qV#j|J6l7ddZS(UYRW|3LIwd)=hQGW;1WMInAEKv4u(Xw}_{r`O!niF3(T< z6`^x_Nr>KuAHw_}4}AQcq4#4+)x51+^}L?WSk@T4L1P-%n;8=6NzW~=W_2Du?lxo2 zssN3Mh-pVQ`TCqbV8YwN;_StvdGSE@^G$1c6j+u`xzXpjH0sbMAG?1EeKWbkHLi+8 zEw7D|<-Wa9LqsO$_8}A1#mc3JZY&Nk(Fj-doHX%>X5_TV&$)yHyn@$X&)lsS^>Qu4 z5`h`h99Kp>IC9ci#{i7Yi^ll!8$qU=EAVGL2E-LSA|;qx?rbwK4z)3 z`iK3#?-2MT>oU1f?~HRD!s!_L>XOB64h zS`uKeate3PJE5K{YL)-0?NioO_P(rjUm@~t;oV3VsaZSy!)H|fm*NmmQt=eJ1A0*kW_#~o6E+z+$r|E0@?0vI62jO`p4S* z52ot=T35z4eLt1bw=N0W0rQwE?GX=S;tCai>3;?GEPgK z@SJOH>He~et)dMAO%_+aBzfLA`*N!9k_k8ZTHi|a^!071uM)r1qcQE+$xl;)wsr&w zIg9Klc&R%n?$pZ3{+rU5J688sa}1Qx{~TvuDsTb115wY252g+-t5JoPvCY}*8yk}fWK zFoTCb{O9%A^=VrS9arWkv?LYQiMpOEpI6-%yZc*!o@ikXw<3$v2F{kkn)P2d=kc74 z9x#Zp`O0pWJ^oo$;nsR+A?|i6QtC7k7@j`eV@DU z(~Zj^*{sv1N9mkfAD|;ya?3C~Tes%Ex@XX$9qpH91^@Qhqpw0mPiTz)Do zPJZkozhi#UR(_q+#(8&sbllz^*0Fes*HV|25llR@{&)7)=$ul=mC%Ut=f=)bCO-{0J{b`?2RvPjj% z?#Q7#O8ev|s7c-}=skLse?^#T&^KP~rQ5U?ebouz+GL{4p_F%b$JzIFpT+HLesXSg zn`yw~acRobsiu>*96xjP_M3aQysJF6Uv^q9J8ky%488NhtqQ!8h2v+X{Xe*OPJMlw z0f)nS_6KG>FAnaGd8)FvrSJLWx4*VrW7>6BEFxBCbJHo~UGw~}ct=JSMNXB=oV0O| zf%k*sE`>c|X2RC)GxzUx6L4Fyvs+F5de((aH}%+#BzRvkQSYicb58HWJL~k7yw-1S z@1I@d`uWcH`A5ohmaKcYD>iDiTz0nI+iCvWg(rNIadUIG_;et#tCh=qz5a)XuG9Ob zFDUAjdeOGl&|pG9)YtM$-XC`}Zqv=w+xpT)&P#PiwxF_dX~;Sa5!piuXlSfdqg!|AYWM1vM3Bmdn$IVxSslH z=guU1k);k^8$EB%TGp64Q@ZQ=CZ9P?&KsW?RGl}7HBYImWDN*eAXPaHrBm%^)ux=LyRs3+Fugt++i;ui@H?n1v(uZ$9<2qua|mvqpxcl`mgjVtZSzztK*1z4EU;*Q^9SZ`QYa|JA;~KlJC* Tor>ZN3=9mOu6{1-oD!M*G)LKlts46#x3+3ci{V-7 zxAUrQ&)lQJ3Q|FB_vB~iJHjFsAER9#pgwms8i8pn!-S2i4Zv!tP= z!)L0{#s$-+S}YQk+Qs_k?c5K$Sy(g-Wu|x?jhgm|Ls{{DkM8;P>k>?l2no-S3VX$} zt#hfPOj*Zc)mO_77WdCr<(u6T%j(S%v`|U$c{KNxrViO8mgYdqK8J>xCvVT!@Y7u$ z?c2k-!?wU?^Ddvu*Em-suDEz!=j{qdiER;CIva!D2mFwFY;(*@v?G&UP&|CPCg)8b znMF)l@~yQqn7I_3SWmm~Hakg(_H}z}-|?R^+nUvXuGP`&){;9ncZ96Gp;dV2;0>|r z-?dri9>=r>JV@DmYUgC`n7^OAL%3MDA35r1{oBoQE=0Q{qRR40je}{&%f5%->P`t~ zr%NvTkXr7v_>$5lQ!n|=6^oo>xIZkOBpx64F#i8Pu52-jn{Ddnbw6MG`rS~?>EjBv z2EV~1&jf$71?k4%nt z8&w`*?rS^n{K{%y1I1N>p6k|_uAY-ICn2@4cfqActE;o;tTp>t@cY+9U%Al7M~~j0 zaDw}R{DytE7KO$hFmkxt5trW{7@?>udZJJ0g*fXvnM;{v9IPe=Jezo4vwsmvo$ywO z-TTG^)pIPW<)`~^+}Uev|M%HD**NR}?2DeAuXwlR;jQZ1HaA`th6~S8t2le&7_&{X z&C^1~h9k~a5{gfBuH5n|=-J#8z;pFNz?9^=FOT`=-~Yq<{5_|RA^ZQY{Qpi|IvW4! zW_$IUH)=B!o|Dvzy|L@u|zc}mYhUsq>E~+VbEq1qA&R^d=a{Vcu z+vlHc7ZDIVqP0ryh+@Sai=z3TQ)dhWveNyM^xa$g1z$Ap z{?ogs`lf$d<-12r%}=B+y;kK zTKh46xctw5*&H$Dh(70iuXqJGZ~Fh1Soxtsdzs+VJ)a*QPf6|SQqU@SCHVgSuQ_45 z53c?Fy~ad$?TVCa3zw}52A1clLu6K7{yDMPJvV}d<$ThLh{rGbj6<9z*&G)NyvbBkV+Mm#|#sMO#tjCFdS~=J{%QJJRvAmhE%F!iu?7 zdsob^H}^jjuHTdXse-F?$|{9CGwvxe-Y1LhZYbQ~{_gY5lSM5rt0sIqxk>T%$q8jk z4+IxI;96rbMbcuPdA+<`zDuUntZnDDBp6+n$DVmprDByBdG^Z5B`zgV){}H*uYTYv zS?zzexg&YiYv+O<`+FVlzI)xPP*w1CU-Gge&?;$8s>GihX7{5Nzkbe8k)D+1Jn2nC z;H~4YSyYc_GDayplGxFdvFt@m+2hL3<$|;CUi`?F^L46u+{}HyUWc|XS`umWIJ3j) z@C9FM57C1%$LilLs@qp)usO~(^yg`xZ|(;fpL}@#<4e}#>c5t@Dnd2CkAAoP$Nom~ X!?7n@CQf8vU|{fc^>bP0l+XkKBUa+O literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/spells/wither_skull.png b/src/main/resources/assets/wizardry/textures/spells/wither_skull.png new file mode 100644 index 0000000000000000000000000000000000000000..84a135a3f6eb27a6bf648077d08f2a0688a64083 GIT binary patch literal 1582 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE({C|XBhtbe6ha9 zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||U=$SRVcGj+S_cCI>uygM$B>A_N2mMt z-##XJy#73oyOOG|W@h~E*Hzi(8#ih^i00$uxgRZJ`#t7|wa8zAzig$|Sw$ypPi)Qg z^Nc#+`FhdKlHRk&BG<;3x$X^8Nw1o4@tUB*xTfB*A*X1jCc4~2q1^0V1L zyuCU*-6G@EcLs*@dd3XjqUG3qAD*Azv{meROy!zvrKTXRgm>F_$Q?Jd-~asl%RSZG zk7h3aZ_9ANdOOeidbKT2*^=fzjOp7dmY~~m!bB)rSE*^M*wPToYnJX3Z8cvk+%%8o zzYBjZ6Mpn$-RZ~8=S3fx=x;WbTIJfyG3UWfEmO{w-on|rl@`yRo$FrwBff#rC9tKq z&;FmT=G*zRo0^wBn6r54w-2Fn#cy7JGh4c1YOI>s^0h)%mlO`DCw2&X%N&2&%*D?2 zn){)vIoI)NGCv*^x0bOvi_YhK-)f(@|J9F0|5g9{_B*y;5h%OE$b0=zl($4%OQMB% z?ZX2(v;V%I^VomB&oo(qmfKcJ6BzBgU)fmwW@1R@iORN<{#QIp{h;76(|~n{R{!By zDv~H6blgzMNIaD>c!z+iV4=+Ur$H|pjv17QD&7C^;*EEYp+vIBClEVUtUjpwQHY{LfQQbYql61D_D}vU~{s)n2+IU0?&tIdAgHo()0HyX|7b-EX!yXfAqSroUORRJL%Uy=%9c^1(^*_N>t| zmnO?U{{34cQ4Qcp`g)*L=vTvgVyT&U*ds@2rQt}R+_ie0?RmZT?E2{K86Hz(^Se3i;`v+HqGkB?E9X@| z`PDG_V#oI=%Y99@!H(SvPTYLFyyrKk^;GAcRqIYLnm<{6?|$c@4sJh=6_c$`^S|0h{kN@ za&dT|wQtt5Bggc@jN0ZXXsokHKb*&OVY4D%`wceb)SD*KE$e!x%0*i}Jycb)iE&$1Rr;aTQET)UnljJiUfp!=zL{>3%(TYr)Lg z<9mDAZpXDw-s0pi_3=mUqOV=CH6poldN@j&7xso*8~lEy6Q^_FPPX{WZ*N2RJaZ3S z_~!AZVPUVO+_o3troPF6Usj}+9{VD3qNAeb)QN-ZET6o5@-d5DY09RvWn%%#JrmZ0UFq zcyN`BqX4VE(b;9YI4w44uHa>QS~2fWw@$N1Xc+UETXx!eUNm(~Fq+5Jm7rQ(`+v*+ z^>Kz1yx%xX-r3UiE%SxhzEy%5^E+Qp6HUnDO4}ZGy;Gk_?7Ns_2S=gIV%NtJ2q!%sJ_ZsIWc-OKP{cf8p }j#EQ2fI!>a3>xJT4X0*mJRg}&A_`&gj{6C@d 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 TsgCIk3=9mOu6{1-oD!M<52sIV literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_10.png b/src/main/resources/assets/wizardry/textures/entity/arc_10.png new file mode 100644 index 0000000000000000000000000000000000000000..82ec1d74a10731b3de0ef3edbea861bbaab9b681 GIT binary patch literal 3619 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_11.png b/src/main/resources/assets/wizardry/textures/entity/arc_11.png new file mode 100644 index 0000000000000000000000000000000000000000..f57e4badb0d6f26e2831e8cded97c6f280379ca9 GIT binary patch literal 3865 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_12.png b/src/main/resources/assets/wizardry/textures/entity/arc_12.png new file mode 100644 index 0000000000000000000000000000000000000000..43c78d9362425b586288ec8db8679bc475f5f412 GIT binary patch literal 3836 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_14.png b/src/main/resources/assets/wizardry/textures/entity/arc_14.png new file mode 100644 index 0000000000000000000000000000000000000000..9e17a14404471492da4e35e0d5ba02a1dea2bd47 GIT binary patch literal 3891 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_15.png b/src/main/resources/assets/wizardry/textures/entity/arc_15.png new file mode 100644 index 0000000000000000000000000000000000000000..d3fd0a9690d1cec728bb33a9d82c2b4a6895e98d GIT binary patch literal 3830 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_2.png b/src/main/resources/assets/wizardry/textures/entity/arc_2.png new file mode 100644 index 0000000000000000000000000000000000000000..a281efed09aa442639a8fb6e9bc0bf4a101ea322 GIT binary patch literal 4126 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 sSNHRcSKEFv-?pei( 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_5.png b/src/main/resources/assets/wizardry/textures/entity/arc_5.png new file mode 100644 index 0000000000000000000000000000000000000000..486881b14ac0ae8f80295ceda41933dd919d12e0 GIT binary patch literal 3858 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_6.png b/src/main/resources/assets/wizardry/textures/entity/arc_6.png new file mode 100644 index 0000000000000000000000000000000000000000..4038e71e9ff05c110a6c0666d8038ec3a3c310fe GIT binary patch literal 3756 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 X1-RTz59(uJU|{fc^>bP0l+XkKVF8#* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_7.png b/src/main/resources/assets/wizardry/textures/entity/arc_7.png new file mode 100644 index 0000000000000000000000000000000000000000..383ef6398be750db4dacaaf67a1efffd1abd5bdd GIT binary patch literal 3685 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_8.png b/src/main/resources/assets/wizardry/textures/entity/arc_8.png new file mode 100644 index 0000000000000000000000000000000000000000..0dc3a0e319d52baf64b686dc2f6a4f6c9ec57ccc GIT binary patch literal 3611 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 MPgg&ebxsLQ0F8Meh5!Hn literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/arc_9.png b/src/main/resources/assets/wizardry/textures/entity/arc_9.png new file mode 100644 index 0000000000000000000000000000000000000000..4ffae58f91400bb5e189a08f2bb7f708b87d60a3 GIT binary patch literal 3617 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/dark_orb.png b/src/main/resources/assets/wizardry/textures/entity/dark_orb.png new file mode 100644 index 0000000000000000000000000000000000000000..0de0ee6a9d580b43b5b727bc3b50bf9f9a94ae74 GIT binary patch literal 4968 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/darkness_orb.png b/src/main/resources/assets/wizardry/textures/entity/darkness_orb.png new file mode 100644 index 0000000000000000000000000000000000000000..c43ff6d720609dfa6724e5d4e6f9802268398610 GIT binary patch literal 1691 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE({YG7#RMux)(oU zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=k_b4iJ6YtQODw~2v)K{hiaqQp5rH#aq} zgaHJci&7IyQd1PlGfOfQ+&z5*QuI>U85mgqd%8G=L>!(w{bo`0aly9z2WM_hPvzax3t098Hr_s=W$**BDquSro z!WMfR)?_rE%Uf(d?zAo2jKkM%z?`wi9jCPc{ zy9#~te)Okn25aFxO}FTdtu6{TEowhIxBhydclh`Hyd?+P;$+@fF5JIKvXd>&d_l9n z2XpVifWV+hB}QVqi>jm*-!9Q$zhtNNY?~zSd{A&*ZL(^&TcypgCRSki^v2o;MK1o^ zUkF}uynMu&xvi^d&WtHDy(H$J?^G_#Q?Z@tlEHZ9*NT&W4}~!NdRlxq-kx1^L+;8l zY0lYw+PP(W`Kq_vP)wTLU?#WEML{{)^AyYc4omg7JwH_o>)NDMTyG!WZYgVL{9;vu z-Kpt&%2-|e8{RPO_N|I*x7`)9IuN>Q0f_v+RwC%Ii1}{IES#sSC%Cb7q1rPM zXJ0?3Lq6BsGL*P3omlwpz{jWdKR!**e#E)I|D28>Sj26JMuWTW%zFpPnLe zWr~W=#g+^vn;I#WBJT^E)@NV4KI`<`WV8L!2R8gH|C+g?vFfk#*1FH9yZFDzJ^pox z&pY%`)>Hv^P7%|k>oiwrXq?pWJUK(yc+s*W0h5gs(>)!%Jo{qfgCm8s=G0~%&ycZY zik!fmcw^fvCQnBvKc91xdMr7Gr}fPEG|SNW7|+a)Z8HQpgN>f0=xBOqcnC6Ws(#it z|It0?3t3ZJu57%Kxw^aO=*}sYoWV6w*}u+q&dr`N!6@;dbxqZMoJj_bCI?++UGe!A$MlgQ z*v#g_yf(&VZx%n>bfT+s-j*w6r%bXQu&z!zd2*)kg+-1EJ~Jk6R!Q{IQSjPi`N6N_ z1k=nD51%pc@_+ePder~E)UWL`t@hrzwDfAd)w3@_u7b~wxV$d8(XnQRezM!48BHa6 zfB(C@+55&?(BSf7ckQoh7^UoZ3{Kl+Jqbw5UOZo1^7Gv}uKEjmr%k!BLS%`E%2Epp zLBmg8ES;=|Ovjjg-m(^aHO@TVZZ2wXYxZUTgT2aDTR*fEik!cbP$k)2c5IR6gL8YP zYwQzWo`2-tsqf{?XMX%MfACX!Rsj2l$JdwbC<~vPlTjD`-q&8?WI@%xBTHZoyXGFsm#MRMLcy+E?I9ayvuU5c&zR3X_?$49T zwtx5PEh`rL%lb^>&8)LJFy~%1ht;3_=liW@@$NSck(9aLW~Wtj<;=5;w3h3|?QheJ zW`(-nUo%JkPQd^F1;0LjUwv@PxrY@?rQghvu-cwdY;pF@mN%^0yMI-Gy}dk{dx_pc zt%Fk%vVI(&o__t$&xc(%rQ|g7O(k!8{onfB{%Y|RW#5hSHh}5~Pgg&ebxsLQ0G0;( AYybcN literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/dart.png b/src/main/resources/assets/wizardry/textures/entity/dart.png new file mode 100644 index 0000000000000000000000000000000000000000..ff59654aac2c3c32e58180f0258451ffff590bea GIT binary patch literal 603 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4Dr3=D~ys(CLM z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|~+)`p@#-8if3NkP-zVLK$42d}Wc8Xz! zaG=ET`t`aV3j#W%lvNbj1zUV{BaTZQb#)Fna&)c2%q4CwLUgRGcBEu?F13(YViCF8 zJ8Ra`=I*8@(RUv{=@m^sGS4H)>~l<2>w_7yr1#waR9myB|NHab|K4+Is(!4HIlXDe z+Q|11B`e~O0XSiHsR%?`7BeLny*K>0E z_AlCfw?^^$UiMHCI?Vl|B`3$*(6&CtbX#nOyltt4toWUM`_x`2{5?wY!fZO@KBR~A&*^H<$Vv@mCtv-#w3ztgHxoR7D}Obg$f6r;my z61qCn#8-Ky51;-6$B%nH*)7h$ZQtp7*hHpW;UC9b<_AI9Q8n*x{W&*RVXBvGX9wr| zPcAE!&iRyHTx`yEX2+hY;GXVk1`+dyegQW6`fXCnP#SS4%JCIB?bUfc1}kd{>zAL`}aQ4OU?Kp)Hxi5t!!BX!4<+MWLxZsB!mJhf@kg zUlchi?rrB-!!$=$yXzMFhwZPK%IYRFEWZzW z8()4h>(0BYGSgc$#Z}8sEHpWFX}V^gN)%v~T+vh5Hv6 wrrUBZHwizz{`CB7p_9%!Ki_+O`n0s{_=6%{#fOvGr-H)X)78&qol`;+0JQF2jO%u7IQw6i;|#;4BGx0c^`{$C3*nNEBOvmpz?v;PQ%W$$L^VNnI z_qlt#A8jwKi~V{l?CCRwxPtrKb40lnwGMKBe51y+Nz#jf(}BCewo_NMq~vQ4&vQmW z#VNZE1}JEF{dpejz>AGs@Vpt1#?uduY30%WKz*VgET4 ziyf}q;D5{b+hDkhEd)2;PYQkqtbm9pZwSou}_MbK}>eSj0@ZWb{}>> zUi$NImFQeiyJiP-dz&o<-IkLY)_FgCBp|`sw6!2q_P~au_is1FJqWCCmgVrCxHW!P zV!yr4-FuH%bIxARxG~XA?)3+^wR+h$eA2#)Zd8=K`TjHBQZ?7Cnz>K8KYWsd!*fvd NdAjU85kJrJY5_^DsH`+`Vxl;Bb0F zLo&l60XHc-Ar_{4&AaF8KiiPuv5P^5|4~|7``jmtoAN~OWk0vy&~sePJO1| z2LCR$S!ESzvGzBwZI}6wP+YOHNcrQxOuY>*`+AQ2UaqwuoS|dS{8PdXTmlS?0t_2e z4;Tq*v9LHWK+qN5Rnj3G91RQw>W(*sX?aPd>7~YuFE~3ED!jR^l>&Y0O*QImGc>W)Tx`jzC{||m_ zElvKF^y^B*^Ul%=ozA+V&yH87{8Vh&K7G*+H@D>HJW8FGMqk6^zsTIlmw#%OUbf?z gz_IBcq9%T2N}5xWXEJ+p0w{_+UHx3vIVCg!00Xnv^Z)<= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/decay_3.png b/src/main/resources/assets/wizardry/textures/entity/decay_3.png new file mode 100644 index 0000000000000000000000000000000000000000..7fe8ee41dfff041c3cd3171249ca8807b7955806 GIT binary patch literal 652 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE{kO5 zYK4n~6mRAbk2%@VCl4fjP*qv*?%^etn{l350rmxT&i8Dt zX=G>$>7|7j82rksU*XxM`!!B>XLp0Xa!`?wil5Sy ze_{)iSPimrJ(L|?WhW>xb{B014;fu1Ij&Z3tN=4}$P+m~rrlF*`D%|01 z)q#`${(H4-b8=d)Zog_PgXfk5OGPch85bR_=jc#z*!UoJk5qi~gNTML8xl>MuV*km z;ZVrsd^nRgYubK)hD_%FiV5GgO}Y9YI;}ZLX?-KZwXUgGdFENmin0H4VM;pv;pl?D zE&2T28~$g{;c)S2vx4%Dgyi?nmCl8>Nw5a2f4!FJgZ+2c z=S)%K6956&O#8EV#!cy@G*xYNHaXjsoLtjRVSz!VSsV z+$_&7+)#P-!jkV)wWgiywb*wldCZ?z*)4n))?|C`(FL9U->WTsgeJUOT%2jS?8kn~ z^AlqEIpn{{#AMf>&OLYY;RTCB_Wx|w?%K=fyS=Tr;IX(dC{cL2`njxgN@xNAGHnIs literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/decay_4.png b/src/main/resources/assets/wizardry/textures/entity/decay_4.png new file mode 100644 index 0000000000000000000000000000000000000000..639ce2ad37c77eca02e5363120e7ca7b8e178518 GIT binary patch literal 602 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEcY4f6KtYAe$KyQR1ARo12JY5_^DsH`vJ}q=ufrH2F|NrB%Rj+z- zeJfo81^Q>I>^iNNwCMQ8O6J?=LAGA z_`&g6gNg#@4xa`QMuCg}FXcDgj%HADwJ&x!%w}8Gv7@){S%dPue!;LW`q!Dx945OvX8u yZS%c0)Ltn5Q1v@F&n&$?`tO@>pVg(e?`4>KsjTqyY2P!TDE4&qb6Mw<&;$U6jP0%f literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/decay_5.png b/src/main/resources/assets/wizardry/textures/entity/decay_5.png new file mode 100644 index 0000000000000000000000000000000000000000..923841831ae444287fff2f013d565f48bc0bce20 GIT binary patch literal 584 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE3oXQFS>JsAO;YB09YfI3rCeS;S5IgdT)7=Rz3|1#%N!h6 zUhP~Tbkd@yEFkUN@dA$*wn7_kED6g@2sl=uAu5?!!OfxK(DgVXlSfQy{Y?JpC)z|B z+$P>U=Kb7l;flw63|7^N(=%3Z$-ft?V4u(&5M{NJYeASM@0K4amP}qN9Zs&l@!;dB zvlsckHWOO!>t#y zu{1CUFx=6tU%6M1kx_vG%q`MBdOLhq2Lmg^>Ej7M_kPmsVi0$Kl5^{#EW?CSjyFnA zr5Puva$IlH?`1Haf9jFXhJ|c1bUM~Z@N{P$So-M0l9d}~Fnx$&J|h)>hr8mY$kCMr zx~%^eF~mB&fA*v2&zcz}%XbND2CSI0MdMFqnaVo}Mw8FAyO%MXt>O=##d<6Dr`+S0 z{~Gzlo*Pt2&o`^N)IB*OWe*$M$+&`TnsX2RSa$M-eS}BUm*?WP?B8$wKb(8+?!!Aa e_w4?)csv!ayO>`PYA756icn8iKbLh*2~7a9Fzmnp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/decay_6.png b/src/main/resources/assets/wizardry/textures/entity/decay_6.png new file mode 100644 index 0000000000000000000000000000000000000000..5adb70a21a119bac0e5cb22a93148be342844cbc GIT binary patch literal 633 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEoq&0oh))%uh)UwbkCjkaF$F~RMN_gHN?>|HTyGE4a4`pNq;PW;}w zx8c3lg)CVGy9FDMF_;O2IXAp2K2)Dn5Xe%i9mnrEq0D#+BV%<)aJ6*I4Ay&G3t#ao zZ*V@q$z7%|AjTSZNMXzNBMg%jTIL@w47S!VnYwrV?=m zZHFy+%?WG`{-rET%!#RPF?08FE&X>p*nGt_(T8&!@|>1j3A(iL1!qwOSKY>g-v76y z@ICP9n7|;@d*HwtnS@n*3ywW^Sp0o51CP`crrcxi1tbdO7`!4Gav0doaW{!QUOgqT z#%j96w-a+0U)cGkd$QosXj?CTN&O(ZvhFRHTO@mzRsUJ^{6W<3>3OBw1CzJ!&XSrv gN9M5cg=*8a=0EhB61AKASAkN1r>mdKI;Vst082&xGXMYp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/decay_7.png b/src/main/resources/assets/wizardry/textures/entity/decay_7.png new file mode 100644 index 0000000000000000000000000000000000000000..52b7d6dc0afdb434fe259d0e206d60738c3cb2bc GIT binary patch literal 555 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEHArVRGMVS-s)&gDO?W1uk}L8PcrnS={)XVoJUyv6lGlpYA<# zh05-P`utiyk@Vm;Lj^cZ~xrpLcUD za)0j1Dst(-oX^_kPR!TNnx`^yXeF#xc#-3sdG)95uXVu=xA=B<*@;ZB2wnJNDg{`mnz2ZE9xm#rujCfee-LY?8GN1yipj3#ODb zF$g?ae)y%Vl*WMrLD#=5J}RZOD)Vt@d5cs~W8MwNvfEeoS)NK?(84WNv-nP=bi^#< y-H)Z`G+*-kyYA!sT0PBK?>uj;)$%t~>*H??t`7B_`sx`d&OBZHT-G@yGywoc2i2bd literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/decay_8.png b/src/main/resources/assets/wizardry/textures/entity/decay_8.png new file mode 100644 index 0000000000000000000000000000000000000000..98951c88017a2def429b4f70dbde5cff0483f22c GIT binary patch literal 645 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE2=Ks?iMHK@g85Yj$xRAM0Kcvrh_qlyRo3k}1)^E78j(=-!^9p|Xp#9Id z=0qttGZ-d$IeW;kN2oUhF=gGaT2Xr7O}3_WyMx|q@82P!UI(*yKWx^{S<@KJy~5U% z>sUkcWcCS43yw~*(_p*5Wy1WBh@D?=a|TS{wY%%3oA)k*pK;aB+uCf=XPN3bHUxq9%o!WL8Y(_Kq`_3>ap3gHOJa%> zYPh1`{C;`(vO?-wzu%X9e%sq^`EX9avpIj4`VIr_BRo$d`R#W)ez0er#4w+WTat7A uMHW$g>nHWCyJyMvn#%3J;Wbz7%0I?x&YFq;OXWbRgTd3)&t;ucLK6T(1_=28 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/decay_9.png b/src/main/resources/assets/wizardry/textures/entity/decay_9.png new file mode 100644 index 0000000000000000000000000000000000000000..35b410707eddd97d8f0e0363529c70bac221af13 GIT binary patch literal 642 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEQKT{#Uz!{&_y`4N?l&LqoiOc)K_5-WWifhSKO4nT8 z`F%-z5c?OVy65a&AI;A&UbBk2;?ZEo7Prg!!7cv})r>|WtT(Na)Dw(%ecD;WkQe<{ zk$pvea|#RhN4;OB>se}Z6qmDjT>CiX8G{kezKn-W&7tq_@k(7eS*7AowC0U3+h)EQ zEIhmauQz5&Vlq%Q;FK`tI^?U{tI2rV#lgp+`+88CP>ENAt7L~?+a5QD-!X@GvutuH z;Ajw5YV&Ujac;Q%$U}%xZ>hpmhC6Nt9Ih%{Rdei_#eAovx8J{wD|^CXU~u~&;~WtXx_uAjJbrI)XpT3+4cP4TN(W_V1C&u?3htH0#i3Bk73 zGKpDbPV0h-oR}h}K6t5Aaw+rlC+lke6Iagc0vx>(xIh@ADYn mJ*)orYD=-P5~ErBp&!iUaZTALTf{$tl7gqJpUXO@geCx{e){qN literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/evil_wizard_0.png b/src/main/resources/assets/wizardry/textures/entity/evil_wizard_0.png new file mode 100644 index 0000000000000000000000000000000000000000..a5dbce212d6e1738717f25dee0a5f67904092288 GIT binary patch literal 1639 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9;U>dXhRZMQ zE?NMQuIvw4*?BBkTsTrY85mfX)foIStH*Wr~}*doTY_FoSElh9P`YGql%|8?mW)}{SzLK~Ozw|XoU z(1^HoqdjQW7FQxLPAl^Tqr)cx?VYt7g+E5rz#*q)*KIDHUbI zW;?l6tUvL5yL!&2Rp*bL5=rwn<7e2s`MS*h`(OUJg?Q!UUOaJCAb4KyX1hs8e^YPcxeF7!#Ss41aH7@?kVtQ#(-i$M znf?EqzyJ2(4uKcPjOycS-Zp&I*%xn9Fyphv(tm6pjE;Co9z5~1@|sSbE}VaYu`?s)61qi;q{m4xHrPBEc3i@pI~_5a(ITZuTg+H>s&um~fbC%5VscrkCZ=C+@cq#cohP_~Mj9=rI#p-4<8M#>-KHh&{ zw^Yqp^UUE*$DbN@H|^XQToY%r-8J&(-P~GzpM)I>NiGYnbR5@uq@6cU*!MtwZ z^6=7~c!!G|FOPHIxO$Pz*0QnWRFuKR;tBJG{B}HSQS@0C#jr+&YtIJH?&E7jW=Q{K zdim4(!erqKlZDN^Ge1g5=`WjLUn`cYdp09G)9v4vNRv39!kI4T9ha!P>zr0oKegvf zkn6Xar4}Ez@USpw-QJP0@yipA4@u%?V&>M)Rqb!u0zxI2&g`~?0xX}_4Vs3Zgkfi<+Yg6ek8!w#3Uzpo_4^OJ@ZZ$Jw5%; z#ByWS)}|Tz>S~O>{uJD2s4I8)z=;`a^(OrOcx@Tm`A=EJNxHSKufFZuV>~^*K>6>1 z?b>^4Hp@tVdu!hqf2=>@*DIc{ufCt}wSDsY@*yoBuZ?r`Z}19)Efnt$TRLg+;wb$M z_q`_Fd4Ia3{9&SIS8=6Ai^8I|1+AejR|Mv#w*@?v7P>ZftqVt&8*fs_x2?K0HNOuo zcKG{mS^Bj?)vX)4?B(t|C!4e_^VqA)B$sBqWA}vCT~U@hgD!4eBHcGne6L=gf2=h- zLq+=WxY;tZ)pu{-61?$R*{Y*=vr3hxA78XDXY%^XN-@_?JQd_?U7*3T%rnry_s{N> z{To)q3%hz~-aW0+HTBT4Ovj76o7Hna^?v=jtu0M)_SYxnd$-K}5!VqCoV}STH89@o znug|8k?6--@_Nq}=$xNY_9dhDZ{1OIr>kMni;NbrpWe0ZQH?<5Z%fapntu_s;l3{>l@#*M3xxHOfXkJ-&t`` zBV0pa)s!bsOkJ2y1}>QMSFSYai0J&&PO8t3sz0&3{$jxtD|d$pb$f*JJKc)Bw#F`XMFI;xl>Dk?IB_}ky0zodAf6Rp%dWp(k$m4!a{mdgJD(?e+;r76?uyE` z|M%n)>+Et@9|3)(oN2030P=2tA6VnQss?@pQ4 z@4el6zrtU;@;0GT8SMyGp{XL=ijonMAAT-%m{4b*F7@ZQAM;0-AN;aM+gdlObP0l+XkKp(P%< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/evil_wizard_1.png b/src/main/resources/assets/wizardry/textures/entity/evil_wizard_1.png new file mode 100644 index 0000000000000000000000000000000000000000..23f919351b38d4825af4a658dbf4ee688304a584 GIT binary patch literal 1639 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9;U>dXhRZMQ zE?NMQuIvw4*?BCiUzb*XWnf_a;_2cTl5y{7 zL~MpgxX8bEZ{EC{(R*@PuR^J`_Qi&4^1l-5dpcZRIx}5r|8>be;Ma;N5z)T_IzqUd z4qiHDHznxuGy#ntLf%0dZo;>=GRj{$;_5Tiq||lkqUcMWX`6Nz|2C+8e{ZL?z4h*k zauLtY*`~j{_xbzXVm(KOyC-}uzqzBsps=+}R_oZz!t?pPbNc4_?^kpDZ)jFEZP~ST z%nT{d(|+Enb+0~oxBb6G%Ke)+n7e~Cj>K(yf9N~kzaLLE*IanS(BOKwrS6$_#z~f* zIefY^56t8DvwCv1p*K|H%)A^qhGomw@2cDX@aESQ({9{aG%;IonT_;o#!p!nn)0}; zE0%J+@c;kvf$X~)y*Kwb8RT+n-K#lYEpa_uQgQ!8=q%@t(Fy+F?c7-m{7=3N(0}{# zo_oty&%Ivl3oi&NNH2=JwR5E`!-tF2?S+rJ>lhB0tJ^8Aye6iX{EWN9{q5Q~{WO`+ z_J6V?J8{QOFo>`QTRx#mx_w#KU+WV{5zHjH`5qIg~m@0MBCA8+~>EcIj^%mb0)7sb> z8FJU^TKs=n_~+N-?H^VN+}&{at;E;E%#y-4tRL?@+0j+Gbjg|Uy=LXbFGT)lxVua1 zo%_Q&rDsB|MZc_UuE8bc6KQW)gYUBc(0te?ohNbVNfzsYtVIX-XKzV4F+_kzH*|{K=udt-vx`GQroK;%>=29f{ge&tO$X}h;_^AXJu zlZ3ov{e4;24+mB|JJn?{+|M~Ky_cckayvg01K+p#&*ZLHRiC=ABD|ycpU}0E+~*e; zs0s%NY<=3QAvnK|>)zh7+?$8vo@mD%IB28N_Uhoj%Y09FGO3=Iww$XS|8e=tiRxk6 z9WSMis3*^teJFi-66Y6Q9_v?3JLTiA?zyym&#f6zzVY>ytF_;sc_Okd{XJ`0>tu7S zjSsKZs((CvQ(0oajqBfEe~S-)|M_pr3a;)T9nmg7W|vTjrHeyXK6|m^D)*c1b5y?n zHo7}+e|+Dg8b&U~j+KHLfue?{hn~+=4EfpCQks5RuxU}?VTnbxrP}iMcYRj~*}wnc zO4Arm-BpkJ+siMA_%E=$_M)TVcNO3E=cOzBwbZ9;?-Jv^eD(99>qkF6xLVB6uzlOx z(i0miHx&n4i)QC;kGiuu%=|N}j)XVgPd43Ssb^~#FM6_H(tDW;mqq@`t{$rqdgzAdgyL7(+&{pQGJmXx$@Z& zF8`kyn(V2S%eJg`fBokB>V1N%w%!t&Drg&Vv2^OQ!zZG}*6zN4f9v;TjjpJVyh}}f z_!*qZ?Ta>7Z>tYTKmJU&J4|$omO?X!@XT3dMdbvd7;-*apMV~x66!~W9mYSHVyFXiB ze&1<4WykA?gTe}do*M-wHBM!W58!Hf`Tg^>ll5;*1pHh6GxV-$Td1|BZ!!Y|1B0il KpUXO@geCy}%p0Tt literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/evil_wizard_2.png b/src/main/resources/assets/wizardry/textures/entity/evil_wizard_2.png new file mode 100644 index 0000000000000000000000000000000000000000..c98d79032ff6ac3eb1cb2e0d3ce5bfc16f219241 GIT binary patch literal 1725 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9;U>dXhRZMQ zE?NMQuIvw4*?BCCpRW6OoPmMO%hSa%B;(%E zi0B-VP>FwOW!tRZPJ0=4yJM4{$qly&-Uc5Jxi&kv+-`AE)_3z&*f+z&hf_-4r%Os$ zNVsR4orH3SqOVWIh8e9#3N#-maq_pEZVNC7xXH!Qcxuz_ndjcg$d{deX}P)h=1tun z>XU7Y|J9$H_y616|Mo&PFPwhqoa~8XV>pstz94CiT-o0+`SS~(cfVKJ|KDOqzJBNV zcMJ?EZu*w4aQ?GyWq*RzW$PFQ+rQ*C=W=bwkc=@(YGF)#@4YP>Tqf8nu3 z7mgPPBnPhfSFl@Q{g0eAPKm#~pEEvqbMtcF{c^j1EUQ#^ndLu;>d^8(ZYf`RG~ZFZ zl{LwCGThJq?bEe=tC8ek9R(r1+^;o; zx@Z3X`YoR%;VD#-JZbOq>Ff0WPP^Z~rhfiM4#j_LAB>KaNFFrc)_GHT^sk0c*n-zq z)#0I{Edn!Gg?S&gX&UIAw)i+T>%d9wEgEcBCVUn>b;W7bDlWGT?#=2iJc3F!6YS@` zxfj2qV59PZKl5EUKAJE*^=AM6R`qJz{^%RGpEoaYzdtRm^L$}7S4!Sp!GZ;QQ`-*I zmtQR|mGoLBx2^h)-LgOfqb;+~etvGIpIu)beVEk=zH&Y4@@v8GIEZWMHU>f+K)i+Bg%BykW z!Sxd)_wv|IZJFoAH7zJPFvImGdqt$mgkCD_h?Gzv;Dl zyWzsKEn?Y6mmXw%vbF5RN|h-t;(c?y>b2ZWC;W+JXt;JoBj-cjzLF!Yw;oSeEcHyM zM#{JU$j!?uqnc_Q&1H}0)hrF+Z(q24l2hFZ20dOrhuC|~>&&Ye8LZ86Sr~HO+&^fu zLht>|Uut4UZ!DZVW9utPG2Sd4F3E?JY{XUn=!Xh0$i;1Nxbb0Y@$+T2Zz}h_VUwxS zIyq(W!d)Bd+ZWgbFNooJ`Pgz<&C&VGCh@NcdvN)BzrO6BBIDaLq`DX7Kc5gFe&hGY zZ_^~_J-xc;htH>DpSxu$tNrF2{CTGI{<;rGTD@{AD({y4*;a1c=08_4?(e_Gh0;0o zSrLt{9BSOI7a0;+tA1uoU2SQV^_8i1+2l8W_sw0Gmha=bF|t9&Gb6w$;4qie6oJ{x z+XCL0t8B5J-6!y*SL%pBar(B6ALn1sXMOeET7K5iDItfs^zO+ui*+tqx-hb%L3(Fl z%-LrPY*x&fv+l*L3%u^9K07|q?Y?sN{r(-#gimY=`pBzzvo5TP7GnR z->0L!bl?6zEc=9)Ty!ivu+Q?hOuzV)Gf9Gim0suevE?gNi=6mf?; zcK!8=#rFdx_n+YM>beq880giz=z`gn3ggGMg%2*RyJuM!@je=E)zu&73*n^-o*v{-lFow7}SdR}>*gTe~DWM4fRvkEb literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/evil_wizard_3.png b/src/main/resources/assets/wizardry/textures/entity/evil_wizard_3.png new file mode 100644 index 0000000000000000000000000000000000000000..8cb1fb91405985bbe7d3b5ca1741b9bb14da9b1b GIT binary patch literal 1674 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9;U>dXhRZMQ zE?NMQuIvw4`9;;trXTBSXJB9x_jGX#$+&kk zB057PT;kukH)r0xIC6HGn&Qe#jU3aAJxiMQdTDEkY5fSfzeVB43SExYAg*6Qf?Ret zzBy{_O<1tN?h1FW$Xc$opTZ{95X)}DBN z&j0zFpYN}I{-58GITg+3GA;p8dG-epIEfw7s>*qJNJM+_T-Xbge9d zfzh1D+4ApfU5b+bSESsJ-y_JkG@xVmn|GVxBo-y^Z?zBTV0i}JNZEnPm920m0_1DHtVr8iL^UyEn?lxYAf`?Z; zFI~KIB=wDxpyt`TuiggjPycsh{r>7}$}I;rE&uuZ$?Ms7?|=IJ^Q^T+e~?segMssz zX@YN@CbrieUpYCne)^@5h-pXfm&UR$6=_Xk^whOvK9(wJzb}f{qP0=%aKjGE_se~B zm%QF}oTJF3MNo0cE|CfS>NkI%p0@S_>x}=CHI^=9OQ1VrIKEWa?@<}`Xfa$%JV-~e!L@=`tn;i7dJP_W|Z1mByIVe|D~sqegB_E*6i?)84kx9n0Og3SXnW2pXJ`4$n`Am z-kh%+#D97T6d3S#F1)olb@%F;%0A5lQAyhQMNgmFpPjWcJxsgfrSwttbi4aU&6lO~ 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/evil_wizard_5.png b/src/main/resources/assets/wizardry/textures/entity/evil_wizard_5.png new file mode 100644 index 0000000000000000000000000000000000000000..18f4223efcfc7ea42c926533e111a39bdd2985cb GIT binary patch literal 1663 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9;U>dXhRZMQ zE?NMQuIvw4*?Fu??S7jTFfg$3c)B=-WZXL% z5uG6tF7Yp|EUo;^k+aLx6jx?y5M(&3@#gRH@d7=*j&TTKeb7ez}|9!`?PHbEKS%{dVDJzU?3G>unocycrqNe7TRU)L)odGJ};l z%I)~I{=Uj5Q#bU^{r%CTZGHS#4WIgziVP2)ot55qe|^P6)e!HJ+*c6a z&2qGFt&~%{!|~(K_WibdzTdAge0NWkLFbm=x369+Ca3wHeq6gbAd}BBr*ZB3cVAj; zzD}9J_w^FHy!^BsTbEW%?Q`C!>|o-ucS~id7{i6zmz($g{>I3_R{zWKRZeD_(X?0> zuhQ*R%T3-(DqX|)?7xbW#|lP`c&oZ61}n|}G#`qa(?3~G{dbkB-SML$619JhG&8UD z^|t-Vgz8(tI^`Yd+XTR!{j=jUen+WXko%C~Wfh*$J{uyFE*{^z?l>n)oGN$|2m_cvsY{i}jfdFS`%>Je!|-H)FO0BST8> zsacK7x?cRuDtr_v$-yvXTc=={N~7K zjCltyr{48=zAov`xy8P$*H#1@FlMCtDep}cE~;X`wjy|jrbt2f`=p6eFI!JA{dD4` ztjCrzCI+v^ix)~SEjoQ|ov6jpF19oIGDpJiR7I59o`2pxFKxE#HP>6OYvUOi%--GP z-?CFq=DPI_^C-9DhvWYp_@p~K!bD-Qa~l^!#%zg3&*wYu8?b)fo~K)J<8zHAhsBEa z9|3oFr0-u{Q`x8G5S_F+!Qkmp`?FF%T~~|#_|p5x`+1*Siu7e8E55H^s$Vf}l+VwN zl8TC3`zl9$cU<)Q)7GVx9OZ7um3ALGtz53Hw*9?L+kAidBdyuaDr@fB-~Qk6)<0O( zq9tKn#3w0-(1dCIVLN9nUL2->Azjh)&3D%-gTEPe$KNWYcsd1nIs}WVOl6t9ye;5} zw9u`&x-J}_+7p=We-D$Kk92^T zwz|01t~B4%*FW#M{&vt*V8$OxFLpZi$hcv5fbgh|hz9x<(8?hI7muW4qpdvt1lag3_?vFS^mGcRry zcqGqQ`0HcVo}7OTA8GGLZk3^?Kk79lg4br(T#FKc{ZKrL*79zEmBik6xczCvdD0`LQTS!Eb-QwOI9w f%mec|{xe>=*5s;qo-c)gfq}u()z4*}Q$iB}HXa8L literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/fire_sigil.png b/src/main/resources/assets/wizardry/textures/entity/fire_sigil.png new file mode 100644 index 0000000000000000000000000000000000000000..d899e25394ebd79635de334bcfad32ba601284d0 GIT binary patch literal 2116 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}>KGVuJuFu; zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL-|xmg9-q;BQ~9b#Z$zv$`W7!q-K>-5~5 zkmI6l^Jnhe{cYXG$7_2P*tRt?Y}_lRbVG9?(?(Uz6`Wf_oxB5XcxcotQx)K`aPaks zF`Z$d$l4;TGHHt+vyg{l;Vi9&sE*8L1)(YOs)0-X8OZD2I5&&`{jGbui+?4ri~M|b z!HT_?GTh6{&h05bXZgOeKPx*s`ACQ09NX$?9x6_!|2VgJofDKQo9B6cExUumM`M%! zF3fcY{LT6Fq!`$p<@6@7UFtcsL42{pkGA8TE=pUrZY_MV(V%+Sd`AoZ8*7CSS713~R=K_kXIy7}C!Fe!^?* z9(S@bZQth=e;*aIoDf*l&ZN-eE#ayt&HOvSF2IgkjL~p|qNVgg?sk?53e&ZJco@yu zXMMMWDI+`k@q^^VPhRH?pF7M{YU{5TJfhf>X5b`P+US2_=Y!LY;0-KeEjLfP-p$I^hkr};jUoQ1EEr0WfMFPt>3lm!E+f+t9*8+ul_8X+O@kr z820q;bia9Fv&e_V0{1F1q)+>=VPfKNEIYS`m9;zSRp62ayKVltDK{ska&UQkJ~ct@ zTI?L3w$CTlDzGtq_{gBRK%!kJj!$-}ndI`q9AiH_i{=N@-RH4idNb>G3tvjI14GP= z|JK~!&K}?XsLXkp^tAaMn^!KGxm8^4aS`K-2i}voj3UKdlxBH8DQG?D&@#Pw?UiMZ zG-7z_Om=eE-Rm=d$bIn7_B6#E68hXGY^{giPv4$U^>C*7^hGBUUN}y6E4X2@X6DxC z%NcS-E}TpMqGiCL(fQCr(>2Iz>6@?JQ#QNU)j2Hb*&#DiFX)_&<-au^QzU~Nr-l^l zxAEw7k<K z=9_hysd>&aiXHnI4&=xFe6M5@f7x5;gu;W#A4R+*g;V0!c}RLMos;_M`HZ>p@d`qz zn|hL$_$+bI`pBK}vPZE~{>DW~X9sW9x|tr0J;_U4X6n?h-)Q#FDtgJB)SzQQnUab@ z$5<^YjJ#R=Y98lU&CWx8Zhx!{G0 zOH*~uuM38u7rHiFiB+Gx;YwrJ1;bDapSEfbL8Zn;mv>Du>5dNDm>k7yB`(r>K;gi7 z-|PG1_f?<;u9%s$w(ZHbe)c3=4B&+1z<=Cj^ek)IMxFZ5ngm}dLMxAf#} zEr-wht4&Tg{H{9C|w%*-Z!HdMr!Z}q#3<>~M0* zKg0HH!r`vf8ZjnP%xv>ASEWA}Ue8$B5y87q(3eBp`Ba#(QwO6fSF*#y2LhjrTw8r* zHC!XEM#pFKMoqp@+7h}q*0}WV^_RyLTMm89S!y6z-F9?}Qp@SD8NHvD)QAXL2B-%4 zZJn~&#V@QoBtUhlNHxonC5KP9eA5y4*!_Lo;m1v0e}X(Wh6Jdln?+0MEswIRjd}9m zyUQY*oAYCDb$`g_h@D}g^M6m9>}4rN`(^AcN|Rc4`b?0p>+09&Nnt+6?bGA%Q84o{OzABuil^6b>1XGT3sw< z?U}eyq&kn=gU3C|LP%9% zYDfyOc&% z#qXDC^M3ixx%)c$Vvo{++Al@=j9r=E-5QeK->uDX+n8Uh?Z2k$^Sw=JBDOoiZD-$o zaLH3X{Dfky?N8P`5ta2*wtRZj8qIq0-7K}5$`4oCZgWrCyMEh*myPqU-_!Eg){~v~ z^kp>5$+@bL&QCP5Z#~MHf2k*!;a^QfS^w0O_vbmPBt9;~BsuI51zguUxGxp_< zdp-A7n%=g_l0UU^Q_R>;>h`tD4> j_seGdv%mfMKLby%&xHk>o8lQ57#KWV{an^LB{Ts5K1axU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/firebolt.png b/src/main/resources/assets/wizardry/textures/entity/firebolt.png new file mode 100644 index 0000000000000000000000000000000000000000..313161076d8ab8fe4740a1aa3a401828f120e790 GIT binary patch literal 255 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 S&YppRfx*+&&t;ucLK6Vm$y;6k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/frost_sigil.png b/src/main/resources/assets/wizardry/textures/entity/frost_sigil.png new file mode 100644 index 0000000000000000000000000000000000000000..9718612cdf5be24f60e20201192e42768c5ab506 GIT binary patch literal 2199 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 ZKl5AGgsw)fJ{3^I!qe5yWt~$(695eY65Rj* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/healing_aura.png b/src/main/resources/assets/wizardry/textures/entity/healing_aura.png new file mode 100644 index 0000000000000000000000000000000000000000..db683f9fe7af6e9a68c0bec33416e71fd733c57d GIT binary patch literal 3819 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/ice_charge.png b/src/main/resources/assets/wizardry/textures/entity/ice_charge.png new file mode 100644 index 0000000000000000000000000000000000000000..0c44b04788a5d9d41d64a2d53bf4881f901239b4 GIT binary patch literal 516 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|q%knm*PaH6 za29w(7Bet#3xhBt!>l-|Z19V z+76Wk;+1E=o>8qV&Ti&{jbqTuPpK%(SalJ25o&W0k9_jf{CfUvUpmD=2eY>8#k=WwQD;HTJ zMc%c#M_v`QJ$byxb*JjaWhG_1Chh#)aDwIV_4ZB6N*>MCYhU*uU4}2Vkwe8jv3;+! z`k(U)?o3Jv{2_WJbIGKf+W)71<@8NjsmOHl=2~yB%bpfZS-%y3@%v@hGk9cLP4@22 ziT|V4-K1zEwNj;SZJYi4gInKbG=Do{!M&-OL#6m%!nLN{$^Ow2hm;?3@I17Qf1I~e zBuuLG(yTsVk58H04f?hxSFL({M3mv4zt3@{=nsdF*I$S>KG_(&%r-gUij<6jMDnjE zf1bMjdUIo;r1WE(g-K%TKRh>{aa8-)Sx0B-)7l%wdE0LN+4esr(e2>%#ru~Q?_T~d TJZJ?20|SGntDnm{r-UW|=TzX# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/ice_giant.png b/src/main/resources/assets/wizardry/textures/entity/ice_giant.png new file mode 100644 index 0000000000000000000000000000000000000000..bd6ef77a4731557e80b5f143314692b6ec5ffc6b GIT binary patch literal 13984 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/ice_lance.png b/src/main/resources/assets/wizardry/textures/entity/ice_lance.png new file mode 100644 index 0000000000000000000000000000000000000000..7013c0606f46586557d908db18a20dbb52ce0799 GIT binary patch literal 551 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}&M-I`I~Zp( zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KnM6f|g<3bQwP9dj+~Vot7!q;#?Udbl z!j2*i=g-*9iLFj%Rf(G>&vl!WiIJ}__EG$C@|^W#q^xgJk`$X>Bmg8$%p(akw$jW}nX*XvMK zD9SFGS{%sfDI&CH+ng``mKPOMq+>)D?QOW;99%k~vEPEBNkbq%`ckOW`ZYW5dT)51 zzDCdd&8wyj^8=n*CQ3YZYF#6%^NeL~U)AR)FCVh~`_ou{f8VCFvZuaxZs`|kt+=av zXI(EWU$`bEcEEi(-v>#lqh7ObTMIVLYT30Lufv5GKxeX1yr1FdgVpPP?MRcKva8Y2S(<9tsS$B>A_Z>QLI3p+}* z&*zjDSpUJn($?wQ`R@Ww8#Y`z9Jar+wP5SiuLm3D9|~;Tz_F5r|D6_hqIg=mVrSfm zr<MSC^Z?fHAGJAJ{ewAWh%U_fyv;Q!P|GI zcP@F8#;R;~XTJWOLDgHHc+wMi$=wr5 zcm-EJy&D#J_ z*M80St@!eVFJVbcYX-%wr>mdKI;Vst0MRqzi~s-t literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/ice_spike.png b/src/main/resources/assets/wizardry/textures/entity/ice_spike.png new file mode 100644 index 0000000000000000000000000000000000000000..24a7e5e3b53e7cc60ecfce418b3688bb62b99914 GIT binary patch literal 446 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^OPm&M{nlmhq8= zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_$SNu*!Yx(Ydw_v~K{hiaqQp5rH#aq} zgaHJci&7IyQd1PlGfOfQ+&z5*QuI>U85kIqJY5_^EKbjzblU51fCv-PKDHEmd>y>8D1 zZtH|&1x2@iO#RQmX`0=0TH#3NrVjguEBHfq&TcYSI2a*f>AAMVxPK0>LyEZryK{)< z;t3zaouWi$=qJw2<^Q-W=61xCspnsau>SkPl5YCRXn9fJ#m`5Qf+ah$*?aWt~$(69CKNu#x}( literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/ice_wraith.png b/src/main/resources/assets/wizardry/textures/entity/ice_wraith.png new file mode 100644 index 0000000000000000000000000000000000000000..0aa87596a68cfd0119200d197da8180b9ae09a44 GIT binary patch literal 3276 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 W|2F8<=QDYr#)PMo@i)bHuy7!q-~H~i+L z+Xg($SN{F~zAby@i{}0Sg_oXbWwP2<6%8ydo=gm9IM0;+Tg&Rh_*s5KNv*g6qYqQ} z0mcO0guc&}JPCi9p5_xSslyAA2eY>P9JdD@EZpZ#{pcJAJK=Bw&*D=gLtNV3h( zu{<5?|9{7M$(I7L|1&ao#wLAvY~+%tr!Sp*>+`C=mJM1hi4Ix}No|HlLVxRNmGv^p zy*Rh;?u|z$wZG)_BpqVlZIJsgu}wsH<(^q5D)%2;Vb!6Tv69QBJ9^FBh@w+7k_EH1 zxBe~{U8!l{pl!?jee*19j+uh*#WwmgmR-<1GB=})PcoG)ev?CKn_KR>uZ)qqlOLvY zOqtd6s9e)PT;jD`ncl>x#Ne&{iDq^e+74JP3|Zj);=1`<*J=ZICW+ZozfAdXdEUgr zThHdJvVFPv&Wl-Gy0g~`bpAS!%DP#>@WRSd zD|QKab|fDZ7B%j333tuE$?)qz({4Ef_mCTFoJ@OfdG0+d*(fX9@Mn?a#nT2`{j+z= z`S0?3vw5j`n@`Myfcq=BEI(^>3x8vpYRUR$Y0vZU)-Q_tvpo)`J@lQndNr4s+d_ej zJL_FvC7f@&73{D)BfYdOHk)@wiNo2psUrFrJX)XPIIq_{4%%b=Bur*$>BT*voWBk9 z?}*;K8RwAwrjt|a#>#0A^S*BAexrAw-(Jm0S=Rli{im;8zQ=hBm)LE2Tl1kT(06*m b1N%<){Kcyj4*g|dU|{fc^>bP0l+XkKp$$~m literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/lightning_arrow.png b/src/main/resources/assets/wizardry/textures/entity/lightning_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..74e34f7ebac0a4bbb618e2420f93b480e2043ff7 GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(~Ds(|LD20|NtR zfk$L90|U1(2s1Lwnj^u$z`$PO>FdgVpPP?Ml_QvEel-IFqoJpZV@Sl|w^Izg4?D=X z-`^@)GNGZPBO@b+-QFQQ-2I@Vh_@qC>|edP%m*JS?C9$DK5^~f#^%SWq9R${OJk2L zs~2D0yyM1$h0lD=W$yGJ|0p89slm0+POS2pWb#CH_d_jA%tG%f5)TL``&}{C3|3g^ z)Nh%vIIVcsX0GV&0_&F7>=xY?X>w<|Y!~nfv?=yIPPqN;40Fg@RioN1o4))!B?2HKGg71v+auV{&ST_5GN)>P@x(?DU60TrB!HI$S=;4sVjQ}HLV#8vIOK%wpF L>gTe~DWM4fYuuq@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/lightning_hammer.png b/src/main/resources/assets/wizardry/textures/entity/lightning_hammer.png new file mode 100644 index 0000000000000000000000000000000000000000..740c072437a2ab93b52c3a7b7835eb914ddb97f1 GIT binary patch literal 4603 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 Uzq&B8Tm*4FUHx3vIVCg!0752LDF6Tf literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_1.png b/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_1.png new file mode 100644 index 0000000000000000000000000000000000000000..b39de9ba80d9b446e2e6d23c54b1e796b168febd GIT binary patch literal 1779 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+*pj^6T^Q~&{AT#_arw`~ z3=9mM1s;*b3=G`DAk4@xYmNj10|R@Br>`sfLsl_iO)cHS>lQFDFvwqluIeb2GM_zMw!%bc_Ob?# z^kZ9_TC_xVYJ?;mboR_u?|p3ZY=gx4A5+5uv`pvynICdhN`0cu^E=h&_ZIUA2$BLW zDlg#sBYWYig4f;S7x(RI@mNxE!ERq!LX%B)%YxSjmwi8F`&WoNTI2hd>hF*1?9a1g zIBs>kR{Zr~sI~0X|3`oR4EkQ!*{VBbSNp=}O+F3Ny!P+=fLNm&QR~0Q z{i;?syv47(G9=9>=^^J7?!R^W{Qvnfl#Api#w=Rc;uX30#CqLFg>N+(4!pZ&d?V)X zf$Dts%PB8RnWOKnPyYR0Am?R5=Z#m!4wtO7m7126icLNp%g}J8_u#3m`YtXXdJEYm ze~#_FKKJ@F4z=gID~zMB_L!))&Ykq@m%4A~LTUGjCidUg`RnevDN-XZ z*3Njp=UY*_eMofat!W3WObVC%Zpf{^u3YPSCgL;$gYUlL*Z2Orr@IXb7hbzb8TB+XzRvu|4?Vla$CD=l4NtPesyE@qRonmatUsX z41dGey|fPtar;}Cy1iC+IAG3sVc)JL&(4%5WaoREOj&XI(-KPth0pJs<0Ivy(wltO zh9^C2@k%|mVRNytZ2RW5`-C(8vJ^CLxq6Lp;&WB0Upq3{GVHf}*-$3#Cwswo?{mLK z&JQoPH+*GWC3%+LYV{Ivze?ick}{UvJxMZAnV{`WhWiZyM!rhRd;_*K#11<#lLF%sUg zE>ii4?IGXj=PoW2ww+5{_pI<;v(2%ub?V|JSv{xrpZuw}{=7nIvViWrkjuYh9pA3@ z*2?5daQ9A(UdzC+?bf=)7gsBfuzxl+ZfOnr{_(%X*JzEkJkI;CKD;7%%B{wLUwZpo z&1K8_CwL!F7U~pXJehRu&Gd*LduDBOD=b%jJ@?7Z)&&f}NV>!D+_ zFlgrT31-vwGHr;_sA5&Le*HaAcfu~i4#{ke%*Q5|j%DVrD!aX}AfRQE#S+xg85Ul?z%KK|ryV|Qt5!Yv8+e={YIRDb@S`zj-gKir|l zpnqlSY(K|LKPN@?i<8AeFUcHeU)Uqh*ZSwOXiSu)-h2L-kd}{yG7~1v+V^kT=Cxmr zcP^+GI-twOU9SJ|+(h|3O&4;1U;4V>`(K8M^9Ab{M{MuyX%ou2wnyP&z@m4%87A&i z;*!3smDzVN9_-xy)oB;Dv+O_}l z3N9bZd|%BR%$;Age)6-94vw_m3HRRz9oR3wHfV_@yOpq3W?zE&hqYd*b(1qHoR)6h zpLF})hgU6IKP~!YRm?Qk|9_Kx{q>Mbe>mT+_V!`eFVcQAXkA$}JHw9Xb5)N0`-51P zq-Co|?zjDYzj%hsoTm$f&fNO<|Nk8guYarfJ4ga@GwT_?Jvw6Ad;Og`sP6G}^>bP0 Hl+XkK)Db^_ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_2.png b/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_2.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e821e0d97ba9718ac517f393b0393e39701a22 GIT binary patch literal 2584 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 C+XDXp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_4.png b/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_4.png new file mode 100644 index 0000000000000000000000000000000000000000..8dd2d0115cca1935a132e90ee566d63b4a4c8cc2 GIT binary patch literal 5044 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_5.png b/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_5.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba2a22052888e38f3821a4dd23d06b5d0d4d590 GIT binary patch literal 6073 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 PM$kQ7{an^LB{Ts52-=KU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_6.png b/src/main/resources/assets/wizardry/textures/entity/lightning_pulse_6.png new file mode 100644 index 0000000000000000000000000000000000000000..460091e743602f474793e7f2f032ce5d550bb685 GIT binary patch literal 4628 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/lightning_sigil.png b/src/main/resources/assets/wizardry/textures/entity/lightning_sigil.png new file mode 100644 index 0000000000000000000000000000000000000000..2ce06d2b82deba9d02139ff3c2fd3b67f6fd7753 GIT binary patch literal 2675 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 ASpWb4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/magic_missile.png b/src/main/resources/assets/wizardry/textures/entity/magic_missile.png new file mode 100644 index 0000000000000000000000000000000000000000..ead49d45feea5247267bfcfcc9835796747d4724 GIT binary patch literal 863 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)2UEx*7DJwkCaI zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifvdReRFmYNO6J=mvdgJNh7!q;#?KEEx zkwl5(^~Rg!cWm{YHf`G4WO;>|5)l!O7Z+-9b>_J`w)5RxJ_zG*P zF3V)PaNX+2?)Ltf5_#w2{`>yF^?$ku!)24ovL#cT&F?RkmYP;@ftNSFU{2(2CU1+7 zw|QsmuH3!r>+8$=DuU8Pw#NWae}{`^2=cJ+%r7bb6K zo_LS3#F<&+%~l_t?aA)!vESdkNGQ{~^U65e+REd3t6X00=FfKFXL}yLel8nv=w#-h zKE5Q*_N`ylpWTg*u2+hd*I0d2i0`3U>-o7~D{u2Z;B0kb@X!ntQB7ZWIG1a;p4l$D zm^k^zXTN%t&AET1f2GF1gsxr2^Iyoko;jWULBDUMQTN4*f!CY%tKQlF$Dnqt^O>68 z4ws5NZpj_`Zl-sFF_fcm%A^u2-zDV?3i(2ARqQLQbv=Fh7D!8#E?2$E-X=bUk=232 zvGcCG);?8zp|aA_jaze)n!_eI;W zBL&v7>hFto?`*C8eLuZ;fB*F0L5z^!^9dVLLRDWz$|rbT{T}4mW1iZ)T|-3N=@3uNv`5KPoXyOoc1<)8 z-eZ5U_+avl`mgNM3S#)nl^@=Dpxe1*%DUqHH|*!_QEgeUVo{gYsuhd=wbwC9SsqRP UW>J>Lz`(%Z>FVdQ&MBb@05v^)@c;k- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/phoenix.png b/src/main/resources/assets/wizardry/textures/entity/phoenix.png new file mode 100644 index 0000000000000000000000000000000000000000..3451a1627f5c260ebb78b8b521448a48b19563d4 GIT binary patch literal 4574 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 F0sx63CtCmj literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/pointer.png b/src/main/resources/assets/wizardry/textures/entity/pointer.png new file mode 100644 index 0000000000000000000000000000000000000000..281feff41c770f59998aca4406ff233ebef9e6d8 GIT binary patch literal 808 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/rune.png b/src/main/resources/assets/wizardry/textures/entity/rune.png new file mode 100644 index 0000000000000000000000000000000000000000..2d16b3e09892a169dcb71616f424900e9e773d83 GIT binary patch literal 2240 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 WtdrlGBg4SJz~JfX=d#Wzp$Py8om+|k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/sixth_sense.png b/src/main/resources/assets/wizardry/textures/entity/sixth_sense.png new file mode 100644 index 0000000000000000000000000000000000000000..5187f19e9284dd58d9b0d3e782dfa317bb52b696 GIT binary patch literal 1023 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4%caKYZ?lNlHo zI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_J>SN+$?ILV0FMhJw4NZ$OG(Dmw!MbF!z4V@Sl|x6}9b-!T(7TCdzWsqFi^YoP^( zJkkZbL^PX1e%%gUUG(r0V~~U%&trij+qd6}tzC1%#5vjN{k^ApjF%z~H2hZlWV=tX zz5m18pY!D_bK1>3I4u@17|9-HHZEW}=62}MeBq2{okrFG#-&0hgqeg5m~1!XtMvSz z)o|{IP=sb<6sN^vhYL5|nb;HfOAc(CC@{~(A-#4fi(bQ0p%qgc^5W*3u(94}j_%#< zcIb-+Q|<)O4Pi{#svC?lH?XW>+N-r8l+{dXdv8l}SMVIh^(EJ`AI#hq$U3{p#`9o? zNP$%0qP=zoo7H0~sy}11t&mts(8R#w|7O0NE@r#4-{HcClj-~w{_Wpw zC+D1e%I5FRF`skO;}_e{TuQuu{XkE9=6)pu^+FRv#>WTRH=VyXakI*gnK3f%Hw}LD z^W1zd^Hcf7?v3|zZb|%;VdOTO$t0wG=i!O@smEtuG7dVat)esIux{@`R8{& a*Y8wZy+Y1m-y8-81_n=8KbLh*2~7Z56T_PT literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/spark.png b/src/main/resources/assets/wizardry/textures/entity/spark.png new file mode 100644 index 0000000000000000000000000000000000000000..130ac30ca2bb99f86cf273f85ea9fea3c609149e GIT binary patch literal 855 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lLV0FMhJw4NZ$OG(Dmw!M({4`}#}JFtxs#)_V?r5P_wPM#xA}bTyOTaM zIDNa`URF5D70R-35l8J8eXsv5u6q<7v4-eqeqE}RJ1cFHpSq{I@$)yU{clx8`ez@E zdi_@Tk9YL_<7>=3b7yfhoKrZj#JTR%+HbF(9D62T`?2cAUj2{P{CgC4?{R5wI9ps3 znbdl~s@*V5XZriSw^r;w^F@8X?nDh=cMi8>32Rh6g*Jsbit-I_T% z|Lk7Ws~0*>@^Z^O<)Zn?`u3imr{^3^e2{uCF(qt{8ShL(jhQF9znK?({Ped$XJ5xH z$^EZomTvXArMY*l*RVp2@*JU?uc9`o$qsdu%FMT(h8UpOxa zHmwo9xi4(fcZ;PbnSV1M|KQbq?I7#%U5CFGoI9A{a6M{ORj#|y#EBA}#{xnozB{Pt z7ya#2Q|-p{Th|O(vw4bh@`iKGU4~3Y1TIw0|F>kp^Xw-1;yZ08b04sMxVm2EHg9QYfryBm z??*DdD(FDQA>VtZiBYD%QcT**5rSsY<8X7&3<0NkDO-TDRZqR?*6b8;j3`Yd^bolKnORBWU;DR4P8iG02>#uBDcd+_I$(tzs^Lsz8J?nmH&%OV`cb2%{elx7#Q6>T^vI!P9L4L- z;<&wBU+fq8JyITr0|oS|1X+38odhN(RG-s*%j;_z<9Ol1g$My(U3cdYXZvX!qMo_| zoV`;t-WjxB$nJ14^v(Ei^WOKLb@FyL=f!`;_UYN~7GHbiUyTC3%%p@%$8S5&+5NivT=)(f(~b-&ue(kwqjT22 z|B$uJU@6nHgLVFv8&apUHyrKtW#~C>@qTyp6|GdaHd}j^zCLD#l?*8T* r+k&4hvFv}Q9awkee_zr6*W4yH#jBT|)0)V@z`)??>gTe~DWM4fCls)E literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/spirit_horse.png b/src/main/resources/assets/wizardry/textures/entity/spirit_horse.png new file mode 100644 index 0000000000000000000000000000000000000000..c633c008986fb9fcff8c0f89acf680b7f0cf2ae8 GIT binary patch literal 10374 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%0D@ z{FSqn$@t&t9LOcnC#x5E{l}d(*-PiW4!FH`NnGhMm9uG|ITpUL`8uoFYR+E61I+yO za_jf}khWUz`QZ75*Xu<0-qSiakDYJ+AIXq(|J&!U$7hS4i1}~*xpE$-&y)fKfsUQ; zE+x6EE)`Mfj%RD6^`HLey1Pz1S0!>=T9@ag2R|-us+DzRa_qg?bd|Yy z-rZH#ZWUgee4zbtz@6gqn{DT(hbhTKeRx=%^U9|C^kPwYHzxJIspdA#vc?PxcdGOy z@P(e*xUEF&Zy9f|v%J%+FGVeK`^`FUc}$jTdeCug+2q3TcLrB}hwPrbAm&lBpZH|! zgd;_hUU{U<N7I43)c2Uem`bs>=8US@7haMGq;3G=d1pTBz`-5{O;z(LI#IfPKudw zv{mdr8h6ZJnQ3WN_lbJDw^57t=a`<~lKt%{4@<*>q7>$Z%Wr+Zy(3Jkb!Qv5V#(>-+U>M840o3%-{F5y(4-Pt z@$k(my)^<{&1>59ds=#3uC3ymSD(03v&CuWk&lb{&-U5w+1s~&?xZJWXEv)cuhIMW zFxPj}7n`o_V$M8lOo=+jqBdE?WFP#x#_Pn42G3QT_MFS^N++`fE?Q9ZY{Bb*voX#S zbL~&=>)(HOQpW!0H$RGPxZk1FS?1nd>*gNmcFZ|^y`{8_t{c~r|JQCG*0>m=y@aJj z$lHY>An5uJ;U?a-37@*2#vOaVTxI87p-gw40_!HnT}Suu?OC$YX{pUAJF{E+IqyhZ z_TRpM@sP)%^M68c<_3e&(BkfYdCI{2%ZjCdHR^KoavkQq&Lf5Ze33Z z5ZWpj(id_5UfRJ0nb)5kjov*uN5j)?{8*7fy|PeuH?A-?a! z>W;&qJL;Gj3jS{WzvX4u{kK29PD-hf+nPAzb-emE z`wMe+9%E;= z>an*iz9`<=^^s}Pj^8t z`n&t?ePq7*_=k1ryi5i6_rEhfuiITOH2vIM$DMWje6s(&XB9{)_UHfCH;HlY!}?`ym@MO z#wNb<*Vbosch2vtX7X)lw-%NDa`Wxh#`6NH{3lczLr%$Xv)9bsCCa^<_r~MPZWmi( z7I-{dS^wR3ikADtW3dKu4FX+HxBoMj_7b7a;fT-e)W^0t5O?d{ipZ`gHJTmSv(zi+Cz zEB^N8T`nz^tC_UbXL?ZY)fes)&pj|~cY7MUeV%)+B8Msq`!gGr&Mixm)fQhpv)}P_ zsbnU zoZ_ZqYrfBW<#+7u#)6FpiqsE23hGdJkbG2VowEQ-%^L6J&jV+#XJfdV*JQz+D7RDF zVdeRl@#!(Zy>RC$UPPO6_PmXLod}N;A zrhV%!ewIkf;%i&D;eP7A_Mj$b?tNZAslIP{@ILQ@E4Wuqj8N0ATq>GeXxU=t zzM)0Ay=jeO%9ne|48gB-mz>*aUuEGi=Y>Gt`uU53u3fc$>(^AKzAg3f+A^l=sgb_1 zT~V!z!!DZrTf6i^TZN|Lj;$h5PtQ+@krcf1E@ON8_UTDWMHfdss@n^;xo}H_zT#(rb62);YwyjF^_edNxn}70aw#`zNF8O1dK)1h8(u8P zB6N76pM`82Q#=2wMljbyI5W-MFr!Yb39}{j~l5$pv%sn*8(~ zCA?K`YIO_Oy3|aWd;Ie0OFMnFciMdF6>Yh&I#MfDwZX0|E_?Oi0O9)`b&6M3c%~jW zp2TD{ohy09fivm1u6|`tJ1rC$+&Xd7j3>LYpUe(D(s?9H+fC+ma!Po#;k3=qLa%=h zNc_BRD#J3j^nNR%)R>U*ASqU!0_OEi=Nq z?J#s%U+w(T_u>FeI_4FzSyOdnR#Xsv#3#jj^oa*V< zt5jPn!CkP9e|?R<5u^F@|58WKtK?4c+7)%w=Ehgks>l0Y21;C?b7f-sl!FFWSL^b#QKQwS4`Sq5Z)Y9vP@1W1CmHT3;$1f!U1^KTS7#J8lUHx3vIVCg!0Md{9xc~qF literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/spirit_wolf.png b/src/main/resources/assets/wizardry/textures/entity/spirit_wolf.png new file mode 100644 index 0000000000000000000000000000000000000000..e22cff8ff075d756a8346a3a2af807c96a6316cb GIT binary patch literal 2818 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/stone_statue_64.png b/src/main/resources/assets/wizardry/textures/entity/stone_statue_64.png new file mode 100644 index 0000000000000000000000000000000000000000..2a7a2ad9e80833ba547596f6e51d94c9e9bf3a51 GIT binary patch literal 574 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE#A&U%;gjC0aE$R#mjHf+a978H@y`5n=>5T%9 z%k21b1rBZxmH9hP{U{7}ZuibeNzK6A;9HOC5NrunX z>2rjZXRqzQvuREF`s>*p&bxNc>Ta_O*glgXA#(r8&`)b;oJg`&Kfn6Ire*aePQ`^6 zl~yj<^?O$L1lPay>knRS+?2PkOXt=0$SYCRCgS&H{(jTW^8KG*R(St=w1ks`W~yY; m{e4ZQwv`Mtg9qfFFxs!O-oI6A!o_eb zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||WR(zSRGas2@;L?u2HDJzh!W@g+}zZ> z5(W@(E=o--Nlj5G&n(GMaQE~LNYP7WXJBC3;OXKRVsSclvVTTMxJdi{;``N=#xqs= z=1$mWV0=Vp%FRf@<_oUIv)8FL&z=>!Ip~C6xSrBFrl#3?CepDbih4&}1s6HpcJQ7p zQW_W~uFAWVQ$(3hQvKM;+4k@6mdET_b%eY9bZhax`?k-I3))#-Z*mZSZ@T1uFvB07 z6yq-E9$ATHg?ow>?(fmADxc5Ev~G@Uurg0&YwQ`#fXb%8(uV_no`se|yrGh1b0o3#)zES8_?7$C~fn4~xxL zwYG&`ytpwvDO&XJs;Hy9OnjDnHw8Z!txVd_f6S2Qe^yX~{Z9wE_3Iw_`UK3Lt$f{T z<<^~+dx~bNXJ`MI%zyOz!y^JmxLTDboORO6*0dE)NjO^Y|4+-jT?LGxt}YA#p>_M~ z=6c)z(ROFLaiejsoQFEAi(rX!cVW*ZyR8cK_jfdg>ph<4Rq@nF+S~h$udat0f69W; zmOqIaB8qHQvM-{=AM+mgbF{ce;;_TYmT;X%Y>djsF6^xCyS#YA(?eU>{lw$;w(Jdm zsWXY?P948e!fG?!e}DG)>FIB_G(H@*R%?5s=!5D9dEs(z{+K49{J?fsf za4L2wZtP;{v13&3GE88UX6EeabzIH3(_f+I0Q)0}Te%%c&Jlm*83H0UN0>&;-WMxg zWO?JRZ|(cCgWoUTTibeUN=<}X!?Wjn6H7gW0$7t3c!F0?QaSswOmWk*+K-G32mXn3 tb~&zf?YYp;;u^FH=O_WRu8;_Uhv(JmkZWHUn|N}Tg^b5rw57(l?e zC^fMpHASI3vm`^o-P1Q9MK6_|fq_-o)5S3);_%yP_wz+UMULBle>eAK+3qb%|Eyr* zWUDdwcVI~;r-znklJy#m73Lc|KDz&5=lStqvf;=33WkOgm3Z7dX7GgiOnlJKF6ScG z!GA%q1QZ_9S?Hm+XJZ+u(N{;=4*9`%`L?ioLS_w(Lo+vj(f%O@6UA6X!}>1R*0 z;+n0W@6X;JUHZ0b$K0X|TsylJIai48kaUcVh`HU_bADn!`^U4~Gb-0Rbx1pKD2lNs z+~K;|KW+NKzwImMD9zqJV@>lECQ0)Z=bZAM@p~2f8(x$UyB3w5&v=24d?BtHw9T(rw9)5Y#m%i{xw zRZso2<+SXdR zMD)8zW9BtY@vD*Q?-*XRXeI;+_xu!zV^fP(UdYMU7i<=5!sQlw#;p=*rUx$??z!$5=byXkrS)qC+V4?nW#oNq9o~yLp zs{OgM{KK9@R}MUJ=d5Fkk3GjRAHd@(pI^*l z%09DGEThn2m&0;3iwBSQ@=rL(;jFWxv#Gkbg=uG*_(5~Kd(+rfE$YbaInyUJNAmFP zJ+nVV%jatgWH-IP#C1b>sjN}kO&Oza(Q~#tw{Ez0t0ml${a91TtOrZ{AKv5$E}!5R z^*`{^v{e2H*IC+YxSV;PKdEiH$Pt}+-LfHQhW4xvHU}i`m5GOLJhGKzlV!^D zb1m}{*>Cb5yV`QRcF%UxhZC83_)`pflXbSYIg8!?H+4 zlQHN0R`KK%XW=|SHfjjp#KD~H3>0|K9RY8$Lj_dos2T9c}=Ja3Ecb{39dGD+b-CJ19%>t%p zuUNS{U~g0YyL2U?_O~Y*)NHs5CNxb~+{Sd3U5)=zR?}b28M%5ztNJvtk;y80}k zYCl6+q|bVXu9kes_bL{bOg?;UQ=U=V4Z#>Ol0NYXQv ztYv;SvC4W^Pn^wN5Oe=@i>20~#A7x{I80K{ex`B!`h>tEOJDe3n|bv|+I?n@ud&}1L c|L6JB_*>E;50`&;^9Gfpp00i_>zopr0B>HPDF6Tf literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/wizard_0.png b/src/main/resources/assets/wizardry/textures/entity/wizard_0.png new file mode 100644 index 0000000000000000000000000000000000000000..e613565a19569e70549413ae26f8664e00da57ee GIT binary patch literal 1558 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 aGlU+^**LYGmz{xufx*+&&t;ucLK6U7G2@>A literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/wizard_2.png b/src/main/resources/assets/wizardry/textures/entity/wizard_2.png new file mode 100644 index 0000000000000000000000000000000000000000..f008cdd3fe6d54d21fa328e7caf53836fb087415 GIT binary patch literal 1557 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 JWt~$(69A4{23G(8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/entity/wizard_4.png b/src/main/resources/assets/wizardry/textures/entity/wizard_4.png new file mode 100644 index 0000000000000000000000000000000000000000..2b678753826527f9e03101dbdcc2a77b6a9f2bd9 GIT binary patch literal 1582 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 Gp$PyAe)s$U literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/Thumbs.db b/src/main/resources/assets/wizardry/textures/gui/Thumbs.db new file mode 100644 index 0000000000000000000000000000000000000000..0eb497c0175c1cc4090d836f0a5d67a776d13695 GIT binary patch literal 182272 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�fHvO90>+~ae;t?a)kdCjvg=Nl( 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/element_icon_earth.png b/src/main/resources/assets/wizardry/textures/gui/element_icon_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..9413854fcbf901a8e6f86f5f76d024c4ea51e9e2 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?jT;_UW7Z;}C>g2OVnsjloU*+aEnK^kTcAl{i>Dn2U+qH25+-Y1u7{idJ!J1U zxIcHk@tP+!GHaPG?9{R>7Pv2QSyHWP%MI(g2W7^GuXJcK?TGnwHhKHO6&y2Woo8Nl zY|D(GlYbhnhY24@?wWC{zVX%jU;Iz6&7Li_dA+2etCQ{m=G5Kx(>6Sq_HygLzBj)V z6GK?~H9PpOi1**p4y|0|ZQbAUcX|+mUA|h7{Yi$3eRa>T=b{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?j(jX&+Ig5dTK{hiaqQp5rH#aq} zgaHJci&7IyQd1PlGfOfQ+&z5*QuI>U85kI9JY5_^Brd1+Z{%%u5OJQ*EF2Jc@!}Fs zu?0)d@H!mq*|J54!FWk>`w7h*&I^h^tJ=Rl-PV1l?&Op+pV@9Y`t4bg_a-X9^oM2z zv%bM5wbfUWEKhKLVC<6HCaG+H=V-b12G<|6`wbRs_EryOOy*g);N&jT?;FxpKbsz| Z`~1H@!Nf&f-(xSxfu62@F6*2UngGW+U(Nsk literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/element_icon_healing.png b/src/main/resources/assets/wizardry/textures/gui/element_icon_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..4225f1d2141edf94111aac7f6683fbc86c43074a GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?jf+MoFYbyf-gKTCM)L!f zD+jAoR<*G3wy_*ub{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?j*r=wp>kI<}gKTCjbrT2mZ0@lyx~5Z#a2^<3iUopOOWWo}T}j_$;wj$#sr) z+p@+jc?=8-GZik{UwizO%`sf*hF#`OKCQ?k%dZoz@oGgX&Hn9F;`M*hR{@5IZOxxk aRPIe+4_vr$f#@rcmponlT-G@yGywn$<#j>; literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/element_icon_lightning.png b/src/main/resources/assets/wizardry/textures/gui/element_icon_lightning.png new file mode 100644 index 0000000000000000000000000000000000000000..287483d359f4ce1787412908cbacd393d394eb3d GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?jgiWa6#XbfG2HDJzh!W@g+}zZ> z5(W@(E=o--Nlj5G&n(GMaQE~LNYP7WXJBAx^K@|xk+>Y&Z^*|ODB^m)( z7i&%m`4|cG7Q!92}sscIH)78&qol`;+0ERDQH2?qr literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/element_icon_necromancy.png b/src/main/resources/assets/wizardry/textures/gui/element_icon_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..38bcbc456967226fca972da52e474735c3b71aa4 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?jM2!FVk6R2346>Oa5hc#~xw)x% zB@7_oT$GwvlA5AWo>`Ki;O^-gkfN8$&cML1&C|s(MB;Mj8Ab2rM26OjpX(eC3p8)e z6l}Yg5iiKI?&PAA2}YfX2OmxO%axlXlO*tmRjr$cMNo&2XV)U0W2P$%2cZ9^Bk_o5#`AaNe}L7F+Xf z@70~{w(`N@$s5hf^>i{;ubjR8lX8hsc-hz9n5eQJ{;SVu^ew(RaVt-46??6_)VY|i jY27L%i$f>9eCZ~1-#p3NR3X0-b{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?jSlHmrtVs+E46>Oa5hc#~xw)x% zB@7_oT$GwvlA5AWo>`Ki;O^-gkfN8$&cMJBmdKI;Vst0BJc@6#xJL literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/element_icon_sorcery.png b/src/main/resources/assets/wizardry/textures/gui/element_icon_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..3900024f690852924519a890d113a8227658db0c GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?jT<6iVqSXux46>Oa5hc#~xw)x% zB@7_oT$GwvlA5AWo>`Ki;O^-gkfN8$&cML1#?!?yMB;MndBdzj1rlu^)t%02=yK>C zb^7;=XV*?n#)aO?J@gaUn1x<2PFfhZVDULVxl ZSp1!TwPv2l22GHMJYD@<);T3K0RTa@cz^%^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/empty_slot_crystal.png b/src/main/resources/assets/wizardry/textures/gui/empty_slot_crystal.png new file mode 100644 index 0000000000000000000000000000000000000000..a4893196d33d21e782b7d239302aa40d022dae10 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?bTPXO$p@|F(46>Oa5hc#~xw)x% zB@7_oT$GwvlA5AWo>`Ki;O^-gkfN8$&cMJB;_2cTVsSb-LE_4RJ9qxrADwm5h$U9o z&UuE$S2gaPde)VnRFu0ITmEF_<^7Xi#u=&GCGI!R<|IdO3tvH}FpotL(-e*T33Dq7 iI*o-^&q$EqiDh7rVAtOFFz?wFkj0*^elF{r5}E)cwn&x$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/empty_slot_upgrade.png b/src/main/resources/assets/wizardry/textures/gui/empty_slot_upgrade.png new file mode 100644 index 0000000000000000000000000000000000000000..22939c7e2ec9c8868ef3f4632d88e7581701ddb3 GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`%D9gc)~C%zn$jz`$PO>Fdh=kds?bn`7N1>(>kn46>Oa5hc#~xw)x% zB@7_oT$GwvlA5AWo>`Ki;O^-gkfN8$&cMK6?&;zfVsSb-LE_$lJ9qxrADwm5h$U9o zv+Y4pkM|tG>5C?-`x^-fE$zopr E07|nxzyJUM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/frost_icon.png b/src/main/resources/assets/wizardry/textures/gui/frost_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e7b63b1124fac0b90f1919fc19650a5d68805efd GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0y~yU=RXf4mJh`hOl#e;S3B6Y)RhkE(|UVvJ5#ary`ay zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KIK@PTMAw?>ZDwF#kj)HeT>@7TOz|(5~V^i1ZIpzzs zzGppAd|}M}Yl-3{rB}g`vybQ*^8|TJa5(8(J8K%W zuqxYCi>E?5kgL$DB+P+lO-0JB?^SH485CEodgT^x=k@nVj2X}En0S-hzpovT%VF;b zNmu!ru`XTf?8awbB;H<5j+vdYZsL{dT|FmDL;hr+-Fs#BiDT6Qk6O~6+PzsDf92Py zCtn)ApRenD@H#rZ`bF5uf6gw&2X!90GU?0Ty5qgz*}B=rEh~g)|6eJks24iB;`}Ww zW*yPey8BBiUmQDEwmG!qUA|TI^R#1HYOf0 zYYjCUKV3L`zjg16PwIM)X0GaA@x$$m;?<<(0^D5poH&-Gpjhy9^>bP0 Hl+XkKSl7_4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/frost_overlay.png b/src/main/resources/assets/wizardry/textures/gui/frost_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..cf4166b0c4e72d7ba41d864593eeac1b68d3557c GIT binary patch literal 33939 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 S`56oh3=E#GelF{r5}E+}XnN%U literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/handbook.png b/src/main/resources/assets/wizardry/textures/gui/handbook.png new file mode 100644 index 0000000000000000000000000000000000000000..9e8aa947e1cc51492084f06041de0c98956a5ad9 GIT binary patch literal 17760 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 L)z4*}Q$iB}D4R@= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/handbook_recipes.png b/src/main/resources/assets/wizardry/textures/gui/handbook_recipes.png new file mode 100644 index 0000000000000000000000000000000000000000..6aab80dcc20a1dde179b209f7f56dafe0d7a3c6c GIT binary patch literal 26539 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 S4{re7nd9l|=d#Wzp$P!d0Xl~O literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/logo.png b/src/main/resources/assets/wizardry/textures/gui/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aae8e46fb0b6f4f7c41564e40da05930bbe840f8 GIT binary patch literal 11755 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/ore_picture.png b/src/main/resources/assets/wizardry/textures/gui/ore_picture.png new file mode 100644 index 0000000000000000000000000000000000000000..6cddbc7e1a54ff72c00900fdf31fdc42d3f15241 GIT binary patch literal 8674 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/potion_icons.png b/src/main/resources/assets/wizardry/textures/gui/potion_icons.png new file mode 100644 index 0000000000000000000000000000000000000000..d31d92c606240d5149ccc366a827b44d9aa855de GIT binary patch literal 3317 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/textures/gui/spell_hud.png b/src/main/resources/assets/wizardry/textures/gui/spell_hud.png new file mode 100644 index 0000000000000000000000000000000000000000..8fb74e4eaabffe5bc5904511202e4d8e7b49c05b GIT binary patch literal 29809 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 z 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 K+ALyVAr1hb>V-Z4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/arc2.ogg b/src/main/resources/assets/wizardry/sounds/arc2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..53a04e5d659d6651e7c9fdd15f25554c088889dd GIT binary patch literal 13963 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 F004VX+E)Mo literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/arc3.ogg b/src/main/resources/assets/wizardry/sounds/arc3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..b2ee55d9b8bebe7d8909713a6eb6b3218bd88176 GIT binary patch literal 14309 zcmeZIPY-5bVt|4+B?#l8iKG*w9AjC2QBr0xNQlX04Txf3U?_wr-oXgg2^C~u0O@38 zU|?Ws(mx`o`yUN3LrjuoU|@*IEXdIFFG^R)$xI3Zo3G%hU}RumZeV6)1Tv116{1+v z$vKRXfrEj8!O%zHXv2jGp$rTH3=9b>ntYSfJT;e2S*TGtV~Pieb=079#+1&Z63IP= z$6$nlNs1@~0}Dfg24~;mXP#N-EYl^_`-&D=X8KtyS77f7d|=6W=&M?C-m)#rvh&Vq zs&eo~vNA9*F*tZAwu%ISh@=k1Hi@JT#devZ6N<~{6me;-SkS~}bV8xo$LQsf$$nNZ zS1j(cdZn@Df)lsymP=kfhF8Oq*X?DCttmcd`FswP-~{_afq{X=iA^#^z=;E7e23<; z8AV)1Cm`NZU}ymO+7N1)gH|N|z%ZGD{&vo9KoxPJYc24oR zpDAoN=SJKZnd4b^x%_VZZeQsVWn*)L* z)t8nufqkyPz|bN9PQ@?+oRlG{c*&$Lty3DC&lsK70TF8spR;DFse+DoSdd1)>MhaV_|D5OkqWRnDElC~K|r!RQJ*WSP08!z65p0MCK zhrx+Mu?3tbrzG_l9-q_f=fnw#U|7y66gfUo=Hx^b?@cPcmvqj4GV%Xxa#7ed(8M=b zH1?us>1DChV6)iErm2@hQ?Hh#-rSZNy}dSa8z{Fx@(hT)UJCXiB~UBV~}bdfw5e(K#)% zbJnVzi*in_d%cSwg6ACfA{F-{P|k5JQbEc&2MlGLgH(=h(((Na@uTfUW82UYS8?PB zU|={ffyWzMjsynjUJWw68l)Qj7g|2a`~WEP-mqVppIkqd$^e4ko@1A-+)M zqts{!&@u!V85kJ(7#JAEoE9o-Gc{N+GPFN-n55wO!K5KM@`FuP^U7tM=RezA zZqevkl*trm;>*auzzPa>vkWgCzJQDqUJME<3m z4GxW+{y1XV^Ug&YvzD#erFZ(0$$4-U6Ng*~B-rH1;~{qKsL~R<2t2dY1!O;nmVu@eYvKs$J_|Gl3L^#$KPA+K{OQ!{~Do&l` zwNhb8P>?1oLxZdZLxXGtM{C;}7KTp@3>?W*lFnE@S8?((d^V?8NO7q|@j1(tBFUg8 z@{~!2&*v2Td7Ye5e9lsRY04SP=W`|pSv{Xq%;%-KwB(%S^CeS)oL#@BkED^VGYRWqM9pRyj|7*0Rj3NlP-pBC~AHLqorE9yE-L zVgo@T=Nqbe8Wcw>SFPf@Y~p)4Bs8=Y)ZSgS>h+;*pzyz5ns|HFDo{utD2=^dnku;i zRDJ7kGcfoUFfeFsNGxrcylCSAC+9FGP<`2A$f4OH5X7dqM8L^IvvmS$@@H%)U|?tv zfc8+#dJ>_mLN4T93!?u*OV*93?6q6N7$nZMGCM@J^ct^GnJe1ICN8x}h=GHXfuYB- z!|;X5lu2G*qE0=Q8md#LMRl!p>M-P3y5ve!j-l9jOZJ6JrbKmVZhK_;e94k4Q9Xvo zqGGremrjZ5*4-vCJ4bQJl%QrIABX~P3qZ#B{w|T6}Lusrz$v}^7NY9#G%Qyvb9HR>5R$KoKDXO z;z`mrEa@?Hw|pAnbX;MlWKwD^#fdo)3w6{S@ka6M}fzFPj3Wf`%G_;m6HymYct6?~C;fBZV z9SwTSF&B=;vO94&2{c8>I52WrSUhY~zxSa;1R?Z~EW)f5`v1|0(}7BclH= zjt%h*iLWvHd*hhrj(>LA50Re`TmMG;cWo>EaD;or7FS)7}q*#`8Qzl{0lZBszCM_=ZAqg;W3TfSr)&q;BOM*j)~{5%7@Y06%P!WW zFl652m~}TZr_~=elUTeU*flcmXIECY%f5*}7H{jie7#Rbvi8Iijjnz(-&a59%5Us& zYj#s`-MIIR=ta)5t0qwe2WH(U{Z#+!Qg@k!W5)#skHz2R84_3-YF?cB-23nJ|Hai$ zOwaZ>+_ zs4(1{wY8LcCgXwov$neQp5SHpm(S3!&GV35`|`Ow?IC=RB6~D%#i*5q7_u=ioRFGO za^Vc`x6VnyXL-{)7O&AbT(MF;U{S2ZhXelK=UfiBoaS@XDR+8O$HGo8HGdmP9o_&F z){LuLHuCs9?3&mbqSWBS$f(t!;JAcAnYpZGf{ugOHm(L!rURSo&nG?6m@u(L$FzY{ zA%Nq)^`UpJ$pS0_SGywE0yrFYEK+)PFg|!9tLw1@m+oGUDUy?K?O(D%rfy zxi}e=4|g5hv?2N%>kWr!o)dx>u8AIeJYBjsm%*i()w+YhDJ5CtHd`VCx9eKbIU8U0 zGKL;xu=9Re$}`h|p=4u7=RbragEblXKtP<0h(h{U4#SVY@ z$jQfZR7UvD8J^1#hDIqHa#JpDIe5bCyWEVzyMxiSq=QkXAwvCz=n=jE4ju-xS%PM6%?gc+64W0bdf~CAK`BYl zHE>IWK##9RyW)z_?XRvb?y%~frvLu<@3QyNd3tx+bMELSm@lvM&`R9SYE|jPIn6nv zJB*9XNkFA2v8&94!D9D{{?q#xe)zDg;ZC>9yY2GDskw;<+6=-v&euJe#~@B~ zlc)L}(Fso`vD-Uv^Zn)&D43wmc!=Yk)z&5alFSb8OS4`|Ok!|&-;}fYEZ;{zx8;iy zrcElE*>EG#$XM9m$Tb0GsW)%3%S^qE>dse9Qe^I2nt5~E9OE0FlRh@gUn)MibLWOh zv#h1Ih3UkKT#EYA9d-UnXlMWj=ftVTI-xld4i+q?acvW}PAJe9ic8_{xRKE7;btY# z({nWI!N)feCKa558Y(JAifugCSRTp0oX#c2y82p2pl%1-1}CNfnFSlB2MP#D>F78u zXKD`ED#0c&+i4@~nk-l4D3^q`|E!Aw9WJesaN#IiaMUcwAVSwubG6ln-;>tI+doRv zHRNrd7I5*?Ircq!Ybu({l3ATR1eQF=U-ft07CzRGOLXEU@VOk^w6G;##kKvb zgh51tVbeXg9@YgrgR7SweE7ywazdA}gvNqaRfPnGx>sko_XWono{PF~t>wS(79$E>SR)cC~ZhNA0zvwA1;G_e{iU*I4-Vf%w}A@v$(BR=-OFN3W2 zO1@ZM&Q`~Dc7w!BWoC!ZnkLS*CeBg~cKUCkeoK7iEB@gjI%RcYlFuC@W5(`@H*Q%; z1?9K=IFh3_YuQyEF~e*7Bz~XK*{qwhKGrAu*gu(>x!+G+J-aRT^q&Jqw%MleJ^r8| zIMvalD{E!2r^vUZejOsanoL3_xA9yJGg<5r?yy+puGgW4fMAOk+YD9CG&o;4k=S{F z!{g+k1ZJfqU9pTKw?40AjoP~=YNJ>VvsiD$5h(}94bJKvqTLaqE*lh8o5OnAL>vVq z0#pLtR`p6a8nB$;5t6vAdolOME#bx_9VML|UR&=KK46$&aLnM;yloSNyWdaP6u3ro z0|SH5fmvRq3SI7e3<=2%raWgW1D^lMcKvL|$Q;MeA~NgXo-XM&#ULOWMIr-j5KpQa^hN(Oq-ej)7kVL$zh%o6b_U(Fft!1(~fXa^xYzD@SL&k70;Z$ zGn{jqgx$(tov{+1DLA=N=&tU@rku^+bUr^jK4+cwu{Do8(#j?o8w>B~yLm&R?MBFq z&d%@R!QZNOZI{ydeb#EOm*-^R>F;-c`!Mr#ovPTk^Dlgi(xd&0jkizXYrY~ek;&8R z)S;->cfVtZAynoCo0swdM?XY(k{14|-8@2pBp@qawQ z^QPQaEdk}m7RScY8)DZVIffWy2lRLb_GaB)(HqXql)Y9fNyItSK%4Ehn5#>GZI@{G ziUp$53?YHJq0Fn46d79_7!+I8&C30R*-ke(n*DusEal;0p_DbD)AvTaJZ!7Zkk38A ziD7|x1-KMZ#s=He-=itV=iRaZmHo9*&Y2kMANK;&O$8GD%Wh>Vv zu!=fN2|1H<`OvNi!z)4C&8vKxLXJEP%3xw-n(=ZecQ}(y%fUm3HoGKj5n$tBth*_r zS0ll}xZrjTU(j@^8B7blpHsQ)cwV?SB3)VVn`N-&$Ko^BQoUY^7^b~1neHjT;dsxj zXyN8{7Il9UAAkJG{oFBU)l$RAHT=!xKa}r9{yt-%_B(##ZRhB%pDX9gJAZ1MPuLbO z9pT21tgMB>3f?Zc*=)^6UERVQ3^bQ4xTq1P7$P{^aixYbkD!9-U+aaO1{^&THoJUD zoWNwM!m*fv$zelBL)d|cEi0A)O;Qz^vo}^tTulZ`t*OiTI?_O+rGyJrc+OHx@W{J(~ z-anH)63*e(o|5+HF6U&HHA2f}wa&9bXR%cA!^Iz+gR`qn`5x7A`zF-W8*o;jR5v&4DEF*XLH{*}k{L8vWSp2) zM3bg6P1w+RP;iqGLrbpp#SXSvN-7&DrA&O$pH~PMpF)d_Ee{YnH6Ya$Uo*kbf*(By4MNs*k8 zBXIg6i{is(D=r7=1Yt%yfekk~5*Pymrxb*HvnD1)vT;qgU@5L7m2PJm6tH(kc~Lee z%igrr=Xc)~5Lze@8hV25$d03G@>lRbb#YZ=i7(doni*WEX{A6V1 z)Y+q?qmv%ZcT`xK!N=;fHml-E{bwv1+)*EAc(}@Rpq+t-G=p zmhPLnZqb#Xz|adJp*?kiUZLx6U%$|%5cEP+F=xqk!Z`MTy-&)WRT)jscjy14cC zoqdt-Kfm;Jy0-R=O|hX6i_WtfKG%Gs?@oXA;dR*Yjk*2drKLq($E0s2pOO6?Sp7!z z_1tUw_s3a0KCz;r$#t=Gam(C_oh(&uhl}=X!Ap-EXs zC&|I_K||<_uFH&(D`&3XWL360JT3OF_vQEBAKy;@_`qmw-T6}j*RpmxDj6{}IDXm0 z;4HV`fS5sYuTGMIwt+&##v5APqS34$0$aNh^zs{O7kx8oJ+a|b+r~AS!AW;js^hDT z4mP+jrmjggJ|brzkj%{RB{2T~QkQkCliZW-BJY1`k4vrHHNVqqLE{H|2a(Qadju3O zyuGz{g53AS?4ZYL?eqVZ{@Utu@VerZ)Xb%`ELQxv=VB_%9d?cXb-|Q%`&Njqoz0K<8Q?5oP0;a}0AA25sVSRYb!p-Me+yB0leJ zoV8!&Os3|%*eey8!^k2S#`1a>hlz5GT)AE6*{^>Ucrp}jA9+%$f96J})Pk1Yc^JI?#BpNN`X5IMaxa(d}TogL@r+t>fo$&NC+Q}Kw+)1D zIQBXIf6?=w-@+;c!+ds}`p4b$@-rc^SLTKxUv>lh?HKh_V=%w;XHA2-luwg z?hB^;S7$QJ)@PDqV77Qr)5OkjprCL2dffvyzh@RJ@Ow_$^YzTv68yyXf5EnB zV?2Y8TZ7aGW)p@59t{WL!u6RBL@eN5%QSh$>DNI!=A}G;Zyx`Dt-up+yS@Zvhp$Dv z4-^=fBa;8Q%Pc4__$zQy_P9&E`yGy|hU4z5y?FfQCQsd4_-gUhITiE1hScqUUR-kR zz3j4Q<&#B<&n2Wy(kYs_|LOUI*%#GcKDc-1;-~ei>K>clyR|*ZF68{W|KA?YwvW}e zm#vUJSCjhd^7q=z`cwN$#rOCB+it!q_hp`DXUG5T_m)lCd2gXr>bGFSTvZ+Un~^E8 z_4f5~|L#q{9%ol&edf4ov$v1X^wbk?&&waOoRhBc<2nc1s%N+KR;;%481Uv&IB#DDjX>)evkbGOfw|CeLzKD^A>ez$tT1Dq^{=09@$`6hL1cdY zhM4fB}A)+c;%UdUV@S7@=r=_h|zM$f9M&pnoJZ5RA{;#M2_UnnQJq)+W|R@UsDXMCGt zyF6R&hUC{R*1Nhhy{|aN^4k_K{@M1&zugc2{P<$U)8t3#l~ya-&(8mN@A=g&TVwaB ztLV*kzw&Y4tMAh;@6k-U%*VYxx8CFF+aJm550b0Dh^3rU+;QdAxzi8tyUm~1HM!xM z9Z$`_p6S{a7AZ2z7Mb^-;Gb*o{E0vFMh52 za^Lo(K)YX-{fa-M@+Z!Gv*=fV@7*tTQ%%J~uNM22an#?RynK`Ke7`N{h48A?wwur=Nms~J^NPq?&l4=XN%+i1bIdsG$(%&1c-}xR?I_Jv$d~$9fiCBc=m2f(%UO7;hci-TI6;QmFpBhEo!u{aL{hlGJt-C33h2IduF4D;O2Y|d?9 z;1sHtEPTADYyKl zy|3mxPtDH#P25eEinQk}JjM!X_?XI9=}Fhwt0>Sl^2)oV;;o1@Be)6YTffL`-s`+lRo}7Hv1u&EL+2rJ-OL>c}96f{XNU?3|qPq z)pjkmH#T($;bds|$>wrIj3J!2LnSxhXg0zJvN4WZZa*?R~R}p?sn(-sCw6mLFJt}L&FNuu5&k@XB_`< zxoy@llaqSB#>SHw7|y>)d-US$u4%iw+dF&hB7N)`@34I1mz!(-K{31|qwed_I6HlLs+E@ACj~6?vX2++gKe=A#uXcR#FKfGL=N@W^mmAgZ zJ6AhXq`o0%=7jl?jhY9hmQP62-@VymT4t$Z;ib!SbKb96^=9^=-y71`<^DODe^{X2 zd*k0tZ|BBe|2Z?o@3wvNGv{xoqn}K>9POR|xnJ$|&#P07>wV9Dm6$ZEQsS48{-t)? zyJwzn&)F$_lh^p;?{^;hmp97ThhP0U>(Tkx{dV0<@6xymjeX@-oSrKjf4sNg%Up9~ z5&1c`wvR-kexGeG?OXfxuE_PgwMW++Qha$TI<#QfXQuAeoBJ14@jaIEb9yVMz$VAK z_0L)-j%9n-<#cSS`2NMnfbWJBQ}Od3_bOUi>ln7FF3#W=DocudD|m-HLGpkDvyj_~ zO%ueEnJpq0e`OPgAw&L| zH#gE#e->S<=c%#2^IJxAZE}f8NGbO$u8&zf3=B8xB$%z|8wcwMU;eIrzwhI=|GVPN zi#$&$e%68WYJ1-rsU2tOU_sI{nZy%5;^QdaC zsrkDuKFMyz{_A#K-ygThO?r9nx)pQtsp{)C##d&3@qf>Et|m4v?)QDONk@+DdwYNS zn>_)aw&`iCpET>)(F>L@Uw!>|?7F$s)Au>Q=L-wYuCP87y6#&I&rg}idp{;{TW*Z#!b?7oaFyQ>j%%JPCg!K~x1HE1XBg?)to`+`h;-zF3oXvP`{6u*Hqr6V- zn`c!&_3KUSY>uqCS-v^u@9fPIr|)gDynVB5#i}ly8OvsJGBEr)`$5LsUij#F)i+@e z-+0e|-IKm+d2xKb!2UP0f3)((&$Qd{W&8cr^X%VOoamo_^x;g+nYA@R@1|9MfAZY^ z>yA3PmeytWK8tM5pRF&vNp${teUsaEw$UXAawPZ9{SuxpDgWi*OYc7-sjf>G-Mllq zc~Y83cy24JdMQ^_c`w@Fz3 zvvIrJ@%>M8{%E2#=HE-{4@7?>dr<}D* z+q*tL+LSjnYUU&rhKAa-T}LYK{n!xx=A2xfec5}Xd#7go-TC-W|NZY*>lCM*Z+lvw zZepLePJfC1y{e73<{jDgaBsQ%yywrpr`N>2tABGSRpzJMi_Dlez8^PS=|5vB!_1K~ z{r+l&$7NpEf1Z@OXx;U!W2^bgz8zOf(vSAOh+XNN_WyMo$0=RD$i+S)sWFWJn!`DSOC)$X?Wan)^2mg&oO zm#v)TEco{ril9lvkwJI9+>%U#}`mHy7+`*g=TPvfuaxvO_2 z-d+CrjAR7gfzX^M%Xg-yerjXn3#n++dcNz*%C>)ZeirQd{N(q;Sb;8@3zL(x8B!X&EHhhGkJ>nrt?ou{+$$%`gUGRcA{Ts;rs-7`_*&XAG^f; zyC`$+w9G2L73sDGm#2z3Pb+@6Q0Qk;@MGTVGpA2JbLM?F_b)?9$LIDN4)gP#y&b9I zxzW_|dA&&BlgbC|G2usMu$9a3ZDL?+;GXj^nW-=3L3{~g=}yVxv&=S#zrSW++jPk> zutD5yQHWy#r&iCo`Hh7vo0?DUXx_u05yViJ7IJgu4LbqbiI>t;&IlUXamhSjUCsa8 z{?G59KkEdi@8i05^Os>wbSU@IB`Il43=E~ey!2U)dp_2$zxB^HKl9&|SL+JjtlML7 zdFtc;_a=QTssB9TAe;8%+s;1xHM=Y8K3{X=<4r&Jd2QYPnr}D%#PoElmuufE(Jc#g z`t)$~gr8NGc`UaV>OU2$l{rqq~uEfXq)T1k34@@xGS5YPPnPB_2K-t!@`c-N)ztSdLk?1a5&Gher4e!8-)#= z!7<^Y$qe8j29`Mqh#>}61_p*+!o-3FB22v!}(I z?b83ycJX|k@&Bg}=kCamTaaO&f4|21nAPooP~(###>@;0X5M&Ly|2)8>-W3s^NWxB z-HS0)yLVsjn7;hK!@p|^zlm$@-(Ihher^8pU8zgWzuVbbDgQaV_0gsF*RPLGI=*eW zgxUCAJ@y875(g~zjWzcz2v<+*G;*v%zODMR$SaY{{NTr zzlwL4$(0|}yJDB>qv{=YuVT;ns~^m(Zr9x}zLtLY+264JkFEWm#w6`X;r4wRo#D4v z_T%Q~v#Q(cpBc~AT=c9nzGBr;|CQOBc3aOlAp7y##rc8(HJ|q+zk3sV)|vaW{EKsa z!rS-Fwm*Jh-U0RnWqsU(w&yS8G|1RI(3N;PVSBnmgE&K7n#y0Zvf`N^Sa$VrSqRTQ-J<@XE#{8= zzF*7#?k@ixb97ly?4Cb4b=RuxYou4LnhJ`70;g4Tzm>f&eVcIk%8~!40&*9Zhsx>q z-TA$D>MiH2TlvqMefEBT@VHd(-^1ru^1dd$J1beGvHEKNYHKUOHdCTR2niTe%gV-=6;XXXSgoT-+bZ`b8>b{}s!x-!56&3g0<< z#fNXbklW9diz*f=<^NH65+$IXcQL6jzQC=n= zztcx<-QIn1zdU2_yXpQryFEYtb!DB~?sqzVUpG#C{Qv4(XUk_(@O=E32wb3ZTVIFs|>;Jm}U zS4;c@zr;8HF1T`r`CI*pEY!0{{H-$-G%eRci4Z*ILH6o>a9V~OZUkc zYgetB1R5e`Sep6aqnF>7cL{p`_`dzOyT_m2b}imNOz+;lxbHpvi(R63&zxSjCwJz& zwzyUP^K~}XzdI1K&z^6py8rs``}WrC3(u_kXa9T2)3mAu?x!Y4-T(b?jn4Gl#kZdu zO}f4Byxs4bcXKxHzb-4we{!4uZj1fub?vV8@9oXF^UsOeZpxY;n^L=P`qMRQmV7_| z-@w*@cgmhMwzu0>o;ZBW10OKb5kpKVy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/aura.ogg b/src/main/resources/assets/wizardry/sounds/aura.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d48bdffcd41c809e89c8d12f40f40b8fa2b59560 GIT binary patch literal 28530 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 ()J{eLGWh1buy84Sz> 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 Lzc+iOq#7RpjzKtm literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/darkaura2.ogg b/src/main/resources/assets/wizardry/sounds/darkaura2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..df471a0d75324a403eca14a34f0329a57e3f6dd7 GIT binary patch literal 56426 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 btMuNTnY~&|lc8Z_>Y7GI24;o>Qeq4MGB;ke literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/effect1.ogg b/src/main/resources/assets/wizardry/sounds/effect1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..dc9a47604b9c007e60e99631ff4661257224105b GIT binary patch literal 33685 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 F8vrxhmdgMD literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/effect2.ogg b/src/main/resources/assets/wizardry/sounds/effect2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c2c9a62d2ca60e4984638ccddc42884e4d8c3b3f GIT binary patch literal 29616 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/electricitya.ogg b/src/main/resources/assets/wizardry/sounds/electricitya.ogg new file mode 100644 index 0000000000000000000000000000000000000000..898bb0b3e60374ca8c1a04f101512731e0ad4f3a GIT binary patch literal 21626 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/electricityb.ogg b/src/main/resources/assets/wizardry/sounds/electricityb.ogg new file mode 100644 index 0000000000000000000000000000000000000000..b8eb148cae86036ef2672f19da8d4aa47a00f476 GIT binary patch literal 26461 zcmeZIPY-5bVt@i`H3&l~b?0_QImWX5qNL1XkPws08W6?6z)%QLyn_*}6Dr8S0Mg0G zz`)SXrO7O)`yUN3LrjuoU|@*IEXdIFFG^R)$xI3Zo3G%hU}RumZeV6)1Tv116{1+v z$vKRXfrEj8!O%zHXv2jGp$rTH3=9b>ntYSfJT;e2S*TGtV~Pieb=079#+1&Z63IP= z$6$nlNs1@~0}Dfg24~;mXP#N-EYl^_`-&D=X8KtyS77f7d|=6W=&M?C-m)#rvh&Vq zs&eo~vNA9*F*tZAwu%ISh@=k1Hi@JT#devZ6N<~{6me;-SkS~}bV8xo$LQsf$$nNZ zS1j(cdZn@Df)lsymP=kfhF8Oq*X?DCttmcd`FswP-~{_afq{X=iA^#^z=;E7e23<; z8AV)1Cm`NZU}ymO+7N1)gH|N|z%ZGD{&vo9KoxPJYc24oR zpDAoN=SJKZnd4b^x%_VZZeQsVWn*)L* z)t8nufqkyPz|bN9PQ@?+oRlG{c*&$Lty3DC&lsK70TF8spR;DFse+DoSdd1)>MhaV_|D5OkqWRnDElC~K|r!RQJ*WSP08!z65p0MCK zhrx+Mu?3tbrzG_l9-q_f=fnw#U|7y66gfUo=Hx^b?@cPcmvqj4GV%Xxa#7ed(8M=b zH1?us>1DChV6)iErm2@hQ?Hh#-rSZNy}dSa8z{Fx@(hT)UJCXiB~UBV~}bdfw5e(K#)% zbJnVzi*in_d%cSwg6ACfA{F-{P|k5JQbEc&2MlGLgH(=h(((Na@uTfUW82UYS8?PB zU|={ffyWzMjsynjUJWw68l)Qj7g|2a`~WEP-mqVppIkqd$^e4ko@1A-+)M zqts{!&@u!V85kJ(7#JAEoE9o-Gc{N+GPFN-n55wO!K5KM@`FuP^U7tM=RezA zZqevkl*trm;>*auzzPa>vkWgCzJQDqUJME<3m z4GxW+{y1XV^Ug&YvzD#erFZ(0$$4-U6Ng*~B-rH1;~{qKsL~R<2t2dY1!O;nmVu@eYvKs$J_|Gl3L^#$KPA+K{OQ!{~Do&l` zwNhb8P>?1oLxZdZLxXGtM{C;}7KTp@3>?W*lFnE@S8?((d^V?8NO7q|@j1(tBFUg8 z@{~!2&*v2Td7Ye5e9lsRY04SP=W`|pSv{Xq%;%-KwB(%S^CeS)oL#@BkED^VGYRWqM9pRyj|7*0Rj3NlP-pBC~AHLqorE9yE-L zVgo@T=Nqbe8Wcw>SFPf@Y~p)4Bs8=Y)ZSgS>h+;*pzyz5ns|HFDo{utD2=^dnku;i zRDJ7kGcfoUFfeFsNGxrcylCSAC+9FGP<`2A$f4OH5X7dqM8L^IvvmS$@@H%)U|?tv zfc8+#dJ>_mLN4T93!?u*OV*93?6q6N7$nZMGCM@J^ct^GnJe1ICN8x}h=GHXfuYB- z!|;X5lu2G*qE0=Q8md#LMRl!p>M-P3y5ve!j-l9jOZJ6JrbKmVZhK_;e94k4Q9Xvo zqGGremrjZ5*4-vCJ4bQJl%QrIABX~P3qZ#B{w|T6}Lusrz$v}^7NY9#G%Qyvb9HR>5R$KoKDXO z;z`mrEa@?Hw|pAnbX;MlWKwD@G;DH2CEtJ_>eTZ@58G+7@qY8!#r8KmbF*h7#ZL488ap8u? z?i~$!%rO^^#>jyg))UKV98GA%DKH`7-|H=R7|KIw5?*F|16aO#&zvO?2 zSZL=Ge%G+fy*^7XGdpb0mi2qj9J0=XF@htZN!xtk`kPxaUQB#+{rUaJmyf4UnHsnF zic4ed+vT^`MQ)osrSRE7+b=#Ep<%a9MLJ6-$Vjibx@u9!(xp;in=+h}SOpoDq-jR6 zue|@^R&SOmS45k%+;08};n@r}dJV5nJMB3%$8MF^*9AAV#7i_=Qw6z8RNkw*7fxjU zmHLab$};rA`4>L=d*@^XNie<+=!sBH2$VkJwx%OPl!3vDTTEMTWBojafZtQqb2imf zyt}~o!ESAy?ecWV)G2{sr)C*FI{5i}vEc6yvbpUm<~r*fRZNYZE5OXq@Fkyj>0+Mq z8~@&Xu9t5Wb@N_?DNnWipN-e1N8DInJne7tr$2Z0|8vsWH;G4bdc>~&l;g|dOTN9E zST!?9X88*z)$_AtHeYuQss8Y`YEgmF^7}g@Pifeu9@Ke1?WhBvap06CHLf$)tqFAw z<$GFoZLdf7n%JtQiEUzMjlQsabUM!wlJrvCq<;gb-)t2&zs&A6g<+V5x zIq`~|OONQYEfQQx+}bq`EKNQ<=QJ++NgZ1xp&9No!L&-ls`tWy345EY&N+5VgkRE3 zTHqT{G=n*`FI16niKJ)G$Acoailwf7lkST6X>Pm7qINm9`fk+{?vqah88&#=h9oe3 z^oR;IVCZ1jpeq`;ZYn7D?SXbSFs7?Ft}VfB-J66 zHPJFeL@ov_{__Y@OZm_hde^2m@=wyxh~p>pDB{ zBu&tD-o*7LE&gAhzf?$e`RS!AQfp+pR+snA|DJuM z`@ja5&3fCvA9!<^|7mb!df)YPYt5T`ltizt4%{AaI&e+etSy(~HpXoBbB%NsVVfb> zu`E-n>*hjb*9wO8Wk;q2dTLH7JK-S2<|)z@S#@>>>wzVXMFtlW_?JnjXS`)8<_U0f zbre~=z2m*_ABp`PlNdL2C3Ibl^R}G$^w^i0<4+#++||3;6SgFD`--Bu%k)$l7GD42 zb2HjQIF;4P$~CjaD^kotY-?WMLURt=CoFgJ7#zx4876#5Vr-grd)9)M#>g;JiA+Zx zpV(MVh6YxrY0aDqxHep4%MszdVV1R)nSmiB)R6b=W*Khp-Y|hRYZ;qoB=>VJSj4qL zYgvS(bJ)fvrUTcw7hTj|#2_Ik$lze8vnFEe!7he^7A%l&ZPz}$JkYIm zFLm$!4b@*_k2Qae?Y?>~ZT0ypH3G+9-KxGV_V-ivH-4v^THSKu*B4D)oIXeVijzzC zjnC6(M1GkUl(|gEruidh{Hn{j`FV$=lvbu)D?65#6z0}klx3AHv)xC``$a;7R%fJ^ z3F}qX#f7ftP6e_{ZEl;?ku?2^*j!=FRSK6pi@Ex>E;$!$5I5{hYB+Y~R>^LS4ZM@` z-j-%un3G}>J}c;{*4^Nz^!*aUy6YOk zUV@S5rfjS;T{~xM$d#_JuBfx~G$j~a)Mp$pno!NBki#&8PnY3E-parX27$$_-GY&w zj16(ESF%|c!o*y30>XIKtV)_@y1=}7(TWr0u~H0AR4#h4gh(=LG%Q`XAj~bDd%>bB zY%Z%Z7<;u(M6F%aw9>b`Be6q5!fZuDL&_!-h6y@>3=AO#YZ;RmT-JBEvM@2+o28m2 zXpz8FoIOpVP=KH1qKncmHU@>dRkr!lD-xe9F8;NxjxX@p=bftTIu^1F4YL>-F2&6) zsrQ#&UU|DF=A6yxIp*><8$T`6UvepBGiyMoq3a_TN4?z@y+t>Yw9aQ<%@&?|vi{mG z>-}FAf4+G7^2FS|#|l4XC7G%AB$vyajCI@*?Bm`yd0q6{m?^c~>>4XFBcyNWp7u+- zY0UeP?HM#-*oBOX+ z`c3NcSQR$4EK=7YprG`Os0D+joZI_DPDws(H@aE!$`i9!PDxIfS+YB6wuGbjMsH^w z-&DqxS9^3XGad3uU~p?x$gGUwTeWnhz%+xK1`RFI)=VDL@~T|4^)^*Z-(zv*U8v^P zJkg`hE4|npW-x4snm6+~Ljxm&O%N-`#IC4vbEXfB69gNSZoge1&vPX-Rgk+OCHFvf zHtVYupqhf>c*8!4X%MMI%1&$Ym*e284S9w z26kiyyB*%3)S#IqWtOCcB@5|^ERA!W9qotG`021fnLQQ zYz!A(TJ-+;KJ&-18T;O@Nv-q~@%Uu2ti6|kp<#s}gFxD{S3lOztKK?y#{N~0BTRWj zU5}P-5IPdT%yaqJy*1$uD}H5Np2;)OJm6x^Bl(?2G;W)vKFdzKt#jV1_}Y&+*(f)O ziyfI8tlWZ+&U$Lwsnn;xT=eLRx}V`4TN+l&{CehRSmJ(i>yuvQb(bP4MAFL`U-F$$ zT?xIA_HToK-u4LWOAUQ%*tOA5?9$;Z1*wjy)Y?Gr7Y$+^x)==BuvYHc^PoN=$1~TW(b2%aykEiy7kt&VaBvTi&}G`1;)qN?X5S zRg%LIR@VazvY}tsWNZ-=ZcV%sa*sEdYe5SGm+kFIOE1h(RASy*WL*5*P^ImIg>=}i zaCROBUY&yu3m7T{x^>oPIvTTeZ|zcP;o6|X)p2p>g$){A4r0Cn3?c!mR+TOY+{mHy zVnP}x1B1cL%?{6_LQGb#-LsH^L5bmpYbYZFD}!D2QDbhK z15ESc)+Vqt@?UWD`!#P)-l|X~YnK_O*UW1Edi>cSsAT%GOTDvGJ<&>(;lrc9y?_7y z@;2mK`lR{l)#Wp9pU<84`uN!^w+^im^`Gu}-0XGK=LdU=E`D5cLGP8ZXQ zRi9hvJa><=`exD6RcTR$GP@G96s0o`8=c&w{=hsn@(ah6?5B&`67sx1sxQ2?gu}V2koA|&$(6!BM zTF;E4b3Cc;PQJ$i<+GGaP8-ZB^s7p`8y8!9u1&IOVb=+XUJa#|54uyH6$eSFv*#Do$8AUpncP`tP!Ou4ZY;Y`OW+8?YS;cIdO$% z^M)g`3;`)D3~b+X!sF}u^Q|@-*2U?qlbxbJYhhnz+!1#<%zu?<_eZ17I4Ofk2fYHqk6gODaiU;snR83F*x!j$UP!iy+;}4Kv`#1J zc*%RM6+Oa6$y!3q$-AG3d^|F15wD^6v-x$6;G1`t6Jo^ z@2r_~VFrW1xj0oVwys3MEjlwgw^oTX9a>^sGhtekB!|g7rUccpz&4SjBbV4Gewwmj ze))_h9odNU>Cy}gP6;tzMHucWGKB~*Y*-ZNp(7z7THcXR7}&)d)Y@~RCrO0+M#fUH z(7+V&1*`%*Cxky-zO`W;Q^HYg2BrzD8v=H-Es1g!6P=Tv*1JpWjjN8>gouT?3=9l! zE_`)jVqlo@%&OCtfx)g@)VOc8tA`Rad^;k!{jzU7a#jrZw-xw4V`mOnXnxWrJ1aZN1O zj`|3Z$erI7wQBNagf{b>;`n~ULR&1LWQ9pg(f37RlXeG1Y1q16{^D|qE!_4?$byyI z!}ppqY%E?Cc~F;gJ-cOKT6dlFLg59Xx(phPCbArye1Z&Y3>P?sy!APo86A>EMOSt) zd|JQG>!papkuEn@28NAF%Usn04SBq$8cx$-U|^8y)pZMr6bT4fBiUi8<$p@F&RXh+!Dpa!0mEk*56zm)@z!TT&DY}>rE1LU2$#(Av|7DE?vI+-&wj{oN@8)3h9|aQVqp&-!!@Q<_1nrmt^2-KR4;= zq=oC)7#J89h-F1d_ar#DWFK*vdi8c3%Lc2qi_;hw7}l+e?cTV8D=v6FsHWe1h=GB@ zC1RSd#WbT83JeV!4@I4oI(m(vp=*^X1B1iajmL~wxL2o4<7lvce1L&LV^JHEQdZRV zylfqi?zr1it+glp!tf5R=# zkT{WnA(DyV*RlKM#%8_N&no24KTBa;I)ja=VTELRdW4S%gMguOfWT^2)+HyK?mXaH zyWPNGzM9(=sh9ot7QfDZdc?2b*bBcqmx{K#gm1J5o4JxqQ1?x2F=Xrgq=` z|Fh-I?>^bbd3x1u{l_w!PEYQ<;+^noU5{+Pmb8Lp^~#0r z3#X}N`6_HkJlLt5e)Q;(l310%Uq06+ZP|6?b&AQCsH}IBijL;rRM@g5CL!xaK+bNb zjKf(Q)^zS>{PX1VI`D`A;{j(-P(X$^KqCuN0Jp6pT zynLf#A|qlw{5?Ek<756$`CrB;cKXRIpH_xZ+7X(kq z7Q3>}s7!P$DuTS;zfY$EsO}C0s)`u^eDKc`V{MSMr0eKVPvj zi0CqOG(;F*RcdB!U|OIS>B7L^!O-BL6t?NiCAO0(iCheJyG6O>Zm??@oGtsvrTuJq zBU=qK!-W$2ijo)J8}BZH5QBmg6GQq-=RdzaAN|_g ze#~*wZhgxi1u^e=rv@%P-Lm?i`{8bhHU@@)hhGTKHpSUOC0K- z9_J<-D{HbNS<2j+d24QCra|LbjpVl~8k1}p8C$hx^l(}F78*7roX}GV4$l_0GMP}g z*7D}!R0fqr0&QEe!)7k+O-<^$9Cs z?`nO(BO}P-&4#R%QkGn4tdF;*oZVnvu+c$%?u*S4=XeuTUVrsARS?>|{#Ag<*I5h1 zONDBW^73BjGTg+*!oVQHm7w74%G|I@i-Chdp(D|k(KS%e@p#=4zL54sU51)_mn&S; zb#%O%CDx_hA-eUdm(mI@28N_4jRje0Mk=8jSZ_uxSmh+PYUx4-1qL&=1MYXVt}UFN z-NnklFr{k|7XycqHlx|^*3~)}>(!QV$))X1NLBqLso}u)hnJzC^n#K6_OkhPWj^*= zQgsv5K0SJ_FlU1YgF~+nqrk+6KkRoue$00EVBUA7hnK!ZUUi(((cS7LuIQlCy)v=h zyLY|qOn<%e{d4YqTd3aKd-uZXFuAqH^G>Ij^Hx;o=M-NSc^#D1b!~ZXcH%dq4|`c6 zjqgV7zAClobmuW4^?sK_IyNa{k(ODT)H?Q9EqGzHh^;8~)mI%(HxEVc(A&LBZ!PW@ zv}$=J_HtH$qs+$cbvdnn7EaRTI(Mpox23JGtsw}RS2*2`j<{lNs4H6;Y zrQsn-x69w=>aNica1qRj4&1XTB@UFs7$RIBtlYb)i}Bzw1|_epX&ay3`j%z6`B3Rz z8xDhJMu81X3=9i4eebJgUEpoRxTY_VMJ2KR!qIqbw~d`s&#ax6`^&B&H=F6f<+O(5 zx4pPuy=Ho0Q!5iODe`a3I`bvjfwA0tercyw+3i$k)QB$U+7Q{}ppY;%=Ue3E2KhC0 zjAzSvpRv!rzW#(y*B!pX_smPu{1_u<9Z;OhdQ3f<&-UvpgD-(r-)|She}1WSDvw(N_$IYqxVo|ZWXLr+ zjT;l?4H}j2c?Y_#E>Qtxn45G-Bfi8w~>ebYQ7~GwsM$$ zK4o_xYwe0)#y8VcON76DY;MxonK&!@Ro9QN8+Trw8>f=EdX7@SN9oz;UOW8`+O2o~ z`i`)reLby2)S;Hc5ahb+q*Ax};oA*x0#xZY@ z5SpDTyy8Z(Qu4%i5juBIDtY@mvl-emG+cXe{Q2bRZy!(1-nwZ1R?jv2Cib2ayvAYd zuIcw(g^__lP||cM%cmLUUzhWqy%%0DzRcI@{+41Rejm}ks-RmwKMn;5T6t`kd+jp& z#a)TrKPqDMGnSR5J)6XTcuv)N>y|UO6FVP0Ehg{nCvRqAn3$K`z;;09mRQ{CJ$#QR_3Y>jSs0*^xP?pUeO6-vgG2XK(-)$F zuImN4n;1;CyYODVq_jBk=(WIA%QzIS?62fxYG&nHa#c?!Dqw3wNDtEi>6)y@enI~& ze+pjx4O%_j%rL|LMS(4YS^L7B9t`(dS-vWXp0vCiGX1NTz4(i#X;1QPMYBY>*Y4Cf z#c3U&8@SczdW^}vSt)@GX^c@z+L_k)vEFiAAai40(AOsRq7+avGB6nTGpN-Q=eSr zqib@NZ`7CBHuac%cr2Fkm2pm~L=;2b5{CV8i`^eyU}`R1@p0!x)0tr=f!~5MtNFWT z)h#ipm3}4iwzTlJ=%!3lxv0G>9(XYvsmgrB&0VRkDf`xcx031-TUDcK`2{&ESs!d< zId?03@$L`d;U_Gw-icbW*rD2O*|Rzqft63^MP58|IatzM^O3j*f*vJ;R}eSD6Gvcj#!lzXkyNgG7KBYpS7qJO zrsJ(3@qch@n>SY2f~u-xpR19#llYbX0M^R=t{FO{sdi ztiE}x@jT9x&g&N~iQ4qga1U#`uKNl8Ibuv(CUH*ijQUe3cUwoIDPUXgW{%V135Mwm z_gqzO?EQ9X)!n9;l$`LdPcNJ}{kq&UGSX%KqMBnn9~baOUSU_|a(tb2LN@f}vdTvd zAtEeymL7HM?r;;CUj4nFf#FJ@s&Mj+mr42CZW^?f@>D$hVCT?nV#ILPV}t)b%coBT zUv-7KKeyR$)SI|{(#|XL_i8NVtp5CeBC9+7yzkr3m(LuYyz<*obD_9hYy|>s#}=&= zWDJ?Ri~o1=SyqOYyuX|&YM~bQ(zYMCptz+({ z@^(A5VAm3%Fny&(kyHG>3CV`ZcZT~huqWh-DogdozTT4&#mCCvBDHr*#g2<%ELWZ^ z-V~rx7Gx;SG`*d{r2e*3u^_`2^8oK@*SC3I-oml0)IwJ#``f;wt0RA{v$sEBqL;&d zG5YMPZr%CoXWmXS)pGTJ=)Fkuuc}o0QMOx(yBv;mai}nPn=Y|Eeo&VuuAj+)?ft*^ zDW=MbZHe3s)z>Y5-r(1YUVb9?=BA!mJKsc|i#nmX@%)}yi@c+Z`{EZYSj*?av!*B8 z_7xW!LyelZ;QF)&yu7n#o@J6%*SvVMY?{8qnjLBkx6}*HPS8HHD$SyIf-v`SYj z^(SMOG+!~pEtW~Y^#iYK?9aRt#=khR-+DXi+NP%~=Ww}+@G5IGMYt7~8zeNOO0YII zN(E0yVPaTfw$Sea&&9;jQ(rn)osHTvb(6*X>ZpzGNyZXF4OZ9U)%HZ6-}~`HWQcv4 zYd+g$&np*a)wuU71#VQEcd_~_)9sf}TpO9V&9v6E85(@|{1|`uUUr0nT9J0|THbr? z5mCOv4CVriZrjU5R>#EzKK|;dy1sO!t$*&-$kTz}u6FsvZocEP=#R_mzSU9TQ`Ww? z&gvNA%e`R&NSnI?@wcuxA(ryJIZ7ABYE@6*3YabR$qvD z?Y_X3ZNkdK=Uvq2o8G>*M&PpU^2#FPWz(K*DqXwp!dLez&mQ#M{ZhBMZ<5e2%>emw zzt;4X8@64kIwf~(!b7DVzMe0?8MkyTEa@>RI9*n@G0DN=(Byi@#|QthMu>K*F-(hV z)W3G@_=Tk2B`0l8?>V-1`wQ)ou-F&b-?jMkuPr{)qW0%4U$DF6$F+YK|9EN6*_Lh` zbZmxLQ){2m86T~i_6$+8M5o3?+G&Z+J;(eY;mfL?f+x?kJc=A5>KPdN^_9DwcAF`0 zn)~>Wn&s=)%jJ75-B%naI4&a2z|bK!b1jF^s@wbLOg{T}x5;O|-1EEtEq?J~*E_9M zmyWMIXa2$@{O2*ANy+;80p~r6-p<^XTKTSdc4dImbJr^?^;Rxf(K<=5_T9=gx4&G8 z72f$ameVt!*EhOMYvhxkpyT3ITXC*PkJGVJ z#$ef+8C+KE3l^MU+LSQuqu|}M8+`gSG+r>iIrg#3FkkeplkF8|#|Oe~6Bf)$Thk)D zZs&2?OE;V2d{?+g{(j+M8kpu|#<`rcON48x3eObwV{cvA9A3(PXe+tF@$hmh;{z3) z8=)5#ExO62;Udtz;*=N5X`Ql!1C6PR1yYt=We8x}v`KJ6t7|~R9)=BCA{`8y6c)J( zm~e|-7uz7waCG8a<}iL4Ltn$9ldS(v9bNolhP+2r_KLfgI>m0xZ*t%=ywAY!-jS=2&`jd_+B3Dub;O(-LClh{N7(`=k9%6`(;|+Ws$I!6_W3H zb-VaBeA`l;bKCFn0_E-dEMA1a%=)c=Qqgbnymb?+J%l%PCfEI*n8p2DM{Low&xx9% z9;HsAcN9Oo_3>KWYI85&Rr9RX+)#1O$hl0hI^LG)tco3sw-&s*$YUCu+~l|6)uDv% z0UH%O7rKO)Dl+%RIqiBAG)=&3!%EvZbEg~;n(xyezm{d1UQ1HaR88LLQ`CEwt9TXN zeEcOPco9rXrEK(s}$qB9YrtmG*%sZC?Hhn5gHwkc5~O) zw=8d^^Fm`Jt-CA?6pOzFT%Y93X6k;C z%cv~osNp(&)uYTd$A-lLE=>X~dj%O7v`;rVhXkz-6O}bw`&6UNfPrCRYT%lP$PI4G zr$^~9)}1!x=6h+cFrD?p(?@ez|7kLOunJ6xOmSkXmA`f~v$yQpl{E1unOj(!7#QBH zwmo{$qpRJni*urin9Oq5Ez8zK{C-ot?ZmEo@%t)1yk5WQ=ehm13i9V4`PO~7S1Nyd z{?i*5J9S>Hd?3~TYvONC{V8YHR!(OSFygLA z<6X%5P2rC4o?QNKN7hM3xx8#i412P;=a4|d;+$@4hr~HKM1^SHkFUyI^0T_RO5)UJE z)GdY-o(91HQJ0OYF0qA7U23Kz;v?8{OH`#n^1#eh#t|WFT`sY#xvai&+R6$;LBZFW zQ90WlPg=;%$i>^gV!>(_28J1-(+;^UU8uv(P$u}$LT#GPB5keLn^k>wxEMaTq~w%& zLD-CsRe<|80|Uc}jh-b_np&4hiZ;qKFfdfK`sHf%%$-}>ti$5%Hpy|d1VfLG_V(2b z3~{%wYV&?eXL8V;u4i)TkEM|Z_k9M2lqpY+u1h#~@up>z{pPOo<%Wgl^&PB485%;E z7~Y)TW|P)FYsGL?%n(DSJd9+9^UmTvXeVz_AiTakSp46$#)`T znd|Q0)9dWhbV}0KzmjYfTxpcc_~vEXo0$nK<@n>W7x3*?khV>YZDH7UI&}I9u~5?o zJz7#dS?g+elvi(F+Ipz)-LF#?YR*;iOO~nLOz^TTxe+FF$SY<^Pmhd{gs`j8md9eQ zO&n^)S{~lKKFkwtIxpA}J85C(*04p~ZF9aka57bf9nDE5s*0y3QCqF)%rWMbv?jf#JZ{sK^5b49={V zlS0H?c^rC=Y&etAIccVw00RTVzARR5-j|I%>RWrhZ0+Kc+A1$5*?nsFnc17SarvIO z>&xyh`u=*(t(hj(XSQrE}MHV$N0zA++}szmcDjTrpR;9>BkPjQkxwt2{~hpLDMPeV&hu1LjB=2%Hru0bjFXNn z^-u_W7n1tOt}D;}byQVk=`IwQ0Td|L@?#}&Cm9A2RvTg3VIQy<+!waQ}8)%76yhJ6+#LE z8&)$gFtjMKv#s^+V{A`lC}Y@ATr%&P{1m5iR@aJIJU2>&2WnjUq{+5JeDTIS7jp@L z2^uBSmE`uCsR%PLxCjWeXEG*uGcqJxWmur`f{lUU;tNy7Roo19-BYc#d9O359DWhp~+k!eh)^zZMzqaJr{Ps(5$o%(G+upx!s!^T8!q5`Edd+()|Lx9E`j4gT zj_scCAY*Nq$*H#oXK()hX#ro{-yfE1?p*Ett7d#I?V@{ecIE!tEbSY;Vi$z$p7fZ< za>{Rm8oQ`~u7+hnftS}lU9x@4Ioa@sk?Sr5zCW zD=9o-*I&y@1{8eIyZp+(II8_ko5iVp2W2?}oec}6W_yV)$V)n9Dm#nqGTVYXM(o>| ztFFp2C?A~Dof$jZ-QswhXU~VLJZj(8^hS7PO}iq=5c1XO{JMJ=k1l<^)$;Gghut3- z)~sPN(N2-$XDHA+tjX{xDyd^CgO4$T@7nG~lM37pL|ssnopr$=vRsCR)#3Z&GkbQF zPt;)8G+F11kM7+U>-ITy%PVtU$n1CES zEM=%WS^c7~UkHoguUJNh1MKZT8#v%d-M5dF#F|b-v~`xA|NF|C7nn-DhrID&_Zb@5Yb` zSTZ_t97SLjuh81T?p!`)>jqtw=bg*cb-6a&Rk^s``1+ZcdC$v! z_PxFHj)A**k5BYn?c-;Pdu8OhjArI(Fch47{F3s0iec<0L$X*{B2AP zE0$ezE#Uw~<-IIcZf=tW4ochOI{UaS)EIutKHecU@l4Z;(|w#f`+uDi4EtQnC6xBA zWchM|nF4-H414mdg&x~n{lxkD>Ee&&yUljg%D#KBbiL`c+uvsz?VEgaceQY3>y7@K zrgepNrzX6A6E{Pxgd;Gb;!5z9)5j~h{lfP1WtsCt?se`u+2VZh`W!EX7J1bf(Sa-s zO&Z5GW+gNV&JbArY?|b)Re>JgXWcDRQ{BX1*^r^?q+*r5)O)7I^dQYL&z08G&t0m0 zAO z(`0D8yEiB+>Q&UH>j5r`OzNAa?Go*1SQV8fyV5H_`Ezc_*=JdIZf)Y1UG(Dl$*#bq zYHIU6CZsSq?6G2Sh?Bp-aF=0%_pS+P%V*8M?lFBa>&?l%eH%iyZk|$m>$c#{nW4%H zxbAy|ZR)MjIl5eT*Ugm-SBeW0l-q-sx*U{im?kefcgX?<28J8i0yi8a7BDd^ko06^ zV9@Rn+0C#o>!>o{Hb%~(8!JOSbyD>b946k3XJj~6#%5LfdarAb4fmnTE0(30E#+Zg zs9MG1V6=0y<;9=uuUjJRt@K^RZtcEsKId24zU1szC-S#SIY?v*Oqiaqr=Zt1a-QY8 z{XM(wZT_5RoN0aImF&5%Up;?j@BA};?~fQQ{jie#*MDz&@^VMC%jZAqcP>6EH|>PR z^p%b7l`nRy%Jy8Y**#CE?4alO9@SS)VV5V!8qDy@Zi-FV=)=HpcjDQe<<=n+PA%KC zVS$*Su=}gB7YP#;W!M`!gPgr5tKOaNQSkD}Jh_#<+`SExIhdl%y3dD9cRKm>$UgQ< zPo5mUlAOfiU1Ygt-WP?X+u93d ziaVR{H3>WkyRxtMjfAlV_pO!3Yo`QqzB;r1=wbg@)0vC@@ZIH^4ocJkF$@A8#rNh0 zT~Sqp^;lQWGTP=@enn@*Z@iJe|uFmiL=i%c*ZS~jBcW%`Cw^uBT&+4Y7{{9OW?eFb< z`gY;`xcPnaHSsG|^sFj({5^-!Xm0qG5|Q0PQ9D?9pB&k!sJY4N6kEpA2m=Pwi#!)iEN8N* zvESl7eV{_g;AdH|LdL~rZ)d@h09;N$p#tKm5VL&NS}te1s~9?UzQVdsA&t+JxB?`y(p-`j%c z#CAW=2tLkgxr)P~$011Oc7IE1M_QQvQv-!vjFJa-U4ELm#1*YHn&!EM!wYTrH_LnOkuR1B3rI_|>>gUF8Wo_wGcPc{EHo0Y+ z_M}hV{H-K#eaxc=tJnOk3Uap;WPHEfK3sHR&(jIVB^5neY^Qsldvg1sK>3TzU0Nqg zy?3vgw~w>XcG1d&6m5>pWi_K@!^NwDyBPeUo{7q@pE-+l zrwK!wM4N`%=H!p10v~b`Cd`cdY9ZlhQrSCmUaI`n-c(*!#5P8} zXI1KLcr4Mwbdo_pS($;EhgCF(IDY)RM)>JUN!1ApX1u@o`th8TF@KAs4i|5e zy>~t5*~|sA@>$Io7!^S zg~E|<-fpqof9;%#`BshhFT4sZ&M9f`6;xdQR#0+--BQC@JVw(azW9B371hwGSsI=v z-Y>G^s)4V5c6v^f`qmzVrc zh)?p1;EW6x%~U$fa8zQJ(@L4$Wjw(zmY<2^YEMhlNRHn;{hnS$8;2=dOKtl{k=}VX z_QcN%P+spIDWV6)4in7u&_a z03MxSH~=p1Agd)n>r`$lxdw~=Z~fo(f9C%=|7ZR0`oHG?g8zO0SN@m#J(ZjLo4kVa z1C!rJjdcwVn>)5H_`%Dtp_R!dXa3i(U$0$Tzrj#exWI&w!C@^cL(CETYyZE=*6rNp zUfcPZFD|yACtPqEOW3i=x32a~D`L9;W$%;156_N$^ViGoQ~u4ic=L<(6>G|Bgum2$ zNNriuFF*fPX#DmU->0Td_ADB2cOyoSu;QTUOTs1H{u=w!T9dnnj^m?>z%&zdF!fz9UBhh+)S6RyVAWVG;km1tr?p0419zb8s77idxcf~^7_6o!uR!=oRa9P z`{Ul;cy0aQ&GUMDE8Ci5i8{|ZL-!~0Z!BNFFa6G4AGenRI#>U!Sikaa*7K##d;C*V zr_?T(ouRty%C9q9JUW68+Ul6@6b{sry>V#kEyvW8udf)r^4OiGrS>!<=}v0au?-%p zT^_ie3E5!aKHZW+|0zw>xuk!NT_N z11VGbggON8X0{o<^mvk%cOmI{)ZBSYA>Y?kgcn>?ERi*SHzoY`!}LQF9!J||o%UQ_ zbvf_igOW9@(QkaF&T9+Jezvr%eU|IC4O4p3Zb!cB^ICi<>p|hR6HneUGB8w3n!5VH zhcCwYao;W-Or9oi&C7D3E@Q>k+z&nStK8z(9q7_^JC|@Xwkd3!A7b3cTbudamOagSIaK$`trVv zO%reA==8g<65Krf=h(%vC`p$qyzauVR?yl^w?PID2*VvLDLL9YqbNx7ZmODaQpE z-t2kYnS3?)@FVr4AWz|myLnuu&wTppnz4(b=1c|WGfr=3T`pXd(0L-SiYbJ}VY7Mq^P-itkk>hp-DCRyDCImM72uZ^-5MGM?}p=0Y;~i zMuzUM&z(e*H!3_Z^=Oh<8R?w#$byk!0cXdGm8&FGqumn|dsa$;OuIMh=x&~8>|Spg zujm*aobZpC>i|E)g6_ky@BUqUarVaJS1XDWK0U0pPTPA$>DnKXI(xsARlr{Ap+J6XBa ze%04S=baLlzv`JcsV>Qxg-z7%y~#S?d&f(@edCu8UpK4MkH!7rE9qHM<<>KInOJW+ z5z{X{X;q)B>X9?EG|y~(XV{?-wqbV5sTg&!<{2If3(qdtlCCH?-KJ>Hrd`36U1v6` zs2y!o`1Rt1+>+C|1}F7y+OoK=|72uX&AD;aZ5;)l<)X)RonOZ>aPcrOtZ9zznH4R} zZ9S<|^2z;NBl}m(%bRwGuC3d(c;?bOSGAgB7eCs?qkj0>FQJYPzbt3m+pW=Ln#Z6K z^5qPdr`d#)HE-T9F(j;B%)sEOKBr4ZdGS*P;l1aMs4Hx{$I-%{?&?>>J!AXhz0nL` zmTMef@DS|NWo}6ES^j(#!?z|bF0Kxx%gdPqxB83Rz9z)rVKQsO(M9VS87!=YH)c&% z?ckcl<+qK=?$pz+o>}z^R2*JT%Q09YuOZPU&(Lt!XKHVx_RFN0a;Dcak~`dPpA(#R zK3BY4h=IW*h{1tR|H$+HdtZ6{{L^;dyZ!(4xwPHaSBNhwj^12E3)j836dj6AC(CPvPk z;k#~G#6v-5h6TPJy%X$3*9v<{8MQdS7S!NwI5u^;*ku=slTzZbVyywMq|0~iYt#5_ z?7F_ZAki->RB1QIU(x$A4VetDW;Vq|urnQFX82I^P|o21gM;yFCw}i&!m}J)gr3E< zUVR%JbY!!5>;EV_fzoIaCXa$#Wz)>RFt{ujBZ*6Zn*L=Jd(%ftjy7`bENltSrXg) z>&^A(3C%lp&uhGOb7{f;t+|~ZENy~2Qv@G`MkYq(#jk!VH*%@}Q2)4)_P(BqU7+_Yn zEoObOQ06rEj~Cw;ohx>odMx4YTQi2h76-A#A(vWTcxx>ZchuVRhKYegiB+^)kof@z zg9>-R6wr3u3$Gnw|C=z_-4mZjr1bWUI`^Jr z=Wkn)yQKSz=rP-^Cw|AC*i>enb?oc90uHmpb&p+_$9}%MR6uzBs|n?N)^ST7&YHKu z@7@}RGS|MvYM)czwKdAfb`E!5HvQlSi-$& z>M4hwZs*%qJ^LDq9`IPQcgbwHtjkg|;TT`SHcRm-mYPc#k{Ha-ToBJzTe_ry>50~< zgI6#0N$+01D6PqH7lXmvKBHNl2lV4EL?m20H>+`nc*>dH?~}WOtX`EBZkqI>EbcPv zJ=2}h*S*djSza1(@Ha(el#l(PtVU^%<8;hgH&6{sdlaM~9#60oL8LM+{2M)*QboAHm zohEcVwTiKQ1USdtX&Y-(XrFuu~w>M{^?;2*Te0Sl__V=z0EL=UT3@t%DX*Y~L%$oX6 zX3bv_wdQ)**@TF7%1R6j`=pKubMwfj2oy-E3HN^D?_fQ0pMl}GeDkYY&ogeHar)HvCT?JE)$$06&WHJ6pr#S zGE8u~vbF0#YZOn{u0?DN_p*)(^ZFcUkooepOHJ$vGeewu^1OBx)@j+-S&n7=og=H} zCAG*lbRJvKz6}LB%nS@Oc2&=KeuaO&MAqK7c^ubwJ)bw}-ph=sV%J3lPhNNu=@@gp zfLr1Jh z{CZ<@m6+t^URQ_mDRa0uMe5p`j&$=vH#YVSXYLxeZ3ves-)=nN`mTk~wX`CA znk=r$y2MpKt~j!6a-Y~r?(1u}DkbnSC~Q)hc}wlxtg61&qD7qNujO1cz3e0ws=DiB zkrCg$K(o2d*B*2>i66DKjpTX48^Rc@CSX{%C|!GH)}__mi>~;$?~Q0I_2e(CYTNM0 zI63y+>9@1(y1wYe>1{szqPn&!aKRRl2VJk<#Cc3oINh=+`S_dYinK!k4^KYPdCkpW zaAjWfWd;U@ITeBoYixKJKJ4A?zDIRZtNc;>{gbbMj5G6Yxv>70^)rTU9)<>X`~Fwe zdv|?&#lmo4=`jX|hI9X#zZCjjWa<`i4Q!exq`1*=-JB3xhK3X$A75WrhGn1`7-8;j z@*ay=lWWd4wFrOP->Br|@Q;n*hN4l<=6lh#%FpHqoOP^xAHu+(z{Rk^>T^X|&WvJp zwOiM3F8!T3@0Z@^p0+6p@4p5d%1T;(P&WcH9>NaVo+Em)O|0jC%m2>*6aM%7-}ryl|H=O||Cj#H`JXeT*F;#` zIqh!Y4V%=;YPrQ~3L92s2C3O*DK67EUG=x@#Dvse6OzkZPp;4_@hXk*TC&eWn86`| z;rHKK|FSE*ESJxm3thCvL#ARvqnY2{O)pn(xS=tlytP_z=T{ps28jnIU%k8frp`&& zDAUO4xNOM+me)%iPH`9MOpuXiW^fbTsG||(vUL$tn1wdeKdV%2zE4dHoE}~Y*PNBW zJfD#(MBrDghkN^!nVa1C_`YsSPM4o}Rej&WWWJ1hUE(ts7!tPcoxEkzwY$Ifn8^LI zsIBst=lA#awfxuo*Y??d-nO}JoAl3BXZvQ_PC2{L>UQ1EW1GXb+0_JZOV8i8dHG_k znYQ7j69WtW+sK}svOMqd)!d@iIT=-t-PYG_es&_W4-8C^$XRQJQgM!$$29E}rwG57vB3g29 zi~ZzC=v6Rt$W3%y*~Pb4Ze?inmWEY!feZ}uUi&KhrvB#Q3R(s#o3C_EAY~_i|B{T0VJ)rn) z?VnTUeCOys-0@}2DOG;k^eKWXXY#NvTDQyZm@Vg}!&4VcUub+dh~K0!{e)k?7;lko znf3IJPMNPvMnTKYu9(zXd{=J!nHnLFeUHWYyu6y`bU5*{e30>pqux z*95vhdiCyzS!?EHDs~kqu6f2S z+I~U&@+29nM@Jq-6rOKibS3+#Nz~MuCEsVS4!#tBFlae51H)Ml29B-!ZoJ&Oc=7kSd#|fYA6E+gv!*3w$~?8qzp^_Y zec5QTz2NiVZ8>je9~Qpsy-`>6;{Pd;!52+u1^P*!&;Pw-@B5wqe?G7ESY8!ncjH^G z(2_bKUmw5F`0vY#4>H;*7+sIJTdP}mZI1qDG1tQ8LX+L;cV_QRGnr?&oS zqIkm8i}J3buJgL5@~yphy6~;!!nL3Ntm*ijq3ye|N^7glo-|$1$w2`Jm^QKU<*43c z*fd#KEn|A<&vPfor*vI6ewq4SYXs*c}p*T`&mPkc0P+0zy54x+-QGu zSM~hc^S)g@w0Qej=S{XdWX}G-IlI*CXXm+pM>%vtR-SsgXiE0)o5dB{AGh6K?@^Vs zDWRyz;pBDYQ)kYca5z5u_+BfHnapS3$!=j)Jes!k%Es@uk2gtQoXyC;c}wTPd4;9M zOs!!Oi!?j#ImMe>9l!l7@=yPqFJfUavn@(><){F$MTMs;f z^jF+1#C*+h25ZrOU=)-d_wx&WC!%nT3y6}udYJ5#1x{q(9=isJk^ zdfyLKr}akZgmr6fon5H?Ir&)8hu2;`2Of#AuYC%dk!M!8k#qZ$&BLg}Oe?g)t9X`8 z*nE;vBGN>O&5(hCL8tj>(zo6he7oD8F)+;YI;!kr;Ao(*cv{fGBS+u5_H&;6%f(O- z+IoCiwRGLJ?Q746ALl5(zuoks3Il`JM1~m#{lCo4RbM@Q@cWTvyMK!QnDBXdb_Ohb1z3o)^j{cn{JoC zaqpac|7?#ZDm2RFFZW4%{r0Z2eBHic-K!rnrpdhe!s6_6ZP$~K-J90f8hWf`XX-4m zojGkvqHENy-OD%1W`%f`3otL5lG%RYWzNyY<9rL;jxIcY`gEd7*3y(FySJ>h#>tJx zr^r^SO?|1+W2LRC%NfB|lr%ANuY+9F&xm*HgyQ>HC!6hT&cz~ zNoOO+0biyxudbx?3nsPtylLM0YjXFC(!y6v+n0%@=bpb*{LJI_H52=0(e)oUi)~bU zvxDoz@9Fa!Ga2SFGB8Zkx^T!L!1ipnjibV8pY6|-P8db5udq7Na%lE43jt+7!2Lr zLD`Do0K?W7A*>8`Sxeb@{xCE6t^VRL^^0c$)BDn>IdNed*vd5KEqLE=Yu|s=BkA0l zeT%p5(tYt~%2Ot}R=U3`R^~jHCXi@kb!h5MDJFjN zCpw~C)&XyB9-jH4GhDpaKVIhco-lJkIsMlQRk{Ryeh0GWX2!;Ns&YPz@>O5Dr~Ar= zQ_~E&&qgIqnXsW~=iRrd;-988bg$XILt^(Fhnuz@`NnNtn{wtVYMuBbQRz0TBGY82 zkvAiQLFwC<3wBocF`VdRVs_YN6!`h^xreBu7EP7LXi6 zKkp~$48WOME+k3*X`ILgjKh34uynomQ4n9_!GN<4HKLh9>mB!5*_uWk^ zd6N7?aBlO2bERkIZeU<&2x4rw{byfd(N_(5^QeD!)!)moSG{<%)J#i2L|zfDPL! zSBcKta%Wop>;L(SOWteDx%Mvdj%jXg+^Wu#uY8vAC?)c~<#{jU!_2km`koiea|{{N z4qe>jo%q72Lhs4%>0#nm=E$XiJkV(H}cZ8$zkcx{|s+I7jSD)4{ES@^~YoyFf zj*iaxEC?>=RxWVWe<&GqjNrBmI;JU1N}9r7kTVBGPB6eWvl#s()vLjRd)$AJ?8F~)2KS<_CihV4^u&2?RnW2@jA!)C6kq{%Z zLTds8Lx`@CcHj8 zI3ku9yg6%j_)ms(SiF-}yLBY!EK={ghWB=_j$d?kH*@a&xqn>CA3d&L7PY#t;Fx{Y z#5WU9b7$7sr`ekA+fWl*|L<1p+UjrdcJY174=*uVr@SL#@xA9+SM>Y%taJo-us>^G z_PTlJja{8fH`K+QnQk$2-4gE!ds}AhJh}ClMB1v&h1P$NqblX+bEZI?7GPr0(N zr)yTE>AksOtp+-#+q`=>@v^NgVZX|0ksR$2nCiNWSOut{*Z z=sJ_VF*R`_8*|N0iCRXbRSA)yykZOogmQje(+(42Fx(Ml%FPhKuy5xTb-f2O7}m`9 zu3eS;edE^zF;3bT2)>YM13BG@4ttGYgx|y&_OvQPbVizGX28PG`ozHD~Ip0Lm z>DQObKR$f>EB^auN3D(QoWA_N|NFjNO^^C@Swd^&-IU+cB(}{LTWp$=GU>@)b@fkE z&(57(d-d3Hb&sI5Ujh%6G}aV7zhV%`>C0cZ#bEt97s(vo{<)H~Q@3Z$;QMVPdbjZj zo38EI5QB*?Y>U{u&%RXIthMTGQTML2E3y{iZ#8aQbKsqu@wUtO@X4)#oKA_S&w1Fm z^|Ib!?v!|XAzMaxdQlAHot-WnULDgD3v_02B^(i}x>_RXkT1q{c8bvIex7Kfjwx2l|Ak(6 z@l*_4CY!FU=P>of0nx0tjH_30#IfCR=7~+J65WybwypKtt(n|Hi!v0QRNAJAJe_ds zmY29{Q07aWW!qnxIb04ac4p8Fmo87xQH+~>r!#o*o(Z#exbJ9S35mQ@vebaLW3z;m z&5fm^DlTd&@4WgHb@^B5C6~*~7UwZd&S~M$TC!q?Leb)wDS;)|xKd9|@Hm8(WoBT4K8Yorx=hQWRU1qC2%Z=WAWv%_zt)VVY>-!UL%f7qT!gY=2O- zbAM~s6u<7No<-mjGp6*(woGJXVEE|8!thdpVOz!&?X@Sen=%|4mvp;rc+7R3g^^4B zFC#-v;HlTg1A87f-Fg0j_kQBcUd0t(^)8z*Fr1K5^;EJT z*yc_TR=wx2_qdtZiGm5=fAU+G%X7b1vHree&7~DT|6RN7GxyEQXx3a)j^1B8+;x*W zZ+u%?H+?~ITiJXs@AIh^6XwgZsuo%C&U?VP>F$#1$dsAcDm!i4rp?RZ^l9jLTE^8c zJ}p7Zdefq9O1C&HJHLf3+%dQCI^U}G3r%d8!)#=qOLQA)DhIzbi45GcO`OMJ#^a8q zRb^g|&th7n4u&p;Q4VS&F+}wR}(GM&mPgqPYrPpl3b$U zvXZ-ShDmtb)sWK1a~T;Je%M@^mF>G#>Q=Eaui!-GY)0u#?N{}`DV^NL*zCaAlvwIM zX@kL`ZAH6l=H(oU>(;hqd7#S6;EIbE&e}9U6|F80Fv9C+O(>m=~&8_R3l%_1p%W5k4eaCyZLd|rh^vSm(CW=NJ zaqwlh!drWz#G(EEQ9*8o72iI!alL2Ua49j7vEq^2hDXIy7q2?kXclm87027M86HKf zU0k=LI7^Fm#g#ts$keyDJQDGxd+`KghASVr7WlAnx0T!2>ar;oYMqg9*pSL_fj?nE z%FSsUD}u5kzC?NN{VsG+rpU|Bmm@T4S=+ZqZ%Y!7dN(r)biDBAZ#*O#&CIanBbVUJ zoDWB%*MIE_V2CJ~$Dc5poB4vo0YUwY%~Klu`(EwrHaaGGf11D78 z5@jo+dZbMLfGIb_1tsP;TU}fpef?p%>XA*1_WJwfJMSy>JWAy~bi#H~nEidfS4Lm< hE#8>6cHP(I+mk|LRTy>3kDXS~<~yVpv(zAh6#%BJOYZ;x literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/flameray1.ogg b/src/main/resources/assets/wizardry/sounds/flameray1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..587f2ac9497a68dde566452ee74947cce1150239 GIT binary patch literal 23817 zcmeZIPY-5bVt|4zSrEnr7mZbna*Sp9MM;^(AR#7~H6V(CfuRthcn2d`CsdGu0i=_W zfq~)ac6lp7-T!ES8Df$w0|P@uW*v$42C`mM;k6o2xVXpU|>j4(d3()=Bc@K%0i9G8B;t!tfK~O!l*S zxngmj)hmrH7o50tw_Nh_F}xaut3>z+GEW{N>Ym+SuSF3X)J=g98(T!|_6yZ|Htr=ZC#U$F z{o=z9R>Hspj&=qH2Sb^og)%2Es`v-#UM?~XFSfm2?0da5HXIZp_;DjRy|6GaD9%lr zmes&vJRuPrETDjvSjgeb1F?yPfuUpJ6NOn9W_>WPV)I2zGIS!bBfPpUYf?ChPKv2%*g z{Y;tj?kp!r3_bZcFfgzr-jFypw@IP4k1a_=ahc*|xsraq$qNimXfBcK?Q`>5*&Glg zslK$N3G8zP28I>^a4Loo;G_&m#Y-l2X`Ry8e8%Xs4v1KD_?*@24TlAsc?`E)^3pNA z8kXF<_1V1Qb(S94OSfK&(q1|x$V+o6IQ&2vL?LB@Bby{RleEn!I;FXMK@%4wI3W@D zLFK%l>_sGW{-aEwkZPci>O~{nU}M|RkkIh5+{o#rx3{;(-YC6)z4rd~-gxmg^n?Y^ zISfu5iY?$gIVGvb@c5i&KPOH|1jBMpp~&%xGAAdhcyChiy`*#YlZpRllZ(QxfhNAe zqOli6OD~J12AjoRHch=8ntHV?_2#zJ=MU*W29(zn; z0cQ(v&RL+*_sF78*>jRg>@>qicCb*Yl1(jm~MA zowHW$T$FQa-RoTh5j^L(7pb@xfpU&(kqT1IIbbN`9Her5laB9ah#ze)8rz1JxQZi3 z00YB;2|V85awITF_iB*o)gax_5L^5?CNwnks)_Gqlg0}ZrZO-{GB7+@vg}F~pHR{S z%TC7(4$mVpM`NsB&RHDO(>_7j&GW5d@EHM?turoowu)SN6qO}g9MavpHpRnHciXWb z#iuLSot(os7#2!0@EvEA@nx3rW(F533=E!^8GJ<;&kBQT3kC*;0~bvkgl!#!U7^wx zQ8K>FCV?y_fsg`>0c6p|5XOrpP`ez2T@M($I+%n~WC>I=7P|sX8U2y$axn3A2=Rp~ zAEib^fR-V^$iTqJ$H2fS=Cn{zo2kKqk)i#u!z2aI4<-%CksoX-qwm8Jpb9| za*IaSqD-bh6JJIK23An8n`L$ z_jzI0%O<{|rLosp7iG*^wsO_F*Sj3R3a^&Nig$p-R_$8%nhB&RH1_(`)P~Get5)q= zr^6f)3g$~LShecau65d{8LpSc-kh2m$@T!m+oZ$5@ZbO=gTet0tCK4>aY*~__`o0{ zwMmJggNcEmC(+ArDNnMH6W78-A14pRl%OCj&81vUTB=in96gpU2{Q81T{Dd_Jex&+Fuj;&YbjOHd;r6uPqpD&pb^2e&B0fd`=Iny22iEYow+vdVetvzBFMOHWfR}aA)%qIp!V*nRj&_i1BL(f(!|@VR)IqLKxypt(p1SE zpz2$Pn}NZ=f>S`hsgTC#3LWv|^D#vpO7mDwS(rPp|k%3RStHgTykP(j`}-aty`JTe2@)G9{`@bK4`!=S!AciRv*t z78S#-xO7TXx9&EH**S_!rUYdh9*asg_S!lns@w3GM7ECC&M86J8;?q4_quA#jt0qQ zuQkVV=F%ykma34K=F%xaL0+1z0!|Q#rAwv+aVfS4 zfF-;*L0%w>g1lCOgdi3z zoe~7rp$W3cOLHky9jI>{qA)&W6cd#K^}1oM%rk zFbJ@3+;S~ybx+YLPtUc^Zc@({EV<#yuDCVAJ5|B)l&9C+CJs%um90HmOJ_`;=5%^S z5Koe}VM&jnyXDgmr{fX~3=B;S49tQ?!W<$Fjg34E77iX0m>9UYd1Mc}IymSlEAwi<>L7jAg$ z-qE1P9CP7lEV~njlR#61i~}R5g~h`*^?M&$q~|OM4teDOt~%rx9xyT}++@$-^{?k!2xzG1A`)1KX}vw)UN&Wr{{{fy}PHkyNA1nx2?B_*MA;+3u{j=ZwFf& zduuyyKTjVo4-YSIPaj_&e=koj9}hP#4^L0O|DtwxvQ{!O2>bmH^X6rkQSgiXO0c@h ziIXQ!o)i>F4p}2nS}(GH-^#z5-`jr`fBgOI<>qhgS(bly{wV%f^ZCo!9EK~?rm{R0 zil4auM%HPsrlQXN6Y+2C9GoW1k>PV#$&lQ%NoRhm_u8YYI@|VA$I#7~q0R7;%R4!8 z+S6NIivl;S3Ude)`TEapzWJ-Wzn3l8-lP!0@_$u_l9cPjOA(w`x@-koCgoYgti2)Z zsPVGx@LmRK$(;&Jz6|aWQ}hpPh}pVqMJDS7twkAY8AS!RC?$nnSRtnUA@AN><==W2 zS044&o|<*>h8x44S*5Z^T=Ok%#+}{8_h^y%oHup{-2C(yGp0H?btLYbvM_9GhKOrm zu5Q;2w~HNXqgX<-dy_6kh)(>h{oU_>2 z*dJhFO_XQ|YS?*BT!lxRNo$Sk;swDDBGIC}VXpgR`CVN_)^^u=Zt1vjsivy6PvWGX zegY@MmU*7cxBu16b>RFFc78*1VtqZ&l!oujJu+h63}WVuOS5JzyzsD)WqnBZq70L+ zgwU&5+N-jj?A!YL_rJP_=e{k<+WJcOj%~Da^Axrt^AZb$`|spdZaq3Hv4Fe&!Mf?! z|1+LAaYB=6!BQRtO*I`B%cN}&^X6dhaZwe-uE%;M^Z;^HOWAHQeV)Ay3^jT;wN z*_3M=FErlua6H)eirJ*GrG<5YiowAhhSLP(*yl!dM`&lw(uy!oTD_{znMigtP$*QoxHC-pTp6ps1)t+^*Lw8Z=kp~WCBJ-b>xUw!;$8%=h{qIU|l68AF zKVRR={d=8MoBVW_bIlp{2N>>~GaPv1S6yA!9^xkx)M;t4 zr09@{cT`uW;baDe1!*ealBEHb%YS3F}f;R6QXs_SDNUNNRfWVpG$c zO^!M~!5a^7B_&2kv@OkyV)s6>XJ@Xaon`mW3F}RxLvux%#a26U*_28+S%1mWIb%OL zNiddc>K8w`dDRXqj4US8^iKJ2TB5sn-L{`ctXehR+t?LNHM_t6O?tn_TmR?PVgk_u zya}r}>)y(LY_LVJL3wTg+a$TU+UMuz&J*2qViG&U-1T>+sp&7*wheiEbiZ;Dvx_%Z z3&V?VavpK7^5w*8eyYyQJRSAwN4Hze3H{!OU-ebmH5jhcmEPQvmVBdJziexKtl8R| z5^B4}ck?TBJd|J#Fm7z7W!-lxt3J zSYE8XVCcmzt&WH-U8^!oyCVuxS{oOxE@v;;s@1ra=>gM~dAFZUjrsJlAb#ufZIw%R zJiT0SUq0a|FGI#e#ve&7=`Om0Yu#4g@NzX=q_t{^=vud_j$WxtSFAMPU=F^QBEr5< zXHQG_L~(sFrX%z0zcoysmE2`p|EAGmRpKuO?R5eSx~UBNSmqzz#1k1K9vL}#r|nAn z_qlg{_Dny1ddl%fRVR9Xq@9q@dp`er3IF;2S^uuRb)TQWaAe-rtGd@`@?RF-b7S+i zT~Bv?ZWKCTEpWgfFvx&GS15s{GRAS5fw`+zORtFQqyy_#_1few={1niPR+3G6y;-B zlJ>W6MGjY}snT-V zkTCI(#_gCm#+F6QOQx;#5c_>YGI84#Bhiyd^47@~w?@Ixkj z**Z=6k9SqW?=F%NOL8<3FnSbOn9g)&-phrLy?y5_zPl!JhHj0r4zv4ieg%V0L58y) z3cf+tJDvtDVhvn6ZO#%AwGPLFi$s%Mv>z}fx6b_aT=eZd_A^aiW2en2fBW!D`oUj% zhbyPc`u&gCK96VOiA2L=3>DeC1D#tNbu`pIe(~L3k-Ij-;EA~D?@bTq3!i27F)MdT zKCCt0(e{DTT+-DJen?$JIY{zh00$D`SD! z%rz@kDQX9XIPUG%zq@U>RK%JL(`Q=O<|GD$$$TU>tC5Q(d{OmN4&v-CD(dP&Xqa*YGPEASD1M6gaMN&!!&h|3YiU7 zp&?hpLPM{v3cKoIz9>V4VdIv(#mf{l@2)uKnmatUnH}7`l<*_SP*tJ;`)ZKE(lpfNWfz*zfOmqamKnde@vD0cYMt@l^w zRhK{Re)!?`|JsI$?FLK>T-hGX?nvno4k*-$`s;P@su$zR4AWH&cc$&099^s4I!j0) z>ZoR($mu(t=TaEA%$mq{sriSZZ28q5vjq90)3^L)5avnbap>l%so10#aq82>4$80UIXqpALQPM}HBSG%t55(ifWns7y}&0;xImC5>w^I&TF-YraDTOJh2 zFX)ZY=5XLum{Xa^r_Hr$Yv{%dAHj_wYcy9xxj0^2$%a8B87HerAoV0Um z&eSe9?Igo9O^r`xxz+Eu-pk7Dr@46lj_ZFJIyr^78^jo6gr5s0@-eP5U9dSI&XGeSPEZg_`PN$aE z)^_nNQO!s`{ji0o!pFf8I^SBPee&Af7a@f2R` z0uO-)7HXX?(#l?wQMx9ypgU@<#`f*o|Gj%> z75Om9_s4GTu(ggF`IF)}uFSi6L2})*Y3J(W-_GQn`Y>zWmw(^m8(f?u#27E|I9M3e z7)&?dnRadMtOd8WMqTCj{?n~zk$1bBV&0Q`TuhGlMYgo^1+MC9SgU)c%`;_tqB0k2 z!DKcw`t2J|6MPsua&BsT(@EO@~dfTLYTI`c#T5mK=cw5T3r*CJgikyvs!m4ySg;J@XtzuUEXVeUMdcdsye(w%@iK;kVgmEHJQSTflo@%LEfU z{)0>nT3vp^&MkGQ%n-WEs+EK22C-iN(~a*rY+LAk##h}x@4GemJHWM13SpvbMaD#^A>D=JVl zG(R%YpwU%2>cSQ_QQa`U*Q-OgL|>igm3eV=f8d%X+s#bRHwG9?SefvC%>hF(sT2RM zT@e%PT#&$|$5^mTSZ6_S>(py=w$^ulk=pXe`<>v$h0Hw*UTsk-Ub|8C;35SMmy8JA z%74r)lm5y+nJvbZmyTh$Stg9j8U`yCVuT@G>tf$rQ&%N+Ygr|u? zNB=$L^Y|)tgh0V8Z7#(M~s{AtlO)QAyZ$El+Ec;IxB$IXg>j zmng5Q@LZm7a8Vblv*+|%=CTbF8dw5$)>yjV>)Frl=r^Y=>a^8E79J*!n-xye5>DRL z$eii!sj^ntxIe|GTp^T+fx(bNtL386aV4(Q$YVuM-fRm$DRIxo$e-iEgG~pjq*`xk z7+1dhmmI}#r?0U2_G*o->YH}UPG-9lIwk6Zj~#4eE_vyuGU@!ze+q_BhCKRrE|fq}sVF&+ULw@BJ>Xt9ZlmA#dni@&#*y-$#< zm94eE_kaHXvd;d#|K;p#Ty4BPJ^a1AUEF;=ef)eqZ2UZZ0^I%Y%)6_2dBsofg+fKs ztIOJb1Yhd+dOf($E?_bzi9t&8L0ab{n|XcH*X_BX9I4G-CBog|;H1o6m=Kb=(JgI{ z*1hxk=8S9lYvMC z)qFHl;OoEt%^Pg3C0WkQO8jt1EKt!+$vC_1pmzJ!Xb!Hw2yjIZ;rD+aI6Ur`ru=)RKzityVOZUeQ%4_vB61VYor+${c^{VO8fwJvu zmIpEHG(5)eBt2(>k-tme!CxNJ?@Mnwqr@r9S9`tcleA8{#+!MumsZD|*1z#?UhcKs zF-zh%)H0~>bZRp6@+8D~1x&d3s$lV}Ac+>KCmFHd=G*J<@M_l4?kTb~7r)Uh#c*WS z%agq2v&E)&n{scq|1|Ydx!-$64#pi~%ol>#G~%zSX71cHNk!LjgNCD{0?(wZrTJ?O z`3_&O8 zlGkgA;6UkOpDn+FRxg;hJxglKf>n3!zYklXo8g#k&=uj_6ynew*!hM*dl|!)q`!TA z`wSP&snfpp{)K?F@~M~g4ZaZ#GL2deMGYAmda0I6S1l0Txa!8DZ~<167cK#=AtsAl zH?ppFK3Vcnblvn;=A%imAydWe7+U;l8JDCk(Yf-`YvnzTGipI%uYP>bQuP-yiDt@U z(3;HC6?}Ek*0A0yBIi8{C%Zac(9()JsMVFUCS&95NyT<2rcD!IUsj+a$1ZfIYh&@I z$`4CSC$0_aanYVVSzRVa-l3sKCYd3N;d+XqP!2i#nP1<&edhUjbKWzP9N97z>tp0lvB;j%k}~ZPdJkqHgOu9I-SUI z{lT-k>24vSdsnPGsucCr=X-kmlk-wXJ7Q0JNpNjWXjb|-JD1^3mu+C%QW=Y|brJHZ z5vLlHWjP$$439CGC?DKbbg1y)!yCV2Y-+teZ@;_m$K-#l_y4Ya+g<;;_G3Nso>{it zeKqfdUq1Y~f0k``=T94vL@Ykw4$b|g;hSN+qT z&3|>))rc<)N80`hZrGp{_bT*_e?zO_#~^m53En z4_BIoeSC3YQRtMw5-p8YqRgxK+8ehjRfR?e9u4mlyd1^qx|}KLiXkFdtQC7uH2h3&C7G)7pbZ)A}mICOLCVHArn+yx7O}@v4l_D_a#M+_?@rxP_&}PVV5F^{i=ws9{nr7mGsT zafw3=PA6|PEnrU+Sp9R$!~=i)RtDYG^WYa`b`VtZVcN7ow57#$hK-<`l89eoC+CzW zAAbsjG*5NP7GZ9D%b=jrYB%pr`{WavW(k5i0TZs>{w^Xg<>U>a1&yqa^<5_|_RDrS z^sw}Bq0)B;+jGBdH(j}_6<;L7%cc84`102SH>bDT>d*j2N0H>Up*f*F9c-d3EF4bCk0P{m=a=2wJyTL_snY4mmYH&s3=&qmnOKR0 zh>A4GvN#58Ydy&4%VS|;q~V}+XvHeWD^5LPjRBhkR-G~mQP3=4xfFFZX+!SfP-g>= z1zj>4hqv9ZRI{Q z@Aac3yJ<>ARhyqzM7&rg@&0LTLvIF;LpM)={**7KF$P&vukZR)RC_PDyl{I^l!(^a z2SFyOOD`%~@KnR=Hfv5LvUz?IK6VqKgZi1t&%v7G0C2+tsux)bYWW{rP8CMFsNy zXWYbnEt&I~eFNjV-3gZ06#g?yJou%V{rcLg~mbG?tE4Po2cbxu(l8Dfjjg{q!`}=|PogYj8l(>VKD(sn zg2qQ7Sf+cjpX!<~ zqUXV@HkmI*&|W9}cl6rM4h1*80EUw8sO*5PVJvIU75E5ngzCn=V0CHNG3#3JDnv1_ z<#&y9vvXmF2+N{ZW(wU5(tEQ03OW2>UtWDy%!6T}{G4yBE0o$ND_;;;z?1nXMt^>y zp^tV}RK)dH22$M`3LJYDaA|~@u9+kou+QoG;?Q|4ZiNZ=TNjsBvQ3$n$dsAA|HJR) z>2n-z-qQbbk3WHvk&)*BFQZgg(y}JWX^T%S%5aS^SrrkfDdD=BC&_j7#jw!M*Wa#* zw$5!~oV-b?IqBn5rZ@BWoxi_L|C9EAYxO;y`YrOGw*UC|n_1@}3)=#f1HLS6JZX+1 zy~|c`Ke?8*H7a!Ls<4o&nX6ZYt=44b_q@w6)@^=%6Y3=X~6(Z+Mg!6HUi>@L?dmnB*{ zQKf<=N2b0A(`T8nHFExK+by#SQ}@jM)4WpPPndDel4-#;X2FU-^bfe{^)O~kZur>N zvU82$^D`zrn*v^UNnF%YTD3@+b)ojIkd30D7rIW&TXL!RfRfI)=+Xj~HM2~)B`h73 za!tF%I+n`J_{;7wVe;gOj0Me%HJ3RG^-l*a(&$Q9yDiBjP$cuaUH+5&=e>Vw?})4| z*IM#bd*AOp6Swib=~}7P6na*5;^*F_Ai?p`Ztd0zI*m5YaY7vuE^QuDLPyAoz9nLvgG1pus{=Mb8Pcr8} zJ67N258zH@aX874l)C+)SkT_+S8GChSFJd@D$6yboli+KXZ71>o!eGzO>#}DymT-s zRMk;u!eRpr#eFPix(eBBo=K-wi#GFo(YINp`#EkNU$c;y&B0Spa7hNsV_+r+awKBpj<6+{OHe10LX8&4FA8TVh&c3tP z{^2Hhg=qp}3<)z?zWRKKI8?}(y;7@5uUE#Jhq*h$#Wlom)lsX1*Sa>EYOQ)CbFI&} zdA-UTjo=j=iVS<^&E9zF-C22=ob}JMbgcJ%mi}hvpxVX5R7d+acKc3v$j}hpy~G1bE_7Gh8#_@GIaRI_c5oaP18jHN*~XwCj7Ku{KHY?5?_A#xt`fE=ZpKi^F_( zq_L3C88`WdX}=jJ$s~g+u?Z<>gS{+WtXDO0O?<-8dcPtrX1n0>iuIop4<5TyHJRba zq@|0NOy1L-oL;Re%>Bf*ZpZQeOj}%-!WbG@8S7$t-t(RmC=F1ITz!;7JN2rWWavSS zrE#Hx+*ViKEi3D2(3&;Dd6(iMcI`vmb*>W3Z@L_f6C>Sj$o*R<5hiMudgG>@gVIES zD@+qa9XNz``AEuys(UTe>R6?<;A3r2dDP0Ii-hL#xvG18kJ`m=+9|}clB3JD`v5z` znR&sS`%1$v&(T_f@^5X4cog<-|VsUs}x~)GVkgk?xNodcTcp5$Uk56)YbL(N#jZE z&)IJzv>Gy)HuSElusL0{b5#~suiIjc(wE8eS8-(>-4eRCOQS0xbam9W>IEiMu~L?1 zLi;CgIeWqAOx;DEW6Mo9Dx7{Z{Zv9ll(XYBaRtYD6POsLFzBd0YEhOJ*D5yADOdp;N7qJ{@P>sYs!}1YqRf)ow-1FdUX_y8UgVm*xFf7(zxAoARU26+#A@F?ZwZ>p z7nptLR_o3CeUT!IBX70d+|STCak6xS21DvrCmDknohv324cB};wP?ll-If8aVkXzL zx&&7rpY;CDpX4<~%NZ^#kYHpuGw(3N#}}>ZYv0`TRgi00So+qk;V=_JLs@#mbS?>X zp7xJhgW9fL%UZ;@W`ncS!UhLM?-Qq@vQ=G!7BsNl6c(zxA1;1+6GKazpeFCzv^u%v z-Mcl#rfk{T{kJuEcRNG(L78bj3=PLQ52UkPS#$a6yXO(7o@Tc?9bA=lyKCQ$iML#I zHU#RV?7yPABY;Id=HAu+Iw!wn8SJSlmE53M7=3Nu*VWz*c@lS;GXFAkPCP8Ywjk`m zi{3>%hYc@i1Zj%8`u486vFO*Q`CHgT16*CTR~7uN|L{n7wRWbdgQ4O#={J3q#_ZN* z26x|-AK&wGaqO&vMVtRKY!xzKP-R$Lv4CN<#J(iQ)sCT8oFZ1w2e%NbbuL&G*^tF*m( zTYOxHY4@uHiyQR~slJ@d6Id-CFbOF}{4n8aU6sY|n!JUnD{PI<0@mI|0g3A9dm8cWKzViFUCoWNlz&yrCkQuiGH>u;lkjQc z>|F6CaB5dt=Vhn0(TlrWZ6n`3o)#XuVP82MXvg)ca+AXZunmn3=cBlhbwAJ$JIb#{pFP6jJcEaE za#W*vP@pJlVCcmTG1oOw%B!@F{=K@=O?jKBfLD)em{!A93zZeRe=|R(#@I4EnWw&d z^15&Cll03fc0Ly?eX`DeQtZbAzZtX{l^JGDbda9Ld1*seWNC)~?M<55t5>PSu8&H|hRQhm)!EBy^y+Xr=J6EILp6XZ>V%n7u8oP4Us#UAb&z?Pd_7oQp*NYibX1na( zzdzsmXZgwu6RF-s9n37{iRO-8mv5NG6^NI~E-~rNeSCM*JS8Iu%bg5!La(sfygTR%ViBc#`KR(7QS&V}bqd zrOFSo_+)bQ4@_&&Y;?HBQf+;tgs{D+^cPh{wg+kTT_&%Dh{nP=_KyiGgr`!Q?!*Xx_NS2HGQ^BmxHYueGYHc|DAlS81Zf2;q=-O4QI@}gN33y>D z&hxbULJBfGB5tx=bod_`D3)%JhX=xFh6V>*&|bX9+k&bH>eZ^G7GQxH3LgRe|p zLFmboD3(PGm#t?ca)|ec9$lq0%iv5vM3ruroa5%8fDPTBF2wFSrP*n>Doee|)us8< zO35c(iJ`vL(`LE}Wv-J5oB1s#+vZk%L+>0PrT}395h0F~LB||87iPJJYAssPwPM98 z5x3)BM>L`~uCNLbEYywu*?qm_zrLcGz<;hQ)3!#oua$}7{IhnJt?&lvom=MpwPjHC zU^~uGlf+>ED~gG+RVUf$wqS(zf(4 zSUYJi^NF<}79Y!o1_nu)1~bMVk#Qa$I{&Y`By-F8!3l|E%l_sD2ZN~Qq@0O+CNA8x zMuK5U*HN}rwSRVOwioRdP5J#}(r3}PlSyvcGs!uo*y^xZWLRt}$qf{N|4*?NK=?AcUOm4 z=vG;+gsogV0~w}V^Y&2JxOVH44a1UYEA^D+moB}r_imQtORYU8FTKl^Pw*CzWH4vh zG5_QQ#ji5@(Y%3cyx(pLYmZueqe<+dmRQV+DA(0jGhA61S1&T|$)$DM9)HE+oqG7-J7x~Q2nVJMYC<7X^ezY=lb`RUy);zzSJm>|-m6SH zU1C$NWc7$TF+JjZbFRpHo!F5^$72UiIWz2;l*sTmP%q|9`bnLJUux`JLZAhNUJMN0 zY!dkmMHVh;JJSSvHBQNPtrG5CkabaU)e3v})eD(*pS%xPDA~jpyO!52Nmbxcg^q&q zlX{Q=+d^=!ZWgeIv=$h=~e8ES6?VJUN$*NWQj;bmLG%sC$xMAYl#ad$P zk0>#$nU~6}<5{zL>%36rjZ-^~Z?k)t8}S_A?Pr_Yb#zVIsFdNU`&VAPTzs40nR&ktyXd?*bT<3^>!XEcMW@m}GMZ_# z94MOjVD^T<#dSA}{yl$PdvWXZr`7vE87Fm}I{Mpv{`u1y;cK=Do%&WFH|^q)i(6hq z?iRHu(OqTqXcy<1X{kxI`!6c*Ui%~ctkLFO_kT>jUY1kMXqISX#E`|v<5T4Dx9K2P zO23&;sbFt_hSWxlut1X)%-2?yu3Xi9VhhLNf7`Wxt&OkJOtrl->**`s!<)91H+yyD zY)&iMv2k{k`HGe!-x$pn8L%yAWr+6{=HTo%4}5WL#idn2fg!G<*H@)2U2%#jA~G}N zXveDST6T2`OM?PK7%w?$Y}#)vE`Dd;?I(wFe)zszSXk}1+52eFf3~+*>>Car;%IPV zGZ5{XZMxW|aO18^(>w%N-WrtXCxuOKa`Dqj48g^oFTa}OiQY4 zIgdEsDX3c>o6q!7fdAZkW{$QEtc(H7Z>BH2<9EL4>MN0u=|%gay4(UoMOr=7j#!C? ztkDole6b<^?6j7*855m2Di>W02|U7Zrs$%IMz*BIjkMhvLQ7mFEpFH`R4OU@usL`x z$eU%rR5L9xbgA3owtxHV_tiYlV$Hs=GS2CemYcd*X7Ixhh3Kq}v)=D}!oH=eb%pZ! zrwUOQc55x0b0Fq)aaHm*6;tzZ7mJ6t<_z0nGmBa@CQ9xnb-aNpir zOkJ|JFaFz4euv&{R)!5RO;7SSr*+Iv;$5o{;kGt{%hjb(O@)JH^(xoJJCXtmLfmr% z1a3RHW^edCS1D2Ecmv~;d54dl@7i|wZtc0<`)p_LK7Z=-k=wBlF&> z_3T;FczWBs!)J1>mbRYW!yvZ7kfFPug@0z;@%-S-gy@>Nhr(o9;$(!|_`xpsR~ucG%^z`t_cylLYG8MK&B_-7+ux>9)IN zO>vvLZQDIt+vhIuE|X6%mSlUtW^^F?@N=c+kHx2wPR3{k>vx3}YOiuzEwOQtR#b0T zAxFom3~^=l!rK#>*BE_H&3m_*^~o&9vR<9%&6EGGl}x#=G41cclmD2nBnTa2n8Fe^ zDQbee1E+EqpU$c<*O1pj>}wqyZ!L1(%Jv~@tJrF(*{PLf8U?2sy&UV_Mp-gmnRb)q z*5=xeb^6nL(&J8VuK8H^p4sO@ib%s#CIeBk9F53uc6GPNwUL=Ip`wp(&ARw>l~?us z<4MsQ+Z?Oy^bXm1P@40}C`ZMlrgjDNai{vT9$1Aj6q? zk&`A$duwnQXHN@EFl!4C_{HdTfhmPyiyPC+)+q^lqx3Fj^u&p;THU4Fb>m=@=!)P} z$85pSvkem*wl#5bUb!USGHp-L)-CzG(7}d!#9#v(0|UdCTb$k|p8j4QUS7U_-oEZ0 zpv@EirT*(%`TKf=dU*u-_;}cR`TO{IJ9s%;+c}1K2lxkg`FPsRDcZ~V#Mi1|?km99vKiTRHX+$@uR#@K28 z@xd>9huI4hBpJ@K#Hk$VXkWk*<+>&+eukRlQK2;*YqO$6qeZqXzVRz;Wl)%)F4u`- zBaOJuA8&U5VOTS-wB2*wUx(>$!p=WR+j`@Tm=$P0gRl_ug=LIaWHi{Bbsr07Z&hs# z5?yjlBcVHJt=7vuGuLulTh$S<+Vr(2ml9{@(zm()tr_?9ZS{PxeP_@H^^N_a-Og_L z#Y+?Xlm0U*E%fD3*pR|t+?L$QAkPvin5&qTP^z&o)TKK~Cu~c`mAglK+-7tAyRvf8 zM!`F}Gv^v6I51wBcROX_@=ZDG@8A0T!YXYx-}?LS*>C8mGUyr|5V-xjbZ6bFuTOWm zO_s@$-Krwhx^xj=nD(kH!I`3gFGO88L^e4{h@32xXftH$|By9-;YgdUq{=$+mFc@~ zY}n3p`m54cpYM!9Pnw=Yu}E>AxTGt<+J1QDD}gmpS66QJo9osq{qx_yfBW~pkDe&Z zC6>MRTi=w3^;w~z*_&-xucX<^oar^#@^JOhSCSKd2{}vOuPys)Bp|G!K1uPxafNHQ z_6T)##fb*4)eQ|~4b@~l`?gGJm0PHe<^5-K)~{KuDH^7pS#~We#AVH^0Kw4Y zzd5~KJGQZ=eQXKZvP+DaY0bQ&jBoVp3aVG9FKpiOx$*RG25!bgPS7Mk)zYIJ^HqE7 zL}V8Qt%wpVy`Z-6^e9)@H=AdsoE#8(Za{`WYQT0Mg{>d4#|m}*2}MM zN|Fehty#VCpx@fEK>pRe5@nvn1c%|<64fe zj*g8Q$(c&Gzo~9rs(r;gsa$oyfs(;AH1Ku??<_f;o2HyLZ|z)h}S5>RITP za>Ysc`lIQ^mRGmfo_N9;*x#k#u+-7yO-{m65zBXx5Z);f3Hc2diDLv zGq!H}PmV0Vs`Yx(Vdiu5m}@Le7+J+^`l|a+*&kqxUw`Ax-oUyB=6(4L4R=|l?`sYG zxNdUJGB4NNBC8G09yz1Jz_3V#GiZ}b;o+Iz%+~e4nOwN6*SDrgT0UQ*j5Dl8ZGjQr zr3D+7$UHHB zEyz`ls*c`l%g5l|z&zpL2}Z@m3HRUa6%uol@@8X?zE;#Q4X+>rZE0LTpA+z7wrf(0`Wl%B@ zI+kS;adD#i&CC;64b)@jw;VURrx3G5VO!M2wO3bWdAnSEA-ZvEkH$2EBa#9vF58^V zFP%Mm);H>;wRYx27KST%wY(e`9$IaW&SziMd207;@ddu#ZhZ}06VCNS^a~um)zd0^ zImB7_s#O;kpZ&2!r*7W&%k?YgO=xA{>5pZ5X3F#O zL-TRHiP!eEo$WlldupbaVsA_Y7lVL4bJVhR47;|hViOI#5~8yrbc<(s_}+VxQ3=zo z#quSwyXE{Sc(GgAje+6HyzA|6-bUR!W>US+=H=eG+YkLsZQr0xSXZDGRP-2KmY2YuJW8k*n;>telR~`FSX}Bs@ zEDfETY}(^1z#@1yU4W&j@b%m#2d@YJ4^8F!GU?*cCGlqrHow;mUj6j5TKmkuYq#HX zI@Bqs%J7ayO!-Dt^x{?BO&3@eigcM8tSONQwBC7EAgQ&ku)NOAfs_x~hR@3`krcRod(D?r3GApBM3Qmb7d;i6ow>-m{dL-nP4g|@A__kGXr zc}v(tT+LeLOTY2|_7ppow-=@uc|CYzcOb05h+z@K!ls^J`HB?RU8^oH z?C?9p*ITNkkrcfCP?(Eo$&C&{-C2_kI4!Pe72{G~xBLtDo;F+ABd%(nZyj&@$_!@I zGaOVEI>eB|>U8H2SJ0^sEWI6zeodbeBFZ>-6&q)0j$pV$;E@RRMI7xNV$z1S%+_L? ze$QbzGpp43xL#IJ^@O`Qk=K3CESh$!`HdaJ&J8CG7}hfC_`2*p*KnFks=LFd^PW7f z(xEN0GzG(0+(cM@3cPYY&T^-zRc*2K#zo(5+;4iRB_O?V%kh6}qVqjZxTv1sJ+LcQ zP<-PCmnRAwt4cXut(Yx;bx}ve>!Xt!9jD&dhtdWOABE zP-n($+s!wR=tKv3h2Lhs;S|7hL5h=$?IkV0};q)SBdQrkldPH`!VaWWlgySVWEsm?9pmEHx@{Q>0C?Ia=X|O5v#LGLRZQ)gmq(}X~O;9=-?s^#SXCv%@QiP414B% zWIW>k_1WCzUwQl#>Ry>w&*KjWJtWa^^dv*I$Bbt}dJnt8wnThgGvh49~YKg46A3j2jPwwAkczU)ygZ5DahP4wPsHc5yDt)xh za+lrqOV6vG)V(V@b30sJ*3NE{#<#ui?PaX)vuC}TvA)8Aah;YPr^uCgmtU&IKT6&= z$9DPUgKr)^Gb^@Z*tUqH!BzQS=F*uHZc3dxChNMlZ{oQl&Rd?GdA5~PY3g0yg|2n;Fe+N1lKY!` z_v*Xs0s;XNTn*P){uD1Sb~&wTb)nDW^Y1loE{All#xa`tMK}iOUCm=lYPVq6QpO$5 zsmxy(q)>*P7y3TwQ!LbQirf*kXC!C3~en%*C)XmC6ifCVgc-a#JrRUN_R-Vb0}4Uuzq5 zmnbltW#YLz_w{4pX^XCAh|XQHNJHx40>hOZd?sSiYYd~5x%lQz(h1d>vWQoPVYNy9 z?EA~zHz+Kr5?q$^=@~oUws8HlGkxtA99DnC6IitsI1X5IZg{lL`Xl!yojbcC6jNkf zw(^xEgmRi__^k;wEt5Frc;n%H(FpBD3Mbnm4{+5ktyhX-ST)TDE<&8cTs&d3T} zFL|)RzQMF8g82ip@qxLquWRGhyWdOoIvaKN^xaKy?w+<`J+HeKDohJA%IryS4XrE> z^eZyon2@U4(k**5iI<1r%)I65rC)XVkKO$IWl^wx+02)$E7lYubNK})5(Q2&MtD5%v(;B%SQEEZL&|kcSWRHSRfBD^?F;R? z#mv9fef(DKe(UUpUXhH_Rq0*m#w@^O(bgBS8yDTsSP{me+ZExe%(wI?U!chPH5`8W<+UH}P0C85w7JY~iyoP@ zlIw_?tc8D$Z z&hZ$H>Cn1Iz*cliYd_v=_ z6zu)HeS`i>JK8#UdHZ|%gm?$|`S^PUg!p;-db)ahg`TN8s| zxnkFqwI?E;&!6=*UFmhucAsaZ|Kt;%a7H*XZ1Or$u<*6BrH-k#tElTmt0``Qp`xp$ zPV1W=_wDmDQR>pT618H^PNi!J&i6KNZDPGM%X70t`R+a4vFm1+fz5pG)|-B_J`wQqV3?M{Jm363ZI#G_Q|3@Z~wR5h`uuK?T4k8e!j`? zyl18BE@oW~G1;-GICth&i|Jvjq?S(D|DA`c$-!lnlrL{= zuEwM(7lqW0N{4P_+Vnd$+w;->i3tq5<2O!G`DZO;@*sGzTx9;;S&MW|pUDbLiCr}7 zM8}rYd*M26!JUHMU72ZVX=;oNVYfxncPrISImkABUbn}z6ycqd_S`n&UfcOpLOU#w zH>C8Uqh?p0;Vc(HsUuvc5_l8+JFHeKO;I#DCXlEsc0sp8W0y2Xj3O69`wLywRSgRl zwHTgo)UiCo!r{{7_~_)3_RYI*JzFNqsp)d)P@$`FmSE^brUfgy3>A`P3>G?x9Bp;n zrXzA{p;scqG{IF70vD4u-f*eOENm@PVwM-b@GE9%G^d15w?b#Emmfnw>D;N`@-y4E zuly!n;J}#2a5DAS-=x;S4-zx|M~E9MvotQ4&{v3&Uy$5xOiV*#>7yfRoip* z@9If0&;P_!NgjTz?Xf0!exX;|2^qcqL*Ul=mTN3R zVrMj_-nji!B3kN5QZ4g=8}`NfBG%+H9K2;;d@p%@wDyt~v1AK|ozmGyXB;@f*DL3u ztaQTHmGyPY^0)SH?5u2+^Up_dyD`1#YkeUcH0l4Tnj7D{UP^Fje$>y9|0drcBbLnL z(93e1t`Kh zd9%v?0?&VD9|6AO99u*WXm2j~+0>HSyLDyM#i%V!dxb(>muI{enxC;niu+WTd&6`- z=55FJzg_;Hp|X2Whvzbsiv zSIrgK*R(c7Enc=ri*Na&t5e?Vl}%q`V6-6mZ0Z)Tho7FkKIF@=W*RH^CD}(}BH^c- zSf6qha&^fs&{AY@Uy#eWXGbq*b5R?GAf&p|(`(^sB!%EPiE@fQ@Q=yckP$k*B^e$-Eu27s3P`%{obSd_WU-LZhvpJE%*P_n=b0*sd7Jz z6ZSEGnU%}%^8N?$jQ#JguQ6KxY5O16Tkm(5z7`SG;O1~<+_7tFf{%`dc6O-u!s{v{vm43T18Ht3}`R2|iDn;gh-NuBh_CM1@EC&Bu3sz0%vUM9OlfScCYd&4PI zhrYd};kZD9V?$Hs)hf2j9gD&PzDCY5Z{6ayYv)AM4XduMdi7{3!=9{Cj)q(EP4hDE zz7kZ}`B(A5P5ucA;wtAEbUX^?q_UJ~Jbe{qvT8?H-zw9L3o$$I-7PJ;`^rCdsdkg- z+C!z;`>a{ToL6p~b#c`~h9!NiT%QiVXSV$~wXan4%I&{L3-<8`Xs={_;K^JO-rB-9 zT~TqX=~BM%UMUyC?Yqg4|Q^m=@&0?XVQ_~ral(jOH zES9&(&zWA<&|CMQV*9*VO3Ep{JZj1l+~+L0ma+6gYoANIZr3g`C#SWWGO`~t1%{Mx z>?_{&`$@9jl7;K+O*S$;v@j6jIy3L-hjUv#to6;l_vWVA_U#{?v)}$^2sCK-W{65* z&jvJtj5RYD-mU1mB^IxeY6BolCiJH%sKSgJ4UO z&Y5}N%jX?8oTe^sS8b=qw@Z_={2$Ynse%l;sSQtkd=+}{{d`mO^xu}+`U$t~zf3y$ zZexnZXXDpv?yQf0^>pw4TmBn&Ke@oKX~dJ_o++`sGeU4$4cD1@Z-pnU{^K>{mi5(n zcZ~&e&W11A|B5+BRgl43?L(vC5}s1ap0tpyF}tId1bp$T71(oWRo+B5k)ST$d};DzfAmDY=lOl^W6T|E>kQ-W=W0z=Fe-n-6vYr{p0(C= z%XOtFR^NrC4sNEr!3L5(%^MG#xOBiI^v2m+GatRzy^yrkl{s#L%AdYug(C%1iZjG^ zKPcpi*|u0`%dETX9R3FwRycG7J*ttFlL!=ZTAiiNrR20mN>=J(n9fa>ZkcI@U2Yq* zSgH*ddH&wZ!O+YRo_UasVaq&U_M9)=?R#z86(4*5pWy$S(af9YfVnW|se4Jn4_{1; z_SEcN=CD~LMC|H{OBrH<<*cINU&2&GPbap`=y7pKNZ-+-Cic0SYt1BXsS9g;Zouf8 z1{O=nN~VTw3~p*?vLo!+wOu!^>JanI5_R3GwfnK^+PwXb^SbH#Ff5F}~ zTZSoVUybdPs&(S44~ctyEqm1Qc4E!iy7%d~g;P~7ha7TKSYkLuFa&fY%Yv*BfzXYn qQAasugsq9*Y*MmX^zE#zQi~0YA_@h#wWoAw^Z1B(y>3cf!T+aM6srm za~LB72Ll6xp^w7Rh6@uy85jf@7!p)8`6j1%YA&6!P@{6j6b}&Vs6pq9DV;|pl6wq~ z!3YJD6j25S7KR25&c4OZJhRSOrc0>z6)mvL^s`v5z}^-3z>@ROSGDB4Wm}eI=bh73 z<=~BEWnf@paPUxU6$t_nNgax95=kA3?J`9t6qnB_;?i2Npoz=qghI2A(aR;1{j6TD zSlnmzN@L3fCvM#>m%MxouZAVB+shVPQ+&?y`5Y+03HFBq0|Sc_n`DZB69>rn4$WmV zinxqUK)j{E&;ate`$Q4XjUuNv%ACEZ;{Qn}P}uaMv1@RMZ)j*}XlZPCS?cw&((7fl zkuzGOchpAiXpO$n8vDI9QKAise$?Lo4nknBD=;!FP_~@*SaXq*)S^e0idRy-4O**GH@qm>uFfy=!T*I&+bJj8plomNHl`wM1 zIHAShz{KEiyin$Np^9se%JCu{c5n!vU|`^2a0t>lT4ds0Y;wHV=6JDUPj zbIwUVo>P2I^VH0v3ua!JRea8qXVy{(t5Rq-``VS4W)+{4d_ITom}KId;&YjoX0fll z88N%~T;zpW&sOXdnO%IYbINS>tvf>?=79|@KDRP%&bfn@59bu0>%28Pdnae?oZ@po zQ|7!o%Lx)gPd*L|3@nK^B#zB(QmE}?OA=9BrZ`!yq@Qo{0>cxUOXPa{+`Lvc2Lwr~ zFD+>T`&@y6p+x|kieUseDMM26l1W`!r!+R7F*>aSBGw!}XZ3o+VF70z!!4J*bWE>? zCHHQ9Hm`V{rAPMCt=FQomre=t(p(A-KTrlyNSWZsCJD|YZ8M5aX)a&T#03dXNW^_m zIWH)C5ec3DC=)288YrZC(MUJg*fumIG`uV~a(e0Q?X9slO7CB74y!;{Vy?qOfbAiEprI z>_ySi%VMd)X0ew|Q!j_6UM)+#xh*w%du`-4P;PZ!e zz;Iv!k2km+2@KM`8f1DkNH;XZ7JrTj4Gq0&;(OVo@xp|u3=EPC3{RFUyHdp`lr+Jz z(=mg?^N7sR7^|0a7RU6oPf&LAe5)9IMu27Oj0>KvB3B+oWyuzYboZ`J@o?1Lb}UHo z=?Zoy=P(Y2g^~<>#~EdOnPt40!G#I~gXd)iUlGQ$!l2rMfq~(`MH2^MTL)oRs5C{C zj4!iEAd5*LqyS?8S#&Xk@uCUTE(c-P1IDfnCZQBr0@aMgu0T^pe}8~$aS6HNH$v7c|wgf#9z?o_Chv*Dk|ewoDsB=P(pEL}4&FnsV4UdDN` zC5y@Ca!ckRlf+dZ^_aMUfuVtsouPq2_>=?OO^ZE*7#J)jr9?6?Eby3=%E-`=8aa=h zfnic=r5vUaq=}$e$k?F4z|g)ZLaadMG*e%4q{Ac~?u1ANU*-xa2N6b)VkVI5q)k-C z*fmU2R2c+V86FgfoW5id_{3t`(#%CC3U$0MyG%^YoVBb|$;A7zi{QNHmCHEKf3~^Y zqS3V|lPS=|myv;i6%_1d8D2Vk0U0N}7!*_(4m`A&_Ox=5M%S{;S*uPJ>YV=U5-8#u z92z_Qam2Leor^SPEnBrq@AM^;^WZ8fv@|wj7F^iGSH$Fogfodty;%@ zUfA`riEn6W>~+>f8MBtHT($1?E(fr}tEI8x9U!q)yVkvC0x1fOy*@RyA#>HLRlC;d zFo%SK`H~A(t$MX!qeL`dkEKh3jJ$N0P77jHoI1&C zrNWY+AWc?=23ZS+2H6OX*0wb)44)VnIFhF%ow0nb;^bxcY)-L|;!=s?bCxSbl0i-6 zDU%GJ&nfovIys~GoTd8Glrxsk=S&W=dOoL^&r5S@$vMmCOQr-ly_i!Rc_?#sp zg99YAyK?*tghIfqFZ>;eWj}@%E}!ppZUL8hgDoRdNTY z`qtrQVDK+sV9?r-SlTjq(Z&N#&S6ZT`m)84L$gI7h)r>cfRl%2>jc!~&)87Fz|bH7 z?V*_UBtlt*T*$o^ME`}BtQ%3;Yqy3mNSteBc8F~0HD04KSG12!TxydL0|zGqLyu#J z;R}^1lf1k{oq8-aRHsgh>RRj6VaTy`$(5)aL$ULg>-2k|kH7dJK<6 z#c(Swof6fpyG>$tj^dIjLD`1KqLPihwoZxaHasSgt>d+GN>KL3qY~M@t{StWL9*Fv zO*NkudvClNmAq!F+Txx`hR33^*KEC}G$qLBm`L!Nt=DF?7##a9k-Wz6dDLW~LqFt# zbvIs($`10!@ROae8np%R*^AVClY8Q=v{4ZKg}nLCphOG$lw2!ewAszziz=l(lq^_!+OWVR9ES@^Jv?*%J&5 z0_+>NT#H)WQ*_GHbFH(R)UyRkZg{dQZjJCxRd77z={2{BLz8V~Yme5_8Iz|uot_cI zlca4}(qrgu`834oxC8?OLlXl7v!IbMhloRCBM*axgU19W1}<(M*~6|54tk1<4=gC~ zu~46D#=zj%0Uk(zw$LC037}f2X6yZ@j1$iYbaot7FkC35p|y;;;V5fc4a12GH#~Ol zXwYMhxo|X=-HF3VpeaJefsxa~;$fTmy$>zYa~1@LymA0n9dZm07#S39GAJo6n)&#} zhaU`_f|81whL(Jy_SyBTetRp2>2`hk68YPCtLMpup?`KBP~+$b{laC& zGe33F65pB|lXZWrVe**$Coz8;{{#hf^>*d}p&9EQF#T+a2wl6I$7ONHqK-QrumAts zSAOTtofA?1b6z>Th`ua$Y$M~Fwu>&^w#5RMdh*SER0GdM=C_zWu5Iw0ut#78=Ld_J zYb*y=Y|U6ZW!sAjQ94n{qDMu$J9>|86U==ZJ-LfvS%EHXWa>ZN%S8I3L zTi&`Es9+Wq_?hv@yjHhmJDx5PVL3MMQzR zw4|jalPQB@qFsE)hL|-gS7ov~iUw}Erl6&i;d*4%foAQutVn1MXe0cP?3uo zN=c%jt5>--ZOo0nniYC=)vki)N0+V&&5ei@j8dFdsN;Rkit)|7RD+ArR%zzH?{4O@ z`ZZ&p$CBgq3Jy&;`%?Eu z_RYM+@b8(~TB@v#yVEVM)b8@|+}Jep6Qf#$5TApmLyzdf1c|IuF`)-_zs2FBknCL4M%9GUl(z2ogqiFI z2~6G$)5H%fR+V%+(Qta>jV?2ht6f{U^p;M)y(vp}73<;~N>Q$7Lf8K=S-x6gf(^r& zc`xUuy^JpIGB`VLWqjJ{=-EdN{xHn$Wz2|VNSr3f?aHurg;e&Mo~fbPq0+7wZ>+jh zbuetHhErs!j-zwsM&;Fqw#di)3<@c0 zZ>enR;rX3$)LKyZeh8n>#wAN7j3+ZNIP_{w3~JNSoVGkjJio<(eVV$?1kPu!J`;7A zmibKj`tHsC%PS@_z7EsAeaJYkD9Dg!^TsV_Opb+A3zlBt>d*+|nPFg-(AvisEMeNE zsq8wbrP1L;S;qQph7#*7SX4BeSBPj$)o^IJ(fam+gED=NbRc`6(LlZ6-wH)hhoR-rb#NN^(CJ-&ao3MJb?yda)ds{`-=QJ*He}3w7`t0;p zolQ>|9iD4%UwZQNORveR_Wme$$>VnM=4xTk$a~-TWa+KUOv`^-iEY|5b8X@0Y5N;oIbL&YiDhNGbC&UFcGMOtmzA0& z@i`(PD_1qGy}Z%MrDM^x6{|VJJ)2H3ada6?TC;(3|Eg7emsc9Boyqv8iF5kJ$->X} zChDYy2-!!}G_>gEu!u4LNp}mHaJ(s_G{clH&~z%3w&>D3vFwQgY_1|~3pdEjEE8aJ zn`SK=5ixW9WSzyP5zNhB+5XInELJSDZY0j*XUyPzAXtB-FC}t* zY)E<0+u*sPD@<74LTq*TFzq-rI zJ-|Ar>!w`6>ejUHUPmkZ-9HAfM;)(i5H)98 za98rdQr@fbq5BTWee9S%eRt6BpMK%%Rz8T+T*{Ofsd5i%u*R1W6t{=G- zr73$OYVp!tIkkP_^>emcT&a|nF4^w%B;%s{+i`pl`5A2-X?|>kH5|Psu1iNzL0T!ww_~bxNFfg1D?Yl(pH*E^(OQi z$Y`fVh^_5fq)~83Bh-QQNY~MZgLp(ml7IPwKzoM+0uv4~m@t;N3W_d~ za$d{DI(6%4(PqpoA&5jkHc9g9kj!~)UK>+`md5)|vFZHff`0&-I zG$DWQjlOU44h|L%o-pXxHGH0$e}wJz=Q&S%Qn#+y{{3Y^gGkm?uA_>&rxF#FS{SzU z95EDd73?pUVYoA|RQvf}4@bwC&FSye-h6N1V0~D@AS0yAAlA!rk4<{QT84)L(!xh> zp5RlRnb69S?VFsUx`g*wm+@DBm)+kP-?Wv+9uv>p5R+#1CbOY9nrHh@21em!5{-2# zFJ5&SwREyODTj%yQg{@haD}UD(+-O%FYMjx0yoFEyX;h-70$k8QmM1{Bc1QkAp$$S zuJJDI48K)>tobkdhb_k#ws<~J7PN?RzA3ONByY;9Uo4I`iC0c=O&8eMuqZ=&)uJTs z7mTO9vK@VR1dnWNc*1&R-bBUV`WyH6)a|-$Y-Rbw`t$7T{@)qBCd~2SXpr`Kutz9u zrcp=RvPHqh-J&Z!7IJxSP-?xDyL)xQ#-NL{S1&2)E&94w^0X1tn|Z$MKPOENd6Qya z{Y>_SQIMR7^_F_ZX&a6()Oe|6Y+gUp(PmbKo$AZ7uhTCd-Jdf5l6L6oP~VP4875M$ zn&0lXCrY#}TdEk@-tYc79s1YE@Xs>a0HLoq;l8x!aa5Q_#G-;+&W3#Gu_}Dn2|D7;4f^ zN3PsB@#H%9&8cC{OMUJcfB&*sntK)>u$7x0CCJd^<{(JPh zjV5b2GJ5tMkSP++o-%doawgW-ZWnJW1}(U8r(pe}43UHTlT%$AWsWOyx$Kb0w0pYG z--4kh&GwAPHeq|6*x5mA=SiQ;_p-Rk?%~tmBhWC7X-74Spodmo>f6FAhq}@fU1Uu@ zwRdbg;j&^Ki_7XKUle#A1w6a!dG1cswyvny&Iq0(^S*lK*RI~busv-XB=`}}18 zp9*_<1;e6@8LSG>z-u6`O5 z-E+drMMA*)9n+mzD_@^ftf*I>Q?DCYaqL;q{-&dDclkHmlxZyEE_nR0ny8&)YW{F!%f+54xVe|YQe zRxk4_6;A)hw*Mc4DPyN#hS!G`EiCKj^28psS|cgAbd{`Wq$RVp!>SdFLVH$(h6ajW zzty`UKxWOvry5hLCol4sdor!GIw9}T#{GL#Uw;?+)OgsWwyr@}F@r^nRVG{|#bE*W z!Pscm)gP5Ig1y2oMokghDC&5Tl}kzK+9E-gCjmK;tcwJXq;1^DYRDM&pZQ8xE8CM( z4vtS&OPrmgqs+w``0k2t3d`(*M20t?C&l>sduxh^uFvvv6m=D>Zhc|+;^>U7RiQ45 zIR?+JFW2Z`2^DL&aPQxl>kMc5w$4Af&3zvP#TB7k^ zrPXbt!=1#Ky1#)!slun{yfxdqPi1T3_t-;M-!c0H%$Ot7n7@wM|JQ#H&Zr3?H)N*m zx~7%YxJqACRA6nAt9q{M>V_3vYb*@jmHmi%(09SYSx7(V7-jnMSq4a~G{WE$o_K`t<#etwG*vwIW=uu8O*Pp-X79fY-vN3y$r( zy44gLCtlmX_12}X4_(p>cji6Z;1xA1kz22_dRe&W#wpI(%D?#oxD$05bXf&*LxfH0 zcX2CyH+}ibvo+v~Sm-KMH69o5jnQjDL|nCf1^9ivVgr_Jx}&+iGsHQQ@xWE4JF`OB z(;_uksv6!-(@~zV=I7;m)r?}Hj1H$I8>Y(`TF;)XkRLxOx?H>|u69b6)+s&ft6?IU zoJ^jri<}oX9C^A!{A1|z3ofgwLk(w!y{bI&^O#%NtJ{b37|zTJoph`ylC%8%SDrSr zX>WD5RQ~3_5OtG5$B${Y+NYDpQtAcYKfiVPNYA+g6M7T-wi~bVnAGXER%LHxiSaJC z`DS538drW*6sCBK&9G2(_;%}ajwHjLX|0{Irx)>TX{gPMyur{tE#T-sRt-bZX$(4| z4}MwAEsc^5yB0g!Ws&lVMH*S_6s9zBJ+%->J@M4nzYNz7wH}x+RFQC;*JS#tP5Y9*XO?Dn9}-`9 zB1?CxM~Fyl$;Ek(1zF%79(B10h`r6+Dd~#ZGJ$)emDu8JW&Z+ba2E+Tl5G z{EqHR^w?<9`jkCGJ6mvrM#3LU!P8G)FHVfrE?Ka9)5a|S^|~vHTd#0m4OtrIxLULK z$fb4SVccqb3$Fb1VJ)=FKYdEK+iS_D($&JyaS40yxCVGN259`Et^CVQo&RqC1D);M z-2H>Yf}cXM!ebPo!PiVY3*_wfzz^LGpI449>@c1!LHKaY7u`O%7) zN!{`fIP2^g8aAECc)Lb&v!M6o?~=tcZeO$tTx(=(%*ep7LdnH}V^PMI%Nu28E!OXs z3I5gF&YI5AnsnKQD_f2y*yt;fXS2{{!>S>)@ zueMELdHQmn(1}FnBqJ`}5}#9fQ?m`P8ZxZAh~IRiig{8zunx&3(N0pH+{GBd%BL0U{@*Put_hxdeTvvhQ5BY|jni2d zG`?KqwN>Y&pKHg*hPOKuI(8X)cEuciIdQ`qP8Ua&%!yIWvkFx>!?>b!Jn}pn8=Qqt zDtS6(Io|#z)y5Yt%^>0_*r4Jl(e{vwSwY2RLjuczTT@q+b}Z89>If1Q4Afn4g)wYv zROo6}!QMq0N=a+hg!zQ}X$m}GniT$4K~2B>wpOU=O;L`+>#lJ7S}BUGT;-L-sKWXp zYc7xT0=+k0ti7QM2N-xNG!J{s_`d&jujr?<`C+@Js2_-X;Q2#;+K-eY&R!c{EdR-J zfoaYxZmkK^e?H+pIkQIfx3z%xeofm8{}=-f1#~g~n9085&rB0V+qk>S`en*rT*xwK zEKO8l3X|-;tdYbd8I^Zp=I_%CNAgNNkM&g_sLQ!_yQD@tP7fn73G@m?Sz^3pg z^Thh6>z5jPyNT|;zMz(ocshT6@oB zQ|TW5fHWEA51z&cVm2?)D{{T+`d2M4tAG3C9bw$3m+p8halS=(n(v#u`ET0Jc{<%( zc=&2E`-;5t2`!IUZ?U4( zc}v8!)X2E7ox0gU+NVzx@%uQIh`L^^Eo1yLEs?$K&tbW^JW2HlV!xis-D8gkaq4#X z&9&xF(!SJ1HMMh2g-%}?GXL~u(Zq`lO<}4XR(!2%6DJ1fmU8-s3v4UfRl*#)zm_v_ z>w-&c%slNgS?=8F;AuZDxM}xCMX`%l*)N=7`oOe6)A9MjGe1kaPX1fI)6Kp*_VulE z+dfP*x$;-^M52$tmcu~`QF?X49TszVa#bsNAFunmaYd@OyIw4PsK#N6~C9USK!sFO-ij6LE@~+K zIX83LUarHNR5;)C$-3XlU($Nk-n zr+RNoS=92N|7&>DB0Xo7C##imtZS<$OLG0%y!y>_5RnBDLFRV}Fn($)o) z=*Htu^MZljyg!5OY+p+u{z8!;MO{ApH*+TH^jJ{@MO$txXl)GPGk0C1N)=ZGMEnc0Wjy)>dloyM#UiA++yo=!&Bf}KG zOzt<^_#fS~otnk@qiE@gE6vYp>L0lt*>u~>!jWr7*|mc2AKrSL|2FyVk+W9Mw-wj? zjR+Mzx6|a*npkV)u6+U`tDIiW=$M(Xb)AC1haet-UZqLlA2=D-H0|Zxz%PGeTh~^d zr6x}&mz_%FXAIF%o8z#cmBHto5%W4nGY$W;!fZF~J_A0F>YGW611I_mFl;Gm3_aC6$NrpcckJr$Gd@x`{x!>`mEU`EMdXl@ zuZqBjb1!%5>fGX)|E?n~(yRJthU>NU`ZAeY#oMJe26cyqs2VpWxHv2j@#VBIFHP)T zx#}%5yOqzh&mu?oUDy@h7euZpX8X%5^I>1{s(ZIq-O5xp+LV@*o&J4JL1|9gq>hjl(kJtYU zf7`qL<%{q)k~^hl-QCVp{e4pS#dFuI%NH!ryM6WULG!eULV2e1X3msoQuwkYZJNt9 z0iBa9B|BCvIItq-PM3DkVuy!L4M$T0*3P&xS+Q|?fB>&*d3k44<%21QZaS=RYuKP7 z&S|z#fn{qTr$>|FLK!KB1V)CG*!@wVD(#N$t9357rt-{Che3TsoTGCHUyZ*7&q>;(@te8#KV=rwX5AFzt(`T3DpK+{6kG(%L z&F^`N%*V~!{e^eEUBIsJ%}ec%#RL8gjS)sOpY{D`V83I}&@fR?i~nfecT*+f^^(b+p@IW>(BYVA9-`A#6u=BpDE?^g73IRw<0fSMg%+%wp~3 zDJvw{cBkoBdc2MGOnUpa?dye%4M_(k>HV+GZ!EarDeUaZb1cE7DR=4>0R{$XF@vlN zBAZTaT=J6f0OyvzuYT%t|MDHk?v{N$dESk$VpE^jGqB6B$uvA=v4~%x%Xh(cUhST= zgDYKx{URTG>oKmBlaoOEY>-V3*&|JOA* z{xCT98L~YPI?#2*H*HPnqGbwO8eQgQh{mnm(8LrMFz;7a?Y;ZCv$wxHRj;?D$(DP< zYLhwtaw25HveIudc};xFTF}G893V8K`@ojM-RtfZ?syvM)Ym<&J4$zvh+DUaYiDCA z*JC!N|Z_h#P9WlC-}t#`hboekNx=El!27YhECbb)40#a@Zj%(XN`KB0%U>kcy(!E;QhvR5E$8X5Ii??l*k;6tE=_V-8~HLy z^m*2q9F3&ROc}prXaDM4@;W(v;(slhNqzq zX39%&M3mUaw%u45F`_B#DtUuShv|3ls{djr2 zYN_Js%Ju%|y?1VBIMdh4{Nv^lnc&6yZW@(tco=Ri$>BYB-FK#vy-Dh#W(<2-aykwR z$zPY=y;Wm}a_ympO$O7VUq?i2@(X*Tc)7~=G6Mtmn%NOYSM{#s{J3iallP{MrCR=l z9cwFiy%>(nd&xQDu$<2J`s!u;cCT(o`+a8&Tg!96{5(r?`QEu+k4o~VEnglWDw?`9 z<_dF{R*{^~koHZymSRb;pri?-o^U>}4@yI8w*m#Pgu-f< zYq#i}MWGuaE@o|!3T-{4z>^mnc}Ohrz>+l?qFqOy&l2T4Gijym1!4Oo|Ic+Dwf(@m z|G{qg1Wray_Xm>>v?(3^+IVn9;hzZ2t~aZeO`jB08n#7y>Xy*lrHk~Q?U{J@`~KwW zv;dYP4{u#N^;ySl2Gf{>+YC$6jvjNf zsd&et$9N-YYY6+Dq>j>kzkj}*D4BEU&>;pJ7tD~jzx(^ET8tgGs@k)I3jb4t6ONaq_+UW z!$;Zc1+oK0C+3^p|HRpyTJZG4Yn6YGn2xl)l)i9z`W){C+in=tGQTP2*>d?iqgd0S z0v0JIlZZ{;M_RTYntHT0F1knOeAHQ|jdx;SsIG0gtQ0VHs;Ks)+wWGbk~rddk}K4y zrnX#%QQ}LNLp z%vH4a;Xc{O_(hGYQhumM=(Z~@u|4+lX`EZeLHRTDjATb{=UAxf93_3J_r=Q*u3`p8>ypqKRC^n|7Qvb z^<;|B5!y4^@Of%d=$+7)=_hjxD4)?9lFr>zn5JuFi52wOb<|7Bv0*{+nfTi&n&C@i5$J zTiLQqed3$s{nBD>vz~>C<$e3U#cHCXnhUUn&KiC3n-+?bn$sHHlDno zsA!m_;`+Gq?Tu8%J(F75VjiBqdv?-9mM39Ts&AP$Y%5|YQ06KKEiLm|(-rk&g~`7N_fU?M{m=bgoBZZqSw15<|+s@DJpN0y*-Olt^d|EUAP1?Tv)_w-j z4aXS1FjwrYy7^|C-pU2+$uBqQU$@@9s!EGPHhRio0oKNZ(A7$}Z4(w}m=xux?2+=^ z@^w4Uo~BaX8U0%o!UI;BttrhmnIEFD;wQsdS2s2XO`&@ci7yr$PC4HBo!eJ`QC39M z)_MF*+}Ud$U1&*cPi%AJTcxz%sA7^zkkxtrEt$KPW;5+++G~75T6EgY?Nxh)FN6xT zyHw5pIxWX&Mgo(Va>BpgeXrlH6A_L|72L}%8mN`zDtdkQI;~@qy23Utx*BokYSiWE zE334^uAF}twTa9$~%cghnUXH%s zxM|&~!15P+b7rqvrWYEav`TOPbdCK}(o@&iR;-+05X8o(QyJ*0 zzN$m$)v;_Q_Juqjk2o z&F!}rzN)WNRM(Q{(oUUNlX*w;cHWZKfVCSpDn*%?b!E8z*uB^#d+kQn39;IDpIb7% zndZryrYxLhpWQa|Xx^DaIr0nK^b{BlL@?B8_wPUOljrHRnt$4#7tGaKwdzHv{+d9S z2CbmBV^OY!9aoc2&YxYMBb>-;$Em%oh4Ih4!%jI*7ks$&b>2_88KTM`w$?VZ_A+L0 zY~bJgaB|n5E$1#4|GQNlF4J1)n45NWohTF2G=uPKQBy@SIk%)Vgb53mtq6Gi=%|xe z#D0b+^H#FGYQ2Af-Mm`Nx?}CnM!h}!27+N+3>!Ee>^dkVdd}}OZ;aNgtX+S$#R=}o z2;Chbx>txr$w+MDfn7IF)~yuO=}O=bIz9XGd8G$eh4wU+O3s+btebXUN^G*kWhcMF z0D~jq2~CH@*c^mse7{(=H|XeEY1>w*owickOLey0o06)y*L2m23|G;D2Nw!II8EB? zC3t9>c#6~7I%byXH&v9)RJMr!jx;u9-21}e_pSPdO<@j9A2^vKK7X?ie$(+_*UfpM zt(*3BbL8?m_Bi$W2)MNzoMFo0#O<_n+Wt?IWN$>Nh6!xj$9iYlQN`tZCeD}K9kbb@ zvG_6bZ~X%&gbx+4=rDiVvBjVw&i9(?O>a@7nSvpgw7T4SIzFAVx7Xdf=pcvJ^lr5a zO)K+${pPyRzmhpENt2bo+NQ!_+HgmJsq5#~UAIbWLrui{E5Hs-ZqYC-1({d_c!iAB_i@88>|)KBMXQixDtm#K~{empDkn(Y6k{X1TJ z9Q|_X*S&9yn+$d`#Bh93I9>fCiZ(6v;?f+Mn4_UrD~ zD(h|=1@Bgv#`rN(fjxV}sZ9(l^Y1Ry`xww(U4Jya+$v7~`Lw&gzcUJ{=I|W2#B*V* zL*cHp?LT+UpR|0rdT1~&-_p3Ln@nwmLbtB7IDFs|i)ce+Y3$9^J-_%m8m7*g$M9s< zO2(2zx#|twrrE|9Om&0j-er%N$eqBj$yVXO<;01NDxF0ag>Fp?U3kJP`(V)OMeN;c z!mheHDu^tpuUfPwbd&DF8`tx$Gu@fC(xvatPuAP9#vVQoGxr~~*ux*7J>!JHikT1A z7@fV~F`w~b&&7}wm&mKD0;*$W6EazkNL@&{dLwCXoX(LM2Bp^gho7wH&6_uc@y)#4 z!)kuD4-!_J&i46UHH&%qcSf`6Ob>!pe!LW_y|mQDHfE)_tLwe$?Gc|0w(fdya#O&I zE}e}E*VZ4=jMMtCMD$#h>eZ{~xPlT&df$s}@W>H4%6O%Uk)17M$KfdbV+xI2>His4 z3yHZbnCo#slz-8h_{CS8G+i&Q;))6k(T;Ew-4YTSsvOmH)oz^r2(wr;fkw*xDo{x6-2hKT$`b~Htb(7?72xZ%o_m|xx ze7C^v`S&;3Zn$2=ytPI?Vd@082j9;!UODn!Y|AgxiMzfehKBkEUe#{WTqV_;aJ6Gm z;Gt!$&TIYFX5IEPPul(ARsC(Pj+SKUHx}ENwq*U4eR1MYUg+!h>l}MT-_$m=Hf-g1 z!gN9VHEZna=u|aR$E6bv-73)PR@&y)!gr{ZA=*WE#VU^&)iCa+3w$4%)^f0jIVP)K z*JM~y_ce4;?ByBqZ{2qPTb8(9^Jep3b^&)kwT1&q4M$#o70q8MdE-aGP7R~0ULry* z-n-7YU8vO-T%2)qQC7&rGTrE(-PcS0>!&_G$Q8l3Wztry%iFTz&gcA(`gTq$Cv~T4 zz;5;fPf{e9FE}ym3|n!#`bhCa#f|aYGG?-Ztg6ae>kEZGwQg_qG|fL<&CrwPZ8Y{*_;gRGsJJ#Mp_&8NQ8Cq@EtIGY@WRTUSR48*7eLRaXp4&ToDmQPmdm9 zm?F!2??gak7>~k}u89Xd5-)u3Rk@U~;miSze^UHq@(In3eC`h>F}!!v-Da|QvPt%L z&eYsSqix4rXS&HJ>uPklZe3xu=0?1>Y3-@?{y#nch`F~Uc8D-MNh@V&QHj5_=i4h* z1>*Vgwz6xYf}VKnYNgQSS+2p3fw~E<>zA%tl+b0j_x0|-7Ez(9 z`cvO0q%txelwvbt{WEW3&bv=x|CPj6=jcgV{Sx4>@zkx5UvO5n!C~qGFN4=c+>-<{ zTrX~3#kb6M(|%r^MS|SgQ`7la+RBBi2kwbX|SJcWHKR!ow9# zOBZEn37ST4UwhH*6sLs2#d8NFZ$6q@CL*~u`{&dkP)?U#5$*WQYG>LLmgkc=+rKl4 ziMl;tQ+5ok5S}Nc{OIKT)fc-<{T@bXWs9m>r@T#B7`ceES@rMhX4_-CkKNz>&mzv? zW}The`6=qn{I8s@{cnuDcu|7!$-Ik^y1%YoJ8)3%dr!!cT@PDk`jyEmq^q+qTwvI@ z>)IUkY8O+@t5Ja>tE#Tw?)pCY_WJ``o`DfzVoTiq+Q%6F=1|I52&S zj>f`HzQt{cFC=a!O0*S5D0*Iq%&xsWHEhyN<~4P-%rEl9<)X8%+pkpBf1(_BkG(@c ztWCMV_knWeOc%GCRaXkLOivjV3iLLat}$8MYG9BpkP#AUxS~b)fym3(1vgHd3l!}> z%#m2Yv?i}q`vP;4_3g0jx0q_C6l}SB%j;_HhD{9&Oy94jC>)PoxMtO*TaVUh-&NA) z-n#PaB6e#Hoej)_%Qh$rPKx?<@sY&Im9j>0J*+WlrSH$YnDx_hJm;EtF?9+j?S?YHgh7CEZ*--ZNPjxpo--*&Mq@%(tOi;_;jJ(wDcGl;s_Y;%t!Q zwdKuQdLpdrR@BxNtxgv^Ts=iEZkAXR{5mL9e4?jd+u!_d$JSGA;T+SZX}o59GwV%!zAeD0jfXEUo_7T>+UC`^3mlr`a} zyaGiJzjL}8E>d4ETgPU}wK&4Ts>}6T`SV9iccwjL{QU35{)acVrx!5)4XQtEY432h zjX6N*ht^W9>$VC(cC~8R`?nWY1%|b+(mJZz9@(O?`O-R_uDFBWIvO=P3S_K}O?6or z1=+GvA{ft9m5M$I-d9+*HNjB$ppjig|93{QLr)GdT;bSoPjaSs_qC;*rq)_pw?&=Y zH+4&g+m>Zv94W0+{8&Y`PjwiSoLGI+^VU>56YV1pW-sP@(zlZD%#w$3Z?X>ml6+yr zTfO-|!`7Atrv;1>3zUr=SMK$hxNcFHNc6{ySdFe%e1~RyTa?h+wJU^GAX3v!UHQ_o zFRGP{$~|i})RrvMxYBfy;mu{cAGg*wnX;b=mD6zA&A(y82C>GQ?0zRA*7)`<_m^Gt zaMd--qqh#RNF7|IXI&7W&oC`JrUurV+& z?6o~mWa1Oz5gZ!m6X@gR@9*#9@8j?7>E{>V=_*F7Z@B6=Hu<} z7aSAn7yhTu@%rgIuMV92SAJ$vmqg(Lg-^^mhZ+Sn80Re2K6QCvi+1$JRZnYva)gSe zrk;GYNNi%)t5v#U7Z+`u+ZY=arWf9*w#{XQf=AyZey%I?p1K~I@YR3D+pjUZAMX5- z$u;xl!~G1I9Ma4MimN9_ zl(9lwsOD$90u!)^!C1n67GAEn0XsRfH`uC9vnv ziBF$fjgmIzM{Z-7GijpjW@G7Uf!%hhi_PzAnCS{`uV!3z#*iV`)8M+4`nB_=8XoU^ zop0y6to(OJ@0C*Go?C@)Tw`;pMayOy^z52$+SkQ;dfMVgMnyfzdyW~a-|6yv@_5H< zewjL5iM0#XRCzC+eRuEAEgL7@vDj(AaCqn5CC1t=shyFppN5HNTV2pzbyVziplGj_ zQddOqHO+5QZHXM|LJ!M39JOOO&dj@dMx;_w)~WtY(fKsyqTQTT2j4MQOeQBg~V&UY0-o{xyqwhiqGm;|_~d*Q*((QAZUORxO$uDHD-wc}O-(G;GGso#zjA zF`j8UddfZiT4Ph=ny*};_fNXYZA(~mC)0oJw?-+RL<^?Cp3uxyJ#DUQ^cJsi6=e6| zx-@N-JHz_et4XCFkAHd-@L&q_RHc{K`vjB{ng7gt>Z5u73-fxS+y$C&#q$AhB}k(MUSQiEOZLF-DS!W#C6hf<^{!tVP`g< zeYsX($-GSWo~L>BhhJ`;_i{!5H-mb?gOC3*xy1?b9WbBGx$pnKN37fuL7{Vl{_m7| zbUcbQiPgh1XzEL>j7@!==+Pz?F$Eq|34~6K1 zEi6&BiW^m>EnU|9yT-7ktu)kmP42^#>r&T@th-7rEYxqa-$)QLU|25hV0F7MuS05vX-Rr#%Zov1uzLH5slU6T1>Bz26?1Kl{zRMCQ8L@tb$=d$9S;ufDT?X07|roU<&2L1%5l z!I`CtHGeL85oq~YW2sJPsOB{d*Vx?;6#TOSOsX_PlS5ZaS?jSjE^*+y-rTnKTCa)? z!=Jj9X@`!T6;VkReIxIncXdirMomNOh6V+O@3s%7zI~d)ynlLSpqKCZw3SIy^;mRo zbR{s!99!z9lXNtWmF4a0PcGppN={RSS+tTEu5?X2r6hOsz|D1GJVwSRW>*w^k822H zoX)YuU*XKNcD|6+4I%g9>O4;=NiK5h<_t?&leI)dhwB#Sn}!M7I8?hc0v)0(6^k?? z9p41(I|DG>)p5F&oX^mPiNR0Ow!8o z2)%g2tjp~p%Os}WT-PJ3Tkrl3ZAqVaNvY+-ssHs}+;8eiwLfg1Q*iR;x^lw@@0Aii zGU+(F`Sl%eV&MKh&G!f6!p%o_>H5f?_g$&CXjRvWj#sO6-2yMJxa0Zt?!|k{LWRq_ z&+x^*&|>&9?`kVwnMB6r-?o$4J+gKDuHR+9;W1UBaT4RD`&RE(cqqG7N36Vbw5UoX zHFmp}_nOifI#;<^kFL>K6fQC|ziS@X_QwW1$u38}%RJR)SQ5AQ+KB^^7nrrCz4ks3 z@X_h(S4N?xrYBJ>UQE;H-k4ZWek@}1y2+1RV?*vnt-qS7UwHWY_wV~xt%|x@Hc^;M zZ2g*VeN!UVXN87lZ?@sTQ}mVV$;1}3y48X9fhSb#GYikIQYtc%Nd zs|0_YeUp5A7v~k-C1>9;yCgjkYAk1qQJB(j&p>>|siNE`i?XJL{9*Z~b#)c1_O(@F zSFf+N4-}jz8qzCK`m^h>aAKs+{|?40eMfno`ReWOeG|U_AI~{onYin3-hXkw_)b#m zfdLESiTC|$t3F4XyxNrFyLNS5h+|8+M3ivXfd&mL5gS4GLYd=1hrJ)i*>7o*WB4-Z zV&`N2XD4q@&NcV(SGad`V!8Wn{tdk{$_1JZk9WOY82s}3ntG9rMOS-{hODg0h%M+LUp4V`^J^PL6Nn{X%oc_Umy{}j&9$@%2Z{3?KzRKZMD{pZB{C8u= z{M{SFa$N$KM8yX9ENO^&qRQo*(kz-8m?0_6wP)5*wllM|&)RN_+Gud{E{9#;Q~d=> zYXp955z?_tVAGCRee`~`R+R6mUqw@dTzh3&xDx{`BGfnZO!Z2P+}fh4^U1-=esOf< z;|I1K(lVQtC)g6y|W?z(u zdABJeynB_@(_i0rt^2nk`{bw3*V-1YUi|dCu+8bB4?p9s)&HAOz2lY6bN6|X+vogR zb@c4<&5euyd9fXt_tI@kRkw7!^~R^udR5&kKQ;$%5RPwfEl^}w=g(N5cT0Qa+Q&Cr zqh#N2-gRx|rj#pQiaR4NE}XDUlx1BHU+=0W_akPPwr7NtKGP`jSzxfuc{0g9?ZdhC1qf;^={^@}??@hL*o}08b;S$q>Zx78EzWS-G%spJMyZr34||Spd*X?W+#%5)qgc;mU1T`tY`j%rlc~1Kg4t>-?)_UM z-@9BB7>&wdgH{hb=~}RVw*cUjxFp`XxYfb zso%m>`&zJ9aJAJpt}F9C9tw^=ad%Jn?%T$4ucl4=Rgm_b(P@q#LoUPf*N1AnW{G_X z=sxORS?}9=@swiJ)m5*R+!NOXoY>_m(6*{;o0z1grc1upb`Bm5ChdC*&di(0ykWZh zx4N|R3C#Pp$UCjR&%Z${nPHm10p`ud-XYJntNj;$eTskmmRCV1o)%eozFsONzEEdt z_SLDclK%R4tlFj|71*R8kzBwtsb{*YMVJcnnYNdVPp+|l%RhdIMPg&YkMG9jEE6rm z4>2rRmA7Txbcwr7Vxf_VS66jpOkJZ<#~hv@XwlIe(A03O&q3(g45kULH#b~Ap#8v= zZOOd7>K(1Vb|-&H+s-xnHBy&K-3t<2 z>+!L0m-^COE4=2$lz10MOj|XjYmrxO<)RXiHVzrq)CoU@Sms}SxIn$IrPprHgW@?m zH%9L)QGN8AVe6$N1}~;<5zCood7S$H{nG!_o|aR;XZ^gh#>LS+YT60`k*~A&dX(rL zXIeVXDMGg}tZ{8tZu04*`=6>A?o3-7u#d|S1BHG+>x=wK;%#ybL3sShe`~BH<_-? zyUBIwRJ-Ll?V0D#q)q>)as4O5Rt06|gh+;1%lGpt4_mAb{rC0u-`%B~SDs4z>a!tc zzCuOwv{S!|itJWJ#kTJ<$Z{4~{UdCG*0uV>vfA}>Yvx_#c%mowFv&c6nY3@^b?2Qo z{veT(45^VcRJ7dL}$3{7Edru|MWn|gVBISE?tIrB0?rmZ!9AYLnA8Ltgy2yHD-bYqv zop1Y39OYN~#-o??`Sm|`Mb&dZ8CSKiGdg&4p6NUn<wUO8_sOGN)9BR^XC9r@u{g15 z=QjR;#Re0Z9~|SHrMzanO=DJFYIWR|wKgO)w0Dt4#Z!v_fry6=Y?3Q(Rf&5z78Dmx z4vP{gxVPr);|y+@`iX3Zrm0tNKbly=c4)!mpFh&?{#x2Ig)8gi7LF%!vpWNG!m`U! zWt;!zP0WoF(lGOWF?+fH$5W-eiCeE|WEk6NcF%uaD;OU0;^Pl-CYjl9844#Q@o#%z zG+*LO)~}nFYZ_W}85T`n(4FjZV(J9mHIu@kuNSRzv)sBOc6IfNtsx?Pm=NZ%_{3P$ng_X41u9#YeAI=^gLneKYSVzt36myLMU+-dgS{OcejeIqCH$W}nBc zn*02okpGz%C&fBC!zdru+?dPYTpFe*)9-TLP>h$EVb8jx&dv&M& zkJYQHV3T>c?Ra)13J2?mBY^A5kc^(8HDn`imXz;J6W$zSb)I zmv&x=*q3P&BbVMwF=Ab~KQ+bB)$X9*&HYEeh)RZKhPiMylsoSa+cH^7f7g|%SK6;O zEpqeLkdZjk(=}u6oiu^9OOo0ah-7Wo5!qOHH7Vt2X@ci z1qQmPDyS652yE}^F%aw)sk;)iFBUQ=!7u?aD8bIaz;NMzyPdV~MlZf!l&KrrY0w>?Idoug!m7WU_Ld(AzoF)&#y5*c-B1Ii-7%_?l^1JKEUR zYlq54x$x?`dMj}5d0+plpW#p6%{NU~gKyp0eCzF`n@cA1>AIiK`pziEIpYLFfKbcd zisQCzfoV6Yr|O3W7O%b*)%h_bRx{vG8s|plK-S(~iHnOg`(+|+Zk@g!>;IDBP1Q@q zSvR8CXU?u&KjYN`yHhFhzxf3^mBiT=sC{^N>cOO<7Su4Bv_~wEB}4Fj%uDGT8zbJ>slS_OnfH2m7a*Ub%B*@=X=ypU?OtW+<Zifg=SUg#;WWj&vpGFth1Lvj3SCJbj}{ZNR~6(d#@<6mDnUdrLmSbT&hj z^1;n7d3)C|2I);*uiD*Jw^Zlrwbm=H(Iwl=V!!>Ir0;*<`%YYOsm&_=;wi4%F6vip zTD?CkXYJmg^DM^~N$&roaZ~_j)h= zb*nc8Z;cLKv+1+iuCnlqi$@oRcz0_xPg`|qmC&PkLBf^KU%vgEdiyY*75Y6$EwxL zivq&7OypZ0_*K+(ZS1Q{X{}w(PBPj@!cJr*@l4pm2AW9w%_c5mI}OFrKHrfD%ADhw2jy5zOP)C_to?I z?)g79$6b_rGjAfpldQZSx6jUdxkN#{>c#D~ciAI&4>LRn7K-?_q3mtf(I5NXb{@NP z$}!p@P)zIVu~)iu=+Fq1n+c-25I&W{(lqQ!(ETDE=kwD_$xV7Y{jXtj*RTHd(L(!?OyiJ#=cZ` ze*A^_|5y9h@L#dl)OKQAGVkd18*awW+MKV;!1%_5Sqf=Nr#Mvi?>+um-cd&k7z>0Q(2**MeG?nc^ghS?9FFw{6Rv@K0vcT?@e z(eAf~-m33c&C@)xZd<~uC|6|(K~Wd2CJx8dj@nPQMKCZu*b$n+`lRpXsW)$&HBaqu zzrAk8dIeiC?p=%jvag7Y5NO!Jr2I|QZT#1KuuIX2Yc2C{rYon8B^+dQ zu6QdQ>w1~3?^Mo_674Xajc&o3P8&tHH1CiJz1r907PZ#+c2aMg;D*B&TA5s#Zp(R| zzFf9r-TQMI6F%&>U^vrMD%;|rKj&@s_FrsCiX1Qhv)*{X$D+q*Bbwr~y{yky>#~I5 zu?a!pt4m|W`Ls8wty0!IDz*GukH!k_?Ho^4LL?$1rX4&TQMkb_KXuIyZ=;|qtWWx8 zDzoc-4OrbDvvJ}PJI{YtD}FQQgt{{5rZy}tlVZs1)+n2M^yF{X$%~fhl_Z8{nk;@& z=ob35bJeu1VR;(H6SMdJf1tCmOpxVQT|pt zpGu@|c*0*bshV+{f>gsaBZm%uo7frFcF(STC{B6(V?mwFmG#A{@84cpzhD2=)%N6t zVc}aB^QV@IUa7lrUTUvM{(0;FtViC+o@-q>JuNm##OpY&pxYz4f0a|Jwe*ohQm~M?c>l_V30X*}7>TC#}AkE&ET8uW<45 z_2*^Emd~uYbUgOI>~|Z}O(*s8p3HJ&s7;nvYQJqd*;%B>p{^*fqY1=}7?zsmWh$dq-; z2K_a4dlw0&OyYNJ|Hr#sF%2&b@r>51>2^a+Q9ak#bjNFw#ZXq->7LpbCOKTL>5mty0hhHgj&9) z-=msGuh(4XuRJ37XVSu_&9Pmx*M(NkIMZXd%(>3u*3Mna=N+5Wa?^2gb z+@;B;@NHXB&8J1$&FZO%(n%kh!jpb(ovK;fpZxLrv2AOOOSBoDvif+Bl@i2ALVkZnsN^g{o3?Yic8o3W|zB91SUE=n$m)%#wyHLb>8`*Nb5V}+{k%5tPJlSakgTQ$R{x>kI1 zy7AGW z=4yYz>dBNDC6dBOJ;mv)`CqrCVOIr`Fk`RnGX;{nna`oF;d$UU2+}7xvW;(#6!>!H0!cY+65Eu}$ zf{8tXF@*7frhft}149baf#8U>5o;f4u3=au6R1$Ml4<5itrk;;1jjWFvEgDYj0Vhs zEPdLHY61zS7iOv^sI+u8h(#|lm|&2xq+}0=1j7T78c%b{MGSYQmG&;*=k4ft_VrEs z*K73@moE6hpuy;6$S^-ecERu9+q|YX(yGe@Hn=T$vo&YuD!*BCq?U+QZns`u`~G6~ z_D|IeEVCWMZd<+FKkdnBmOG}GLvMWd{V#dySPg@h`qU(bD$blr1!etB%hTO28}hw2 zXxJC$(7oZ{>Zy$eW`9bBs#=73E*_e!$S^0XTg&6T$E(8d)mH4=s?E2iuj5ac9LRaV zn(0Q>W98<@+09$u=SO!6Olw+@?EHYC&4VvJHFhIQm`v|ej?){q8@n(_^StRQot<|k zD#qw+)^+V`e4?BC#8lF6uU#Iswa6`Np@dk2nZ>m?kH0=o+Sq;|XoJT~VTnT4dE5SP zI9qSrIs8SlI<*uzo%``8{nnWGG; zCr`%K-+1KvErR3Aq^T+Gz8{v~{iiSKlCXZ#nX})RSS)uw-oe&CKQ?ed%yShw*UY3`5*CZatl)MC0|I!r5{!6*dcfGhoX|i(n zgsbckT8SJC0oot#o#CxM5#YB^AQhA|b-&ZM2*S|B+cNfdRBf$Ic-?vTva8Vr7rpj} zKX0!*bpN;gL5;n&@7h1>?f0*L+PFWw$VyC}Wxn&0#ChNRGq%6~{zhrT{kQ%Z<=+|A z6cloy0q(+P)+Ed)fEnzueo?%tBlx8w%{+@A+oo`v3Re&AYGY zM6a{zlQ~kym+N}22G%a-)BTQO0;i3RSnYLVGn2pb@~dZ} z!KA{Ij~~|VPP=!zgR97h8!J_nYB&2ceZJY^;}yN$g+CXwJ(dJL``mpEuQM&=)uL@ z6=opT&Dw3qp*clKQE=TGhCB1#3UAJ~Ki$3R;le{zx-Nh^~7oC-_0s{G*-A%hPG)*%KTK!;kgD;(Wq;OOq-?d@S{?&Im< zHA+kIM~-OG(6bf$IIWx*T>g4D8M_=KQJi#zsrBe|9i5w_DWd2S|}a9b64}- zWg+@~FPU{D7#OxpPndA?JI9pZr#FgRUH6CUufNUxeEB?$SKE#Sm3Z8U(_GBaF-tVEbw!u!#W0>M(WysIhqy9cTooqz%0V~UQF4+?hpZqcxAgixm3^#B z`d+F8o6RVzTAgAQon?M#$>g`p9DW;4FhsBtY>??r=U4f=?ohugH$k?LP99-7G>iXcex@G;!KUurD zSmv)~%zSO{^zT#ES+|MXa{i`&^DkdM+svhd#d0UBz>Ia~D{j3y^un}LOUiZQs%fs) z{y#sTtyvu9bN_<(hIQLqWSlq5lXPX`+0yoxbH-+i4Y{o1E(zxzDJB#vFj&q!B+;-< zNZXsr zkHjwF_kKy*6>RnnO><%-*qFRE9A{3s2SB0R$71mf9)J|bMu$WJTyf& ziM1u>%-#{WCS{3|=8chDGOyM1-r4paNme(SxqI9Ay;f#* z-N91(18NF}47x@QmYj)vJVLd1?|vR7ykm-Zf`BBYTf^ z+|Zgfh3g~Nw&*$LpSMq66n3=fbilm5Osr>Stvq|DyIXyW`|UL|Z+)4&4h_Ohhl>tsXmzorl{ISq2J4DR;%u3F(oD&X$nL;vwiorIM+ZG)QUc1@c{(zG8@vz;AQzWOgU+`WO zdD+T@_14yFt6VLwWh!@xGOKNw(E5^Lm$53_YU4wE*O_!V^rK9+D(Uj(O=uBya%hrL z?CNRQ&>_aNP?l?o2iK9$)h^Xb-PR=Z3MzM8N!@i}O-Q%T9q&K-4FWoiT!%J_Nw3~v zcwy3M(GqPFy(Fz)t^a~2_^G^2*OxC~nKbL&e2$47dLQGZH90T*%yK*5_uM)2(DIaU z6(Qk^T#Hm$C$P;^n$A9pcarkAidoIYvx^rhf8t!PThM2)=T_6!O2(GHuYxZ;Z|!0J z8+lD#VcW80e0TH{yj>VSNIcLFlj?t1VcQk9erwjWu3ZbVj(YVjTClP!BOsx-W7f9N z-8!MAS1)IXc<3l8EfT466@0WLd>Shc!;(p!58nQI*!p-)U*v6)RA4=^;CgRredRxQnEqc zfs4CZ4xTv0x@OwNlO>hgmmewku{zZt<RLYo#pezL1dCv;`j z77dQBFcY(`wV}PHUQ;(DZHeRDnxV)SAnc|%cd0<1_Hwta(kW>xS&z7iEpNY-nzog> zqg5x5f9qZbVHN!%hA0jNnK|z@tOEsorHx;&sEyN_ZI>nDy)q6TxuqHEnk1$J4B zp5LA=${^sVvw-JuIAciOO<{re`N7^9UzEjb86Q2I62N4y?;t&0qS0UV0JqUQQ-v^t zE8nkq)LG^AWTt=I7*=$ZD|K~gm)BlR?V~|j-8xdI?&r2S%J51Z?N;9Gw|ng)2ga1V zR`Ut+>*b@)Pn#S4!%?lae!hU0$7g1p5>DnuRpATESEWBln)}LkO{{KYM^K1}XrSm+ zSNq$1hw8L=w6$adzZ}26Klb%~OV%ITmoI%BsXVXyx!~7@3@t$uIc8McsG9cO(^ZI@ z+xF&ZU6%LEIy=l5F4Q#{8SUwa*w=V^(VhIY*M2pf(w(wuTat^QX2&L(tgTUNv!;gz zn#!^U-r@+&KA6=fmZ0x+_0|fuma?Nh5gU7pcify>_L3#yS$p-ydPXrlBZg^{7tGK1 z>pAZrDt+Sf6^UHKhhC=_bp%OVjJU`ZXt9cI<1ryNmUTO(&Eeva3SrpzMq+{L*0Zcj z+CFlf;yC;!>~M5yVgqRPJ5E^^5XV& zi?ditubtvLlI0q!qT;yu1ZR@+qf>Q{lcE`>)JpY&ts&v_MqygggM{x)IxMY* z4BcK2uA7R=NceOnZc|M$3TsNb7_l_sOLn@`n~FmdoJw|hn0~VB31g9TnouI#nK+Rl zCatzPr!?BE<@D?`zh;^IP}7b1$1M_P~>IxAC*Rihrx-PTsm?zSvZ;P+zr@6$O#Xp$?+1%NIFniae38S8$rVFv_Fu zruLs~hL*06Jk$BV$ya38hVY10cC!CozhK>d22(~)h6im7ucgv_5`Ea`K;zOujWLFMYlH++tm_3`X| z&w9f{^cceyx2Et@0){Vhr&iy%`*nKtpX*jv)8C0My67IMWE!R`<#=_`i{!xCYt^@J zEi|6+R-?^1u%>P+PtBW2++|@4<6}cla__#F0c>h_@{Y*YV`ISV2y5fOWzZ*8GA=jFM^=ZGc)mH(KIv)nwhKWR)`iNdBiNXC1tHc7y#heVOO1H=1IU zE}UREUM_NNvBi{U&rb9$w3AvK8@=Gx4kgp7jSE(Fhy||YaN{!Ra0@w@`L@S){lbGc z_ORI)c}p3T{0QXBpA>ngVc}bUi@nt)RTCR^TbLVd^H+udTCQ1O)mx2pDu~WSn>{%guV>nn+R3Vy-48AqJjLr9C(kF z)LiR6$&tyuR)Oi-jG}^`Fn33f6^_d_R%s=5vxOea-tD&4EpV&GqYF&gLat$9D&ZQ7 zqFzp39Tt@>k}X)1;wN}q;QiJmVs*1a-gGQ^Z}RY+-GNm)3=Yl>Kbd%?T-YwW*%afp z^_@{@a_^$3DqXIK^~YLGCr##SGMM17yu)hST&1q|tp{B+)V2j>?9Jt7jw$=|#_1dqnYE9Y0h9Hfi`%Kxc(*k8G-?GG%9cAB`Z})jp|2D6+?-ua?p6;^!4})l# z;DJYK3K^x5`P=wHuXe4C66sy^D#z2iF@h;@;dRrvmE1}}?tuzv_e}Y03!)sanB9&` zuQzl1_4w&`aRV=AhA69}ukW${V_=q;+w@h#>=FBov>!8;ZSxD97C0r4H?Y?z^_y1e zif?z?->-2y>h9tqQ7jN}jDbNb^7yQ{rsU2|f4S59%>K{4zo%a8t?pYRgVN ztlBaY?;5<}y^?f$3_7NPt)bCwy`m0^!i`RX zE|L>DCaS8tg>^7BGw4s-ZLRWjM}mNc!6v521kW{P7m5^1Kc2H~zQQ^w$s@qc)*vm3 zAyJtz@@Phx3M-St4Uv;4g1kEx>MD2~_z=QylFcQ@;EE*Y>|-1gW@;xivM||a?UFuZ z8Jkfn-Xh4*5MYxc&M6gb(!lT{!0^r1BibiL1riJxvRTy`?7VY-%bYpSz#INvXX_g8 z&OgQz4;kz(S|2e%<=f4w;vjXqRat79U6XV;7#ij_e=T)gQ|8(2vBzs;(sQ0?8Baey z+VZ10#YC;U|Ju|u*S=qvCtmIUPF&ijc>dhmS-C1TJ&B2VZ+0w=d6nh*AvB65=A@Gn zua>jEHPcd|3OWgn5W9LF2Q;TKy3afWxnyXEoC;!C8wk(gV0>9s9II#d59~_e8EkA$K>GCQqI)Wr7GxjHwBe*0Vb6l?dO9w9AIF3&JuV?CVTCndFojXQhOx0g6#@C z+-4POvhF$He$Q-)DI3!S@c0NT+g`-@2qyyrgTxWJL_YQZ7B0^AApyRDUOxZXRWn+S zY+&N>V0pxI`NETpJfAcEYIlC>PYwwC@cCeL^@(NvqJMNBFbX((_7T@s%5|KR3K3So-M1#F<)~m&}~0!pP7u z$+t3d`P9c&`7frL9(?nAUevn6y50K4f1kbiee}(?C69md2(YW4eEUtbZ2P;rZ)$97 zt}m)PQzG&=Au(rKg2Ah(;7zKH=^_)ke4KPPu=K6%n7SfoYQRo0>*dZpD?bK#ky+OBE-vv} zE4V=;W#*I1=K51EMu~(3cMBF~s7+B52%F~FaL%`1e)oh%21c_lk@GfeZs}0=n!G4z z&U`L~M%}m>`+t?~eo`#ee&a~`?_biN*4CVpi#Rl`!_lNzFye;#Cssb|Ir8Tg^my5Y zngn?+nOIgh<8b_xCYCdaT?^i_2OOFc3|bu2C%x#;ihf~%$K`uC)V@h`y1Sd_83#Nz zuo3FLaf?moPy?eWpRe`V4eTyXA629`uUX%B_T2|fy#vena_k&t6tXzzGro+UrrF|{ z!tH6g%6j9*I<3b!E0=Oj2{^q%c8Uu_OZsjdyZ(tYLKW`m=~yMQ96ltU!!$RF>FK%V z%e4&Aft&}H`#kvgU(#0h$ws{}#|<);Vv1{=%vxM_tlqL}qN3lD2`M6t*QCXmgBWC- z1Q#dzMY&9C4?4W$_&Z0PrgNW}rm#M6TcFGN?ZZsZ(8cx0LO=!;U&5wh(Oy2u*#fs18LSq)p&I;^sx?LrDROy-{+rlTRk0(0yyPR6+ zqFv0&I;}#~YognV1E0iHyh?>9xEtT8dmL=esCbKg`(Fm`Y~BM!jB8d*-VpPlqkL(! zNX$l!MOUXOHD&d-39%kZ)Rfwy-LfftskMpMt*mSn@5u|7id3X>ayWZ`k(|iY)~i^( z%TC4PjG3O!;b))Dt-c(Zd~&Oxw?xCeWWIYkpY!92-9oOdXw`A;-*+UbWW}PMRZCby zBQwu^s`mHX>#%U{s;&gXO-U>Yi!CylzHol6K0IT|zxLJNIk&o2O_`~7Hh*rJpyx3z zH6s=`c@>+FB2n5A$?SYnAG$73+U68uA8olQNjLlVfflFZT~qS?`fe^*VfH;hWo@|YmY{q+(ZJhXTf5Yz z*j#JzbKQ{8>KMt)#q4Z(Xj1>QSv7ar7^>3#ltu?jAH02r-8}Qy{q3r{ocB%@F~869 z-5RtuMEj~2n0i~byZ7!bvpFq0xgezpi~0&qyB`lM`h;tm9yb^l9q8Sh6p{Pp?IYu; zt-14Eo-aG9p&hn1Vr#@z=N$oGMQdH-FRpf!XmONiIk+q0nn}u1QTIX-HqgTU4SK6} zz&G{E91W}q4V!oO^P1DUKnfitjt0sc4Npx~Ww>zpa@@7l*h30D5cEi+FUeB7@#REO z*FX{1i%S?@WS%~~tEC(Y0(DMDGJGkq=~|@GwMg?p?Ube0RG~T#Y4qu&s~XsD+Ljl3 QYLm|COAH@1x)yN&0J>Rs$^ZZW literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/force.ogg b/src/main/resources/assets/wizardry/sounds/force.ogg new file mode 100644 index 0000000000000000000000000000000000000000..0da336b2c1af64d0fc37fa35ceaa1e3b18cc479b GIT binary patch literal 32548 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 UH|Q8ItD4N}!?=WxA>kAg04ZCes{jB1 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/wizardry/sounds/freeze.ogg b/src/main/resources/assets/wizardry/sounds/freeze.ogg new file mode 100644 index 0000000000000000000000000000000000000000..014dc1e436b94b5a73a49aaba4970c8e12ec895c GIT binary patch literal 19753 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