diff --git a/src/main/java/cr0s/warpdrive/WarpDrive.java b/src/main/java/cr0s/warpdrive/WarpDrive.java index 9cb93df5..1e4facac 100644 --- a/src/main/java/cr0s/warpdrive/WarpDrive.java +++ b/src/main/java/cr0s/warpdrive/WarpDrive.java @@ -119,6 +119,7 @@ import cr0s.warpdrive.data.StarMapRegistry; import cr0s.warpdrive.event.ChunkHandler; import cr0s.warpdrive.event.ClientHandler; import cr0s.warpdrive.event.CommonWorldGenerator; +import cr0s.warpdrive.event.ItemHandler; import cr0s.warpdrive.event.LivingHandler; import cr0s.warpdrive.event.WorldHandler; import cr0s.warpdrive.item.ItemAirTank; @@ -731,7 +732,7 @@ public class WarpDrive implements LoadingCallback { // Event handlers MinecraftForge.EVENT_BUS.register(new ClientHandler()); - + MinecraftForge.EVENT_BUS.register(new ItemHandler()); MinecraftForge.EVENT_BUS.register(new LivingHandler()); if (WarpDriveConfig.isComputerCraftLoaded) { diff --git a/src/main/java/cr0s/warpdrive/api/IItemBase.java b/src/main/java/cr0s/warpdrive/api/IItemBase.java new file mode 100644 index 00000000..25cb4ff6 --- /dev/null +++ b/src/main/java/cr0s/warpdrive/api/IItemBase.java @@ -0,0 +1,10 @@ +package cr0s.warpdrive.api; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.item.ItemStack; + +public interface IItemBase { + + // wrapper for Forge ItemExpireEvent + void onEntityExpireEvent(EntityItem entityItem, ItemStack itemStack); +} diff --git a/src/main/java/cr0s/warpdrive/api/Particle.java b/src/main/java/cr0s/warpdrive/api/Particle.java index c765c33d..cc8aba1c 100644 --- a/src/main/java/cr0s/warpdrive/api/Particle.java +++ b/src/main/java/cr0s/warpdrive/api/Particle.java @@ -1,11 +1,14 @@ package cr0s.warpdrive.api; import cr0s.warpdrive.Commons; +import cr0s.warpdrive.WarpDrive; +import cr0s.warpdrive.data.Vector3; import java.util.Locale; import net.minecraft.item.EnumRarity; import net.minecraft.util.StatCollector; +import net.minecraft.world.World; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -17,6 +20,9 @@ public class Particle { protected int colorIndex; protected EnumRarity enumRarity = EnumRarity.common; + private int entityLifespan; + private float radiationLevel = 0.0F; + private float explosionStrength = 0.0F; public Particle(final String registryName) { this.registryName = registryName.toLowerCase(Locale.ENGLISH); @@ -42,6 +48,21 @@ public class Particle { return this; } + public Particle setEntityLifespan(final int entityLifespan) { + this.entityLifespan = entityLifespan; + return this; + } + + public Particle setRadiationLevel(final float radiationLevel) { + this.radiationLevel = radiationLevel; + return this; + } + + public Particle setExplosionStrength(final float explosionStrength) { + this.explosionStrength = explosionStrength; + return this; + } + public final String getRegistryName() { return this.registryName; @@ -80,5 +101,26 @@ public class Particle { { return color; } + + public int getEntityLifespan() { + return entityLifespan; + } + + /* Effector */ + + public void onWorldEffect(final World world, final Vector3 v3Position, final int amount) { + if (world.isRemote) { + return; + } + if (radiationLevel > 0.0F) { + final float strength = radiationLevel * amount / 1000.0F; + WarpDrive.damageIrradiation.onWorldEffect(world, v3Position, strength); + } + if (explosionStrength > 0.0F) { + final float amountFactor = Math.max(1.25F, amount / 1000.0F); + world.newExplosion(null, v3Position.x, v3Position.y, v3Position.z, explosionStrength * amountFactor, true, true); + WarpDrive.logger.info("Particle caused explosion at " + v3Position.x + " " + v3Position.y + " " + v3Position.z + " with strength " + explosionStrength * amountFactor); + } + } } diff --git a/src/main/java/cr0s/warpdrive/api/ParticleRegistry.java b/src/main/java/cr0s/warpdrive/api/ParticleRegistry.java index 5d846d74..400b0e4e 100644 --- a/src/main/java/cr0s/warpdrive/api/ParticleRegistry.java +++ b/src/main/java/cr0s/warpdrive/api/ParticleRegistry.java @@ -18,10 +18,14 @@ public class ParticleRegistry { private static BiMap particles = HashBiMap.create(); - public static final Particle ION = new Particle("ion") { }.setColor(0xE5FF54).setRarity(EnumRarity.common).setColorIndex(0); - public static final Particle PROTON = new Particle("proton") { }.setColor(0xE5FF54).setRarity(EnumRarity.common).setColorIndex(1); - public static final Particle ANTIMATTER = new Particle("antimatter") { }.setColor(0x1C3CAF).setRarity(EnumRarity.uncommon).setColorIndex(2); - public static final Particle STRANGE_MATTER = new Particle("strange_matter") { }.setColor(0xE2414C).setRarity(EnumRarity.rare).setColorIndex(3); + public static final Particle ION = new Particle("ion") { }.setColor(0xE5FF54).setRarity(EnumRarity.common).setColorIndex(0) + .setEntityLifespan(200).setRadiationLevel(2.0F).setExplosionStrength(0.3F); + public static final Particle PROTON = new Particle("proton") { }.setColor(0xE5FF54).setRarity(EnumRarity.common).setColorIndex(1) + .setEntityLifespan(200).setRadiationLevel(4.0F).setExplosionStrength(0.5F); + public static final Particle ANTIMATTER = new Particle("antimatter") { }.setColor(0x1C3CAF).setRarity(EnumRarity.uncommon).setColorIndex(2) + .setEntityLifespan(60).setRadiationLevel(10.0F).setExplosionStrength(1.0F); + public static final Particle STRANGE_MATTER = new Particle("strange_matter") { }.setColor(0xE2414C).setRarity(EnumRarity.rare).setColorIndex(3) + .setEntityLifespan(40).setRadiationLevel(14.0F).setExplosionStrength(0.8F); // public static final Particle TACHYONS = new Particle("tachyons") { }.setColor(0xE5FF54).setRarity(EnumRarity.epic).setColorIndex(4); static { diff --git a/src/main/java/cr0s/warpdrive/api/ParticleStack.java b/src/main/java/cr0s/warpdrive/api/ParticleStack.java index cd5a390c..cd9e6c39 100644 --- a/src/main/java/cr0s/warpdrive/api/ParticleStack.java +++ b/src/main/java/cr0s/warpdrive/api/ParticleStack.java @@ -1,9 +1,12 @@ package cr0s.warpdrive.api; +import cr0s.warpdrive.data.Vector3; + import javax.annotation.Nonnull; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; import cpw.mods.fml.common.FMLLog; @@ -77,6 +80,20 @@ public class ParticleStack { amount += amountAdded; } + public int getEntityLifespan() { + if (particle == null) { + return -1; + } + return particle.getEntityLifespan(); + } + + public void onWorldEffect(@Nonnull final World world, @Nonnull final Vector3 v3Position) { + if (particle == null) { + return; + } + particle.onWorldEffect(world, v3Position, amount); + } + public String getLocalizedName() { return this.getParticle().getLocalizedName(); } diff --git a/src/main/java/cr0s/warpdrive/damage/DamageIrradiation.java b/src/main/java/cr0s/warpdrive/damage/DamageIrradiation.java index 45100474..73391c87 100644 --- a/src/main/java/cr0s/warpdrive/damage/DamageIrradiation.java +++ b/src/main/java/cr0s/warpdrive/damage/DamageIrradiation.java @@ -1,6 +1,18 @@ package cr0s.warpdrive.damage; +import cr0s.warpdrive.Commons; +import cr0s.warpdrive.WarpDrive; +import cr0s.warpdrive.config.WarpDriveConfig; +import cr0s.warpdrive.data.Vector3; +import cr0s.warpdrive.network.PacketHandler; + +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.DamageSource; +import net.minecraft.world.World; public class DamageIrradiation extends DamageSource { @@ -10,4 +22,54 @@ public class DamageIrradiation extends DamageSource { setDamageIsAbsolute(); } + public void onWorldEffect(final World world, final Vector3 v3Position, final float strength) { + // only search up to distance where damage applied is 0.5 + final double radius = Math.sqrt(2.0D * strength); + final AxisAlignedBB axisAlignedBB = AxisAlignedBB.getBoundingBox( + v3Position.x - radius, v3Position.y - radius, v3Position.z - radius, + v3Position.x + radius, v3Position.y + radius, v3Position.z + radius); + final List listEntityLivingBase = world.getEntitiesWithinAABB(EntityLivingBase.class, axisAlignedBB); + if (listEntityLivingBase != null) { + for (EntityLivingBase entityLivingBase : listEntityLivingBase) { + // cap damage below 1 m distance, since the entity is never really inside the source and damage tends to +INF + final float distance = Math.min(1.0F, (float) Math.sqrt(v3Position.distanceTo_square(entityLivingBase))); + onEntityEffect(strength / (distance * distance), world, v3Position, entityLivingBase); + } + } + } + + public void onEntityEffect(final float strength, final World world, final Vector3 v3Source, final Entity entity) { + if ( strength <= 0.0F + || !(entity instanceof EntityLivingBase) + || entity.isDead ) { + return; + } + + // common particle effects properties + final Vector3 v3Entity = new Vector3(entity); + final Vector3 v3Direction = new Vector3(entity).subtract(v3Source).normalize(); + final Vector3 v3From = v3Source.clone(); + v3From.translateFactor(v3Direction, 0.6D); + v3Entity.translateFactor(v3Direction, -0.6D); + + final double speed = Math.abs(strength); + final Vector3 v3Motion = v3Direction.clone().scale(speed); // new Vector3(entity.motionX, entity.motionY, entity.motionZ); + if (WarpDriveConfig.LOGGING_ACCELERATOR && WarpDrive.isDev) { + PacketHandler.sendBeamPacket(world, v3From, v3Entity, + 0.25F, 0.75F, 0.38F, 10, 0, 50); + WarpDrive.logger.info(String.format("%s strength %.1f speed %.3f entity %s source %s direction %s motion %s entity %s", + this, strength, speed, v3Entity, v3Source, v3Direction, v3Motion, entity)); + } + + // apply damages and particle effects + entity.attackEntityFrom(this, strength); + + // visual effect + v3Direction.scale(0.20D); + PacketHandler.sendSpawnParticlePacket(world, "mobSpell", (byte) Commons.clamp(3, 10, strength), v3Entity, v3Direction, + 0.20F + 0.10F * world.rand.nextFloat(), + 0.90F + 0.10F * world.rand.nextFloat(), + 0.40F + 0.15F * world.rand.nextFloat(), + 0.0F, 0.0F, 0.0F, 32); + } } diff --git a/src/main/java/cr0s/warpdrive/event/ItemHandler.java b/src/main/java/cr0s/warpdrive/event/ItemHandler.java new file mode 100644 index 00000000..284230e5 --- /dev/null +++ b/src/main/java/cr0s/warpdrive/event/ItemHandler.java @@ -0,0 +1,28 @@ +package cr0s.warpdrive.event; + +import cr0s.warpdrive.api.IItemBase; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.event.entity.item.ItemExpireEvent; + +public class ItemHandler { + + @SubscribeEvent + public static void onItemExpireEvent(final ItemExpireEvent event) { + if (event.entityItem == null) { + return; + } + final ItemStack itemStack = event.entityItem.getEntityItem(); + if (itemStack == null) { + return; + } + final Item item = itemStack.getItem(); + if (!(item instanceof IItemBase)) { + return; + } + ((IItemBase) item).onEntityExpireEvent(event.entityItem, itemStack); + } +} diff --git a/src/main/java/cr0s/warpdrive/item/ItemAbstractBase.java b/src/main/java/cr0s/warpdrive/item/ItemAbstractBase.java new file mode 100644 index 00000000..f77f394d --- /dev/null +++ b/src/main/java/cr0s/warpdrive/item/ItemAbstractBase.java @@ -0,0 +1,20 @@ +package cr0s.warpdrive.item; + +import cr0s.warpdrive.WarpDrive; +import cr0s.warpdrive.api.IItemBase; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public class ItemAbstractBase extends Item implements IItemBase { + + public ItemAbstractBase() { + super(); + setCreativeTab(WarpDrive.creativeTabWarpDrive); + } + + @Override + public void onEntityExpireEvent(final EntityItem entityItem, final ItemStack itemStack) { + } +} diff --git a/src/main/java/cr0s/warpdrive/item/ItemElectromagneticCell.java b/src/main/java/cr0s/warpdrive/item/ItemElectromagneticCell.java index 444de6ec..5d8ac87a 100644 --- a/src/main/java/cr0s/warpdrive/item/ItemElectromagneticCell.java +++ b/src/main/java/cr0s/warpdrive/item/ItemElectromagneticCell.java @@ -6,11 +6,13 @@ import cr0s.warpdrive.api.IParticleContainerItem; import cr0s.warpdrive.api.Particle; import cr0s.warpdrive.api.ParticleRegistry; import cr0s.warpdrive.api.ParticleStack; +import cr0s.warpdrive.data.Vector3; import java.util.List; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.Item; @@ -18,11 +20,12 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.IIcon; import net.minecraft.util.StatCollector; +import net.minecraft.world.World; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -public class ItemElectromagneticCell extends Item implements IParticleContainerItem { +public class ItemElectromagneticCell extends ItemAbstractBase implements IParticleContainerItem { private static final String AMOUNT_TO_CONSUME_TAG = "amountToConsume"; @@ -150,7 +153,7 @@ public class ItemElectromagneticCell extends Item implements IParticleContainerI } private static int getDamageLevel(ItemStack itemStack, final ParticleStack particleStack) { - if (!(itemStack.getItem() instanceof ItemElectromagneticCell)) { + if (!(itemStack.getItem() instanceof ItemElectromagneticCell)) { WarpDrive.logger.error("Invalid ItemStack passed, expecting ItemElectromagneticCell: " + itemStack); return itemStack.getItemDamage(); } @@ -199,7 +202,7 @@ public class ItemElectromagneticCell extends Item implements IParticleContainerI } else if (!particleStack.isParticleEqual(resource) || particleStack.getAmount() >= getCapacity(itemStack)) { return 0; } - int transfer = Math.min(resource.getAmount(), getCapacity(itemStack) - particleStack.getAmount()); + final int transfer = Math.min(resource.getAmount(), getCapacity(itemStack) - particleStack.getAmount()); if (doFill) { particleStack.fill(transfer); @@ -215,7 +218,7 @@ public class ItemElectromagneticCell extends Item implements IParticleContainerI @Override public ParticleStack drain(ItemStack itemStack, final ParticleStack resource, final boolean doDrain) { - ParticleStack particleStack = getParticleStack(itemStack); + final ParticleStack particleStack = getParticleStack(itemStack); if (particleStack == null || particleStack.getParticle() == null) { return null; } @@ -226,7 +229,7 @@ public class ItemElectromagneticCell extends Item implements IParticleContainerI if (doDrain) { particleStack.fill(-transfer); - NBTTagCompound tagCompound = itemStack.hasTagCompound() ? itemStack.getTagCompound() : new NBTTagCompound(); + final NBTTagCompound tagCompound = itemStack.hasTagCompound() ? itemStack.getTagCompound() : new NBTTagCompound(); tagCompound.setTag("particle", particleStack.writeToNBT(new NBTTagCompound())); if (!itemStack.hasTagCompound()) { itemStack.setTagCompound(tagCompound); @@ -236,6 +239,32 @@ public class ItemElectromagneticCell extends Item implements IParticleContainerI return resource.copy(transfer); } + @Override + public int getEntityLifespan(final ItemStack itemStack, final World world) { + final ParticleStack particleStack = getParticleStack(itemStack); + if ( particleStack == null + || particleStack.isEmpty() ) { + return super.getEntityLifespan(itemStack, world); + } + final int lifespan = particleStack.getEntityLifespan(); + if (lifespan < 0) { + return super.getEntityLifespan(itemStack, world); + } + // less content means more stable, so we scale lifespan with emptiness, up to doubling it + return (2 - particleStack.getAmount() / getCapacity(itemStack)) * lifespan; + } + + @Override + public void onEntityExpireEvent(final EntityItem entityItem, final ItemStack itemStack) { + final ParticleStack particleStack = getParticleStack(itemStack); + if ( particleStack == null + || particleStack.isEmpty() ) { + super.onEntityExpireEvent(entityItem, itemStack); + return; + } + particleStack.onWorldEffect(entityItem.worldObj, new Vector3(entityItem)); + } + @Override public void addInformation(ItemStack itemStack, EntityPlayer entityPlayer, List list, boolean advancedItemTooltips) { super.addInformation(itemStack, entityPlayer, list, advancedItemTooltips);