diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index e13fcc28..f2f8737a 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -179,6 +179,8 @@ public class CommonProxy { public void handleConquerShrinePacket(PacketConquerShrine.Message message){} + public void handleBombExplosionPacket(PacketBombExplosion.Message message){} + // SECTION Misc // =============================================================================================================== diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 4915fe45..b3004d66 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -717,6 +717,65 @@ public class ClientProxy extends CommonProxy { }else Wizardry.logger.warn("Received a PacketConquerShrine, but there was no shrine core at the position sent"); } + @Override + public void handleBombExplosionPacket(PacketBombExplosion.Message message){ + + net.minecraft.world.World world = Minecraft.getMinecraft().world; + double x = message.x, y = message.y, z = message.z; + float blastMultiplier = message.blastMultiplier; + + switch(message.bombType){ + + case PacketBombExplosion.FIREBOMB: + ParticleBuilder.create(Type.FLASH).pos(x, y, z).scale(5 * blastMultiplier).clr(1, 0.6f, 0).spawn(world); + for(int i = 0; i < 60 * blastMultiplier; i++){ + ParticleBuilder.create(Type.MAGIC_FIRE, world.rand, x, y, z, 2 * blastMultiplier, false) + .time(10 + world.rand.nextInt(4)).scale(2 + world.rand.nextFloat()).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC, world.rand, x, y, z, 2 * blastMultiplier, false) + .clr(1.0f, 0.2f + world.rand.nextFloat() * 0.4f, 0.0f).spawn(world); + } + world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y, z, 0, 0, 0); + break; + + case PacketBombExplosion.POISON_BOMB: + ParticleBuilder.create(Type.FLASH).pos(x, y, z).scale(5 * blastMultiplier) + .clr(0.2f + world.rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); + for(int i = 0; i < 60 * blastMultiplier; i++){ + ParticleBuilder.create(Type.SPARKLE, world.rand, x, y, z, 2 * blastMultiplier, false).time(35) + .scale(2).clr(0.2f + world.rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC, world.rand, x, y, z, 2 * blastMultiplier, false) + .clr(0.2f + world.rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world); + } + world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y, z, 0, 0, 0); + break; + + case PacketBombExplosion.SMOKE_BOMB: + ParticleBuilder.create(Type.FLASH).pos(x, y, z).scale(5 * blastMultiplier).clr(0, 0, 0).spawn(world); + world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y, z, 0, 0, 0); + for(int i = 0; i < 60 * blastMultiplier; i++){ + float brightness = world.rand.nextFloat() * 0.1f + 0.1f; + ParticleBuilder.create(Type.CLOUD, world.rand, x, y, z, 2 * blastMultiplier, false) + .clr(brightness, brightness, brightness).time(80 + world.rand.nextInt(12)).shaded(true).spawn(world); + brightness = world.rand.nextFloat() * 0.3f; + ParticleBuilder.create(Type.DARK_MAGIC, world.rand, x, y, z, 2 * blastMultiplier, false) + .clr(brightness, brightness, brightness).spawn(world); + } + break; + + case PacketBombExplosion.SPARK_BOMB: + ParticleBuilder.spawnShockParticles(world, x, y, z); + for(int id : message.secondaryTargetIDs){ + net.minecraft.entity.Entity target = world.getEntityByID(id); + if(target instanceof net.minecraft.entity.EntityLivingBase){ + ParticleBuilder.create(Type.LIGHTNING).pos(x, y, z).target(target).spawn(world); + ParticleBuilder.spawnShockParticles(world, target.posX, + target.posY + target.height / 2, target.posZ); + } + } + break; + } + } + // Rendering // =============================================================================================================== @@ -881,48 +940,13 @@ public class ClientProxy extends CommonProxy { } public void registerItemColorHandlers() { - Minecraft.getMinecraft().getItemColors().registerItemColorHandler((stack, tintIndex) -> { - if (Wizardry.settings.spellBookColors && tintIndex == 1) { // layer 1 is the overlay - Spell spell = Spell.byMetadata(stack.getMetadata()); - - if (shouldDisplayDiscovered(spell, stack)) { - // Even if the spell is discovered, the charm might be required for colouration - if(Wizardry.settings.spellBookColorsRequireArchivistsEyeglass && !ItemArtefact.isArtefactActive(getThePlayer(), WizardryItems.charm_spell_discovery)) { - return -1; - } - - Element element = spell.getElement(); - if (element != null) { - switch (element) { - case MAGIC: - return 0xAAAAAA; // GRAY - case FIRE: - return 0xAA0000; // DARK_RED - case ICE: - return 0x55FFFF; // AQUA - case LIGHTNING: - return 0x00AAAA; // DARK_AQUA - case NECROMANCY: - return 0xAA00AA; // DARK_PURPLE - case EARTH: - return 0x00AA00; // DARK_GREEN - case SORCERY: - return 0x55FF55; // GREEN - case HEALING: - return 0xFFFF55; // YELLOW - } - } - } - } - return -1; - }, WizardryItems.spell_book); + // Spell book overlay textures are now per-element, so no runtime tinting is needed. } public void registerModelProperties() { Item spellBook = WizardryItems.spell_book; - ResourceLocation discoveredProperty = new ResourceLocation(Wizardry.MODID, "discovered"); - spellBook.addPropertyOverride(discoveredProperty, (stack, world, entity) -> { + spellBook.addPropertyOverride(new ResourceLocation(Wizardry.MODID, "discovered"), (stack, world, entity) -> { if (!Wizardry.settings.spellBookColors) return 0.0f; boolean discovered = shouldDisplayDiscovered(Spell.byMetadata(stack.getMetadata()), stack); @@ -938,5 +962,27 @@ public class ClientProxy extends CommonProxy { return discovered ? 1.0f : 0.0f; }); + + // Returns ordinal+1 for each element (1=MAGIC through 8=HEALING), or 0 if not yet discovered. + // Drives per-element bookmark texture selection via model overrides in spell_book.json. + spellBook.addPropertyOverride(new ResourceLocation(Wizardry.MODID, "element"), (stack, world, entity) -> { + if (!Wizardry.settings.spellBookColors) return 0.0f; + + Spell spell = Spell.byMetadata(stack.getMetadata()); + boolean discovered = shouldDisplayDiscovered(spell, stack); + + if(!discovered) return 0.0f; + + if(Wizardry.settings.spellBookColorsRequireArchivistsEyeglass){ + if(entity instanceof EntityPlayer){ + if(!ItemArtefact.isArtefactActive((EntityPlayer)entity, WizardryItems.charm_spell_discovery)) return 0.0f; + } else { + return 0.0f; + } + } + + Element element = spell.getElement(); + return element == null ? 0.0f : (float)(element.ordinal() + 1); + }); } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java index d380ba84..495f2626 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java @@ -1,18 +1,18 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.packet.PacketBombExplosion; +import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.EntityUtils; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.NetworkRegistry; import java.util.List; @@ -29,41 +29,28 @@ public class EntityFirebomb extends EntityBomb { @Override protected void onImpact(RayTraceResult rayTrace){ - - Entity entityHit = rayTrace.entityHit; - - if(entityHit != null){ - // This is if the firebomb gets a direct hit - float damage = Spells.firebomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier; - - entityHit.attackEntityFrom( - MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(), - damage); - - if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit)) - entityHit.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue()); - } - - // Particle effect - if(world.isRemote){ - - ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier).clr(1, 0.6f, 0) - .spawn(world); - - for(int i = 0; i < 60 * blastMultiplier; i++){ - - ParticleBuilder.create(Type.MAGIC_FIRE, rand, posX, posY, posZ, 2*blastMultiplier, false) - .time(10 + rand.nextInt(4)).scale(2 + rand.nextFloat()).spawn(world); - - ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) - .clr(1.0f, 0.2f + rand.nextFloat() * 0.4f, 0.0f).spawn(world); - } - - this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); - } if(!this.world.isRemote){ + Entity entityHit = rayTrace.entityHit; + + if(entityHit != null){ + // This is if the firebomb gets a direct hit + float damage = Spells.firebomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier; + + entityHit.attackEntityFrom( + MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(), + damage); + + if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit)) + entityHit.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue()); + } + + // Notify clients to play the explosion effect + WizardryPacketHandler.net.sendToAllAround( + new PacketBombExplosion.Message(PacketBombExplosion.FIREBOMB, posX, posY, posZ, blastMultiplier), + new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64)); + this.playSound(WizardrySounds.ENTITY_FIREBOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F); this.playSound(WizardrySounds.ENTITY_FIREBOMB_FIRE, 1, 1); @@ -82,9 +69,9 @@ public class EntityFirebomb extends EntityBomb { target.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue()); } } - - this.setDead(); } + + this.setDead(); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java index 83ffbb9e..2c0e7d0b 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java @@ -1,20 +1,20 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.packet.PacketBombExplosion; +import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.EntityUtils; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.NetworkRegistry; import java.util.List; @@ -31,44 +31,30 @@ public class EntityPoisonBomb extends EntityBomb { @Override protected void onImpact(RayTraceResult rayTrace){ - - Entity entityHit = rayTrace.entityHit; - - if(entityHit != null){ - // This is if the poison bomb gets a direct hit - float damage = Spells.poison_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * 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, - Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_DURATION).intValue(), - Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_STRENGTH).intValue())); - } - - // Particle effect - if(world.isRemote){ - - ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier) - .clr(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); - - for(int i = 0; i < 60 * blastMultiplier; i++){ - - ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 2*blastMultiplier, false).time(35) - .scale(2).clr(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); - - ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) - .clr(0.2f + rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world); - } - // Spawning this after the other particles fixes the rendering colour bug. It's a bit of a cheat, but it - // works pretty well. - this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); - } if(!this.world.isRemote){ + Entity entityHit = rayTrace.entityHit; + + if(entityHit != null){ + // This is if the poison bomb gets a direct hit + float damage = Spells.poison_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * 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, + Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_DURATION).intValue(), + Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_STRENGTH).intValue())); + } + + // Notify clients to play the explosion effect + WizardryPacketHandler.net.sendToAllAround( + new PacketBombExplosion.Message(PacketBombExplosion.POISON_BOMB, posX, posY, posZ, blastMultiplier), + new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64)); + this.playSound(WizardrySounds.ENTITY_POISON_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F); this.playSound(WizardrySounds.ENTITY_POISON_BOMB_POISON, 1.2F, 1.0f); @@ -88,8 +74,8 @@ public class EntityPoisonBomb extends EntityBomb { Spells.poison_bomb.getProperty(Spell.SPLASH_EFFECT_STRENGTH).intValue())); } } - - this.setDead(); } + + this.setDead(); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java index d3bbeed8..5e32aab1 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java @@ -1,17 +1,17 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.packet.PacketBombExplosion; +import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.EntityUtils; -import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.NetworkRegistry; import java.util.List; @@ -29,27 +29,13 @@ public class EntitySmokeBomb extends EntityBomb { @Override protected void onImpact(RayTraceResult rayTrace){ - // Particle effect - if(world.isRemote){ - - ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier).clr(0, 0, 0).spawn(world); - - this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); - - for(int i = 0; i < 60 * blastMultiplier; i++){ - - float brightness = rand.nextFloat() * 0.1f + 0.1f; - ParticleBuilder.create(Type.CLOUD, rand, posX, posY, posZ, 2*blastMultiplier, false) - .clr(brightness, brightness, brightness).time(80 + this.rand.nextInt(12)).shaded(true).spawn(world); - - brightness = rand.nextFloat() * 0.3f; - ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) - .clr(brightness, brightness, brightness).spawn(world); - } - } - if(!this.world.isRemote){ + // Notify clients to play the explosion effect + WizardryPacketHandler.net.sendToAllAround( + new PacketBombExplosion.Message(PacketBombExplosion.SMOKE_BOMB, posX, posY, posZ, blastMultiplier), + new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64)); + this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F); this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMOKE, 1.2F, 1.0f); @@ -65,8 +51,8 @@ public class EntitySmokeBomb extends EntityBomb { target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0)); } } - - this.setDead(); } + + this.setDead(); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java index facb0dd0..031a36cd 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java @@ -1,5 +1,7 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.packet.PacketBombExplosion; +import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; @@ -13,7 +15,9 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import java.util.ArrayList; import java.util.List; public class EntitySparkBomb extends EntityBomb { @@ -31,47 +35,37 @@ public class EntitySparkBomb extends EntityBomb { @Override protected void onImpact(RayTraceResult rayTrace){ - - this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT_BLOCK, 0.5f, 0.5f); - Entity entityHit = rayTrace.entityHit; + if(!this.world.isRemote){ - if(entityHit != null){ - // This is if the spark bomb gets a direct hit - float damage = Spells.spark_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier; + Entity entityHit = rayTrace.entityHit; - this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + if(entityHit != null){ + // This is if the spark bomb gets a direct hit + float damage = Spells.spark_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier; - entityHit.attackEntityFrom( - MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(), - damage); + this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT, 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(world.isRemote){ - ParticleBuilder.spawnShockParticles(world, posX, posY + height/2, posZ); - } + double seekerRange = Spells.spark_bomb.getProperty(Spell.EFFECT_RADIUS).doubleValue() * blastMultiplier; - double seekerRange = Spells.spark_bomb.getProperty(Spell.EFFECT_RADIUS).doubleValue() * blastMultiplier; + List targets = EntityUtils.getLivingWithinRadius(seekerRange, this.posX, this.posY, + this.posZ, this.world); - List targets = EntityUtils.getLivingWithinRadius(seekerRange, this.posX, this.posY, - this.posZ, this.world); + List secondaryTargetIDs = new ArrayList<>(); - for(int i = 0; i < Math.min(targets.size(), Spells.spark_bomb.getProperty(SECONDARY_MAX_TARGETS).intValue()); i++){ + for(int i = 0; i < Math.min(targets.size(), Spells.spark_bomb.getProperty(SECONDARY_MAX_TARGETS).intValue()); i++){ - boolean flag = targets.get(i) != entityHit && targets.get(i) != this.getThrower() - && !(targets.get(i) instanceof EntityPlayer - && ((EntityPlayer)targets.get(i)).isCreative()); + boolean flag = targets.get(i) != entityHit && targets.get(i) != this.getThrower() + && !(targets.get(i) instanceof EntityPlayer + && ((EntityPlayer)targets.get(i)).isCreative()); - // Detects (client side) if target is the thrower, to stop particles being spawned around them. - //if(flag && world.isRemote && targets.get(i).getEntityId() == this.playerID) flag = false; - - if(flag){ - - EntityLivingBase target = targets.get(i); - - if(!this.world.isRemote){ + if(flag){ + EntityLivingBase target = targets.get(i); target.playSound(WizardrySounds.ENTITY_SPARK_BOMB_CHAIN, 1.0F, rand.nextFloat() * 0.4F + 1.5F); @@ -79,11 +73,18 @@ public class EntitySparkBomb extends EntityBomb { MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK), Spells.spark_bomb.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier); - }else{ - ParticleBuilder.create(Type.LIGHTNING).pos(this.getPositionVector()).target(target).spawn(world); - ParticleBuilder.spawnShockParticles(world, target.posX, target.posY + target.height/2, target.posZ); + secondaryTargetIDs.add(target.getEntityId()); } } + + // Notify clients to play the explosion effect, including lightning arcs to secondary targets + int[] idArray = secondaryTargetIDs.stream().mapToInt(Integer::intValue).toArray(); + WizardryPacketHandler.net.sendToAllAround( + new PacketBombExplosion.Message(PacketBombExplosion.SPARK_BOMB, posX, posY + height / 2, posZ, + blastMultiplier, idArray), + new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64)); + + this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT_BLOCK, 0.5f, 0.5f); } this.setDead(); diff --git a/src/main/java/electroblob/wizardry/packet/PacketBombExplosion.java b/src/main/java/electroblob/wizardry/packet/PacketBombExplosion.java new file mode 100644 index 00000000..1955416f --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketBombExplosion.java @@ -0,0 +1,79 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +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 bomb entity impacts something. It is used to guarantee that the + * client always sees the explosion effect, even in singleplayer where the server may remove the entity before the + * client's own simulation can call {@code onImpact()}. + */ +public class PacketBombExplosion implements IMessageHandler { + + /** Bomb type constants, matching the order bombs are handled in {@link electroblob.wizardry.CommonProxy}. */ + public static final int FIREBOMB = 0; + public static final int POISON_BOMB = 1; + public static final int SMOKE_BOMB = 2; + public static final int SPARK_BOMB = 3; + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + if(ctx.side.isClient()){ + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask( + () -> Wizardry.proxy.handleBombExplosionPacket(message)); + } + return null; + } + + public static class Message implements IMessage { + + /** One of the bomb type constants defined in {@link PacketBombExplosion}. */ + public int bombType; + public double x, y, z; + public float blastMultiplier; + /** Entity IDs of secondary targets struck by the spark bomb chain. Empty for other bomb types. */ + public int[] secondaryTargetIDs; + + // Required no-arg constructor + public Message(){} + + public Message(int bombType, double x, double y, double z, float blastMultiplier){ + this(bombType, x, y, z, blastMultiplier, new int[0]); + } + + public Message(int bombType, double x, double y, double z, float blastMultiplier, int[] secondaryTargetIDs){ + this.bombType = bombType; + this.x = x; + this.y = y; + this.z = z; + this.blastMultiplier = blastMultiplier; + this.secondaryTargetIDs = secondaryTargetIDs; + } + + @Override + public void fromBytes(ByteBuf buf){ + bombType = buf.readInt(); + x = buf.readDouble(); + y = buf.readDouble(); + z = buf.readDouble(); + blastMultiplier = buf.readFloat(); + int count = buf.readInt(); + secondaryTargetIDs = new int[count]; + for(int i = 0; i < count; i++) secondaryTargetIDs[i] = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeInt(bombType); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeFloat(blastMultiplier); + buf.writeInt(secondaryTargetIDs.length); + for(int id : secondaryTargetIDs) buf.writeInt(id); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java index 2959b5eb..f2cbd363 100644 --- a/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java +++ b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java @@ -35,6 +35,7 @@ public class WizardryPacketHandler { registerMessage(PacketSpellQuickAccess.class, PacketSpellQuickAccess.Message.class); registerMessage(PacketRequestDonationPerks.class, PacketRequestDonationPerks.Message.class); registerMessage(PacketSyncDonationPerks.class, PacketSyncDonationPerks.Message.class); + registerMessage(PacketBombExplosion.class, PacketBombExplosion.Message.class); } private static int nextPacketId = 0; diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book.json b/src/main/resources/assets/ebwizardry/models/item/spell_book.json index 7ad16e32..cdc3b048 100644 --- a/src/main/resources/assets/ebwizardry/models/item/spell_book.json +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book.json @@ -1,17 +1,14 @@ { "parent": "ebwizardry:item/spell_book_undiscovered", "overrides": [ - { - "predicate": { - "festive": 1 - }, - "model": "ebwizardry:item/festive_spell_book" - }, - { - "predicate": { - "ebwizardry:discovered": 1 - }, - "model": "ebwizardry:item/spell_book_discovered" - } + {"predicate": {"ebwizardry:element": 1}, "model": "ebwizardry:item/spell_book_discovered_magic"}, + {"predicate": {"ebwizardry:element": 2}, "model": "ebwizardry:item/spell_book_discovered_fire"}, + {"predicate": {"ebwizardry:element": 3}, "model": "ebwizardry:item/spell_book_discovered_ice"}, + {"predicate": {"ebwizardry:element": 4}, "model": "ebwizardry:item/spell_book_discovered_lightning"}, + {"predicate": {"ebwizardry:element": 5}, "model": "ebwizardry:item/spell_book_discovered_necromancy"}, + {"predicate": {"ebwizardry:element": 6}, "model": "ebwizardry:item/spell_book_discovered_earth"}, + {"predicate": {"ebwizardry:element": 7}, "model": "ebwizardry:item/spell_book_discovered_sorcery"}, + {"predicate": {"ebwizardry:element": 8}, "model": "ebwizardry:item/spell_book_discovered_healing"}, + {"predicate": {"festive": 1}, "model": "ebwizardry:item/festive_spell_book"} ] } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_earth.json b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_earth.json new file mode 100644 index 00000000..3888085c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_earth.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/spell_book", + "layer1": "ebwizardry:items/spell_book_overlay_earth" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_fire.json b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_fire.json new file mode 100644 index 00000000..ecb99ea8 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_fire.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/spell_book", + "layer1": "ebwizardry:items/spell_book_overlay_fire" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_healing.json b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_healing.json new file mode 100644 index 00000000..93b7a622 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_healing.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/spell_book", + "layer1": "ebwizardry:items/spell_book_overlay_healing" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_ice.json b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_ice.json new file mode 100644 index 00000000..b70583c3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_ice.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/spell_book", + "layer1": "ebwizardry:items/spell_book_overlay_ice" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_lightning.json b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_lightning.json new file mode 100644 index 00000000..800292db --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_lightning.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/spell_book", + "layer1": "ebwizardry:items/spell_book_overlay_lightning" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_magic.json b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_magic.json new file mode 100644 index 00000000..7ced19b2 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_magic.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/spell_book", + "layer1": "ebwizardry:items/spell_book_overlay_magic" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_necromancy.json b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_necromancy.json new file mode 100644 index 00000000..d9de729d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_necromancy.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/spell_book", + "layer1": "ebwizardry:items/spell_book_overlay_necromancy" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_sorcery.json b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_sorcery.json new file mode 100644 index 00000000..7d480baa --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book_discovered_sorcery.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/spell_book", + "layer1": "ebwizardry:items/spell_book_overlay_sorcery" + } +} diff --git a/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_earth.png b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_earth.png new file mode 100644 index 00000000..15898a6b Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_earth.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_fire.png b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_fire.png new file mode 100644 index 00000000..1fa3e193 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_fire.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_healing.png b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_healing.png new file mode 100644 index 00000000..29fd8a02 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_healing.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_ice.png b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_ice.png new file mode 100644 index 00000000..6ff5c31d Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_ice.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_lightning.png b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_lightning.png new file mode 100644 index 00000000..3e453ff4 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_lightning.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_magic.png b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_magic.png new file mode 100644 index 00000000..8803aaed Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_magic.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_necromancy.png b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_necromancy.png new file mode 100644 index 00000000..e9f53b84 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_necromancy.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_sorcery.png b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_sorcery.png new file mode 100644 index 00000000..175d2be6 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/spell_book_overlay_sorcery.png differ