|  | @@ -1,22 +1,30 @@
 | 
	
		
			
				|  |  |  package me.km.effects;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import java.util.Collection;
 | 
	
		
			
				|  |  | +import java.util.HashMap;
 | 
	
		
			
				|  |  |  import java.util.stream.Collectors;
 | 
	
		
			
				|  |  |  import me.km.KajetansMod;
 | 
	
		
			
				|  |  |  import me.km.api.Module;
 | 
	
		
			
				|  |  |  import me.km.api.Utils;
 | 
	
		
			
				|  |  |  import me.km.jobsystem.JobAPI;
 | 
	
		
			
				|  |  | +import net.minecraft.entity.Entity;
 | 
	
		
			
				|  |  |  import net.minecraft.entity.EntityAreaEffectCloud;
 | 
	
		
			
				|  |  |  import net.minecraft.entity.EntityLivingBase;
 | 
	
		
			
				|  |  | +import net.minecraft.entity.item.EntityEnderPearl;
 | 
	
		
			
				|  |  | +import net.minecraft.entity.item.EntityExpBottle;
 | 
	
		
			
				|  |  |  import net.minecraft.entity.passive.EntityAnimal;
 | 
	
		
			
				|  |  |  import net.minecraft.entity.player.EntityPlayer;
 | 
	
		
			
				|  |  |  import net.minecraft.entity.player.EntityPlayerMP;
 | 
	
		
			
				|  |  | +import net.minecraft.entity.projectile.*;
 | 
	
		
			
				|  |  | +import net.minecraft.init.Items;
 | 
	
		
			
				|  |  |  import net.minecraft.init.SoundEvents;
 | 
	
		
			
				|  |  | +import net.minecraft.item.ItemStack;
 | 
	
		
			
				|  |  |  import net.minecraft.network.play.server.SPacketParticles;
 | 
	
		
			
				|  |  |  import net.minecraft.network.play.server.SPacketSoundEffect;
 | 
	
		
			
				|  |  |  import net.minecraft.potion.Potion;
 | 
	
		
			
				|  |  |  import net.minecraft.potion.PotionEffect;
 | 
	
		
			
				|  |  |  import net.minecraft.potion.PotionType;
 | 
	
		
			
				|  |  | +import net.minecraft.potion.PotionUtils;
 | 
	
		
			
				|  |  |  import net.minecraft.util.EnumParticleTypes;
 | 
	
		
			
				|  |  |  import net.minecraft.util.SoundCategory;
 | 
	
		
			
				|  |  |  import net.minecraft.util.SoundEvent;
 | 
	
	
		
			
				|  | @@ -28,11 +36,65 @@ import net.minecraft.world.WorldServer;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  public class EffectUtils extends Module
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +    private final HashMap<Integer, EntityData> entityData;
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  |      public EffectUtils(String mname, String prefix, TextFormatting color) 
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          super(mname, prefix, color);
 | 
	
		
			
				|  |  | +        entityData = new HashMap<>();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    // -----------------------------------------------------------------------------------
 | 
	
		
			
				|  |  | +    // Entity-Data
 | 
	
		
			
				|  |  | +    // -----------------------------------------------------------------------------------
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    private class EntityData
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        private final String s;
 | 
	
		
			
				|  |  | +        private final Object data;
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        public EntityData(String s, Object data)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            this.s = s;
 | 
	
		
			
				|  |  | +            this.data = data;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    public void addEntityData(Entity ent, String key, Object data)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        entityData.put(ent.getEntityId(), new EntityData(key, data));
 | 
	
		
			
				|  |  | +        removeInvalidData(ent);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    public void addEntityData(Entity ent, String key)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        addEntityData(ent, key, true);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    private void removeInvalidData(Entity ent)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if(ent.isDead)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            entityData.remove(ent.getEntityId());
 | 
	
		
			
				|  |  | +            return;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        KajetansMod.scheduler.scheduleTask(() -> removeInvalidData(ent), 100);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    public Object hasEntityData(Entity ent, String key)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        EntityData data = entityData.get(ent.getEntityId());
 | 
	
		
			
				|  |  | +        if(data == null)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return null;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return data.data;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | +    // -----------------------------------------------------------------------------------
 | 
	
		
			
				|  |  | +    // Entity-Level
 | 
	
		
			
				|  |  | +    // -----------------------------------------------------------------------------------
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  |      /** Returns the level of a players effect
 | 
	
		
			
				|  |  |       *
 | 
	
		
			
				|  |  |       * @param p a player
 | 
	
	
		
			
				|  | @@ -143,7 +205,7 @@ public class EffectUtils extends Module
 | 
	
		
			
				|  |  |          spawnParticle(p.getServerWorld(), EnumParticleTypes.SPELL, (float) p.posX, (float) p.posY + 1, (float) p.posZ, 0.5f, 0.5f, 0.5f, 1, 10 + level, new int[0]);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    public static <T> void playEffectCircleWithData(WorldServer w, Vec3d v, EnumParticleTypes particle, double radius, int counter)
 | 
	
		
			
				|  |  | +    public static <T> void playEffectCircleWithData(WorldServer w, Vec3d v, EnumParticleTypes particle, double radius, int counter, int... data)
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          double x = v.xCoord;
 | 
	
		
			
				|  |  |          float y = (float) v.yCoord;
 | 
	
	
		
			
				|  | @@ -151,10 +213,15 @@ public class EffectUtils extends Module
 | 
	
		
			
				|  |  |          double angle = 2 * Math.PI / counter;
 | 
	
		
			
				|  |  |          for(int i = 0; i < counter; i++)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            spawnParticle(w, particle, (float) (x + Math.cos(i * angle) * radius), y, (float) (z + Math.sin(i * angle) * radius), 1);
 | 
	
		
			
				|  |  | +            spawnParticle(w, particle, (float) (x + Math.cos(i * angle) * radius), y, (float) (z + Math.sin(i * angle) * radius), 0, 0, 0, 1, 1, data);
 | 
	
		
			
				|  |  |          }                
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | +    public static <T> void playEffectCircle(WorldServer w, Vec3d v, EnumParticleTypes particle, double radius, int counter)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        playEffectCircleWithData(w, v, particle, radius, counter, new int[0]);              
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  |      // -----------------------------------------------------------------------------------
 | 
	
		
			
				|  |  |      // Sounds
 | 
	
		
			
				|  |  |      // -----------------------------------------------------------------------------------
 | 
	
	
		
			
				|  | @@ -169,6 +236,11 @@ public class EffectUtils extends Module
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          playSound(p.getServerWorld(), se, sc, p.posX, p.posY, p.posZ);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    public static void playSound(EntityPlayerMP p, SoundEvent se)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        playSound(p.getServerWorld(), se, SoundCategory.PLAYERS, p.posX, p.posY, p.posZ);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      // -----------------------------------------------------------------------------------
 | 
	
		
			
				|  |  |      // Potions
 | 
	
	
		
			
				|  | @@ -183,22 +255,107 @@ public class EffectUtils extends Module
 | 
	
		
			
				|  |  |          ent.addPotionEffect(new PotionEffect(potion, duration, amplifier));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    public static void spawnPotionCloud(Vec3d v, EntityPlayerMP p, PotionType potion, int duration, float radius)
 | 
	
		
			
				|  |  | +    public static void spawnPotionCloud(Vec3d v, EntityPlayerMP p, Potion potion, int pduration, int amplifier, int duration, float radius)
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          EntityAreaEffectCloud cloud = new EntityAreaEffectCloud(p.getServerWorld(), v.xCoord, v.yCoord, v.zCoord);
 | 
	
		
			
				|  |  |          cloud.setDuration(duration);
 | 
	
		
			
				|  |  |          cloud.setRadius(radius);
 | 
	
		
			
				|  |  |          cloud.setOwner(p);
 | 
	
		
			
				|  |  |          cloud.setWaitTime(5);
 | 
	
		
			
				|  |  | -        cloud.setPotion(potion);
 | 
	
		
			
				|  |  | +        cloud.setPotion(new PotionType(new PotionEffect(potion, pduration, amplifier)));
 | 
	
		
			
				|  |  |          p.getServerWorld().spawnEntity(cloud);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    public static void spawnPotionCloud(Vec3d v, EntityPlayerMP p, PotionType potion, int level)
 | 
	
		
			
				|  |  | +    public static void spawnPotionCloud(EntityPlayerMP p, Potion potion, int level)
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          BlockPos pos = getPlayerTarget(p, level);
 | 
	
		
			
				|  |  | -        spawnPotionCloud(new Vec3d(pos.getX(), pos.getY(), pos.getZ()), p, potion, 40 * level, 0.5f + level / 4f);
 | 
	
		
			
				|  |  | +        spawnPotionCloud(new Vec3d(pos.getX(), pos.getY(), pos.getZ()), p, potion, 20 * level, (level / 4), 40 * level, 0.5f + level / 4f);
 | 
	
		
			
				|  |  |          playSpell(p, level);
 | 
	
		
			
				|  |  |          playSound(p, SoundEvents.ENTITY_FIREWORK_BLAST, SoundCategory.PLAYERS);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    // -----------------------------------------------------------------------------------
 | 
	
		
			
				|  |  | +    // Projectiles
 | 
	
		
			
				|  |  | +    // -----------------------------------------------------------------------------------
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    public static <T> T launchProjectile(EntityPlayer p, Class<? extends T> projectile, double scale, Object data) 
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        World w = p.world;
 | 
	
		
			
				|  |  | +        Entity launch = null;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if(EntitySnowball.class == projectile) 
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            launch = new EntitySnowball(w, p);
 | 
	
		
			
				|  |  | +            ((EntitySnowball) launch).setHeadingFromThrower(p, p.rotationPitch, p.rotationYaw, 0.0f, 1.5f, 1.0f);
 | 
	
		
			
				|  |  | +        } 
 | 
	
		
			
				|  |  | +        else if(EntityEgg.class == projectile)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            launch = new EntityEgg(w, p);
 | 
	
		
			
				|  |  | +            ((EntityEgg) launch).setHeadingFromThrower(p, p.rotationPitch, p.rotationYaw, 0.0f, 1.5f, 1.0f);
 | 
	
		
			
				|  |  | +        } 
 | 
	
		
			
				|  |  | +        else if(EntityEnderPearl.class == projectile) 
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            launch = new EntityEnderPearl(w, p);
 | 
	
		
			
				|  |  | +            ((EntityEnderPearl) launch).setHeadingFromThrower(p, p.rotationPitch, p.rotationYaw, 0.0f, 1.5f, 1.0f);
 | 
	
		
			
				|  |  | +        } 
 | 
	
		
			
				|  |  | +        else if(EntityPotion.class == projectile) 
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            launch = new EntityPotion(w, p, (ItemStack) data);
 | 
	
		
			
				|  |  | +            ((EntityPotion) launch).setHeadingFromThrower(p, p.rotationPitch, p.rotationYaw, -20.0f, 0.5f, 1.0f);
 | 
	
		
			
				|  |  | +        } 
 | 
	
		
			
				|  |  | +        else if(EntityExpBottle.class == projectile) 
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            launch = new EntityExpBottle(w, p);
 | 
	
		
			
				|  |  | +            ((EntityExpBottle) launch).setHeadingFromThrower(p, p.rotationPitch, p.rotationYaw, -20.0f, 0.7f, 1.0f);
 | 
	
		
			
				|  |  | +        } 
 | 
	
		
			
				|  |  | +        else if(EntityArrow.class.isAssignableFrom(projectile)) 
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if(EntityTippedArrow.class == projectile) 
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                launch = new EntityTippedArrow(w, p);
 | 
	
		
			
				|  |  | +                ((EntityTippedArrow) launch).setPotionEffect((ItemStack) data);
 | 
	
		
			
				|  |  | +            } 
 | 
	
		
			
				|  |  | +            else if(EntitySpectralArrow.class == projectile) 
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                launch = new EntitySpectralArrow(w, p);
 | 
	
		
			
				|  |  | +            } 
 | 
	
		
			
				|  |  | +            else 
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                launch = new EntityTippedArrow(w, p);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            ((EntityArrow) launch).setAim(p, p.rotationPitch, p.rotationYaw, 0.0F, 3.0F, 1.0F);
 | 
	
		
			
				|  |  | +        } 
 | 
	
		
			
				|  |  | +        else if(EntityFireball.class.isAssignableFrom(projectile)) 
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            Vec3d v = p.getLookVec().scale(10);
 | 
	
		
			
				|  |  | +            if (EntitySmallFireball.class == projectile) 
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                launch = new EntitySmallFireball(w, p, v.xCoord, v.yCoord, v.zCoord);
 | 
	
		
			
				|  |  | +            } 
 | 
	
		
			
				|  |  | +            else if (EntityWitherSkull.class == projectile) 
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                launch = new EntityWitherSkull(w, p, v.xCoord, v.yCoord, v.zCoord);
 | 
	
		
			
				|  |  | +            } 
 | 
	
		
			
				|  |  | +            else if (EntityDragonFireball.class == projectile) 
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                launch = new EntityDragonFireball(w, p, v.xCoord, v.yCoord, v.zCoord);
 | 
	
		
			
				|  |  | +            } 
 | 
	
		
			
				|  |  | +            else 
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                launch = new EntityLargeFireball(w, p, v.xCoord, v.yCoord, v.zCoord);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        } 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        Utils.scaleVelocity(launch, scale);
 | 
	
		
			
				|  |  | +        w.spawnEntity(launch);
 | 
	
		
			
				|  |  | +        return (T) launch;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    public static EntityTippedArrow launchTippedArrow(EntityPlayer p, double scale, Potion potion, int duration, int amplifier) 
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        ItemStack stack = new ItemStack(Items.TIPPED_ARROW);
 | 
	
		
			
				|  |  | +        PotionUtils.addPotionToItemStack(stack, new PotionType(new PotionEffect(potion, duration, amplifier)));
 | 
	
		
			
				|  |  | +        EntityTippedArrow arrow = launchProjectile(p, EntityTippedArrow.class, scale, stack);
 | 
	
		
			
				|  |  | +        return arrow;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  }
 |