content: package tanks.bullet;
  
  import basewindow.Color;
  import tanks.*;
  import tanks.gui.screen.ScreenGame;
  import tanks.item.ItemBullet;
  import tanks.network.event.EventBulletDestroyed;
  import tanks.network.event.EventBulletInstantWaypoint;
  import tanks.tank.Tank;
  
  import java.util.ArrayList;
  import java.util.Random;
  
  public class BulletInstant extends Bullet
  {
  	public static String bullet_class_name = "laser";
  
  	public ArrayList<Double> xTargets = new ArrayList<>();
  	public ArrayList<Double> yTargets = new ArrayList<>();
  
  	public ArrayList<Laser> segments = new ArrayList<>();
  
  	public double lastX;
  	public double lastY;
  	public double lastZ;
  
  	public boolean expired = false;
  
  	public BulletInstant()
  	{
  		this.init();
  	}
  
  	public BulletInstant(double x, double y, Tank t, boolean affectsMaxLiveBullets, ItemBullet.ItemStackBullet ib)
  	{
  		super(x, y, t, affectsMaxLiveBullets, ib);
  		this.init();
  	}
  
  	public void init()
  	{
  		this.typeName = bullet_class_name;
  		this.enableExternalCollisions = false;
  		this.playPopSound = false;
  		this.playBounceSound = false;
  		this.effect.trailEffects.clear();
  		this.homingSilent = true;
  	}
  
  	public void saveTarget()
  	{
  		this.xTargets.add(this.collisionX);
  		this.yTargets.add(this.collisionY);
  	}
  
  	public void addDestroyEffect()
  	{
  		if (Game.effectsEnabled)
  		{
  			double mul = 4;
  			if (this.item.item.cooldownBase <= 0)
  				mul = 0.25;
  
  			for (int i = 0; i < mul * Game.effectMultiplier; i++)
  			{
  				Effect e = Effect.createNewEffect(this.posX, this.posY, this.posZ, Effect.EffectType.piece);
  				double var = 50;
  				e.maxAge /= 2;
  				e.setColorsFromBullet(this, this.baseColor);
  
  				if (Game.enable3d)
  					e.set3dPolarMotion(Math.random() * 2 * Math.PI, Math.random() * Math.PI, Math.random() * this.size / 50.0 * 4);
  				else
  					e.setPolarMotion(Math.random() * 2 * Math.PI, Math.random() * this.size / 50.0 * 4);
  
  				Game.effects.add(e);
  			}
  		}
  	}
  
  	public void shoot()
  	{
  		if (this.expired)
  			return;
  
  		if (!this.tank.isRemote)
  		{
  			this.collisionX = this.posX;
  			this.collisionY = this.posY;
  			this.lastX = this.posX;
  			this.lastY = this.posY;
  			this.lastZ = this.iPosZ;
  			this.saveTarget();
  		}
  
  		this.affectedByFrameFrequency = false;
  		double angle = this.getPolarDirection();
  		int redirects = 0;
  		while (!this.destroy)
  		{
  			if (ScreenGame.finished)
  				this.destroy = true;
  
  			if (this.homingSharpness != 0 && GameObject.absoluteAngleBetween(this.getPolarDirection(), angle) >= 0.1)
  			{
  				redirects++;
  				this.collisionX = this.posX;
  				this.collisionY = this.posY;
  				this.collided();
  
  				if (redirects > 100)
  					this.homingSharpness = this.homingSharpness * 0.95;
  
  				angle = this.getPolarDirection();
  			}
  
  			superUpdate();
  
  			if (Math.abs(this.lastFinalVX) < 0.01 && Math.abs(this.lastFinalVY) < 0.01)
  				this.destroy = true;
  		}
  
          this.affectedByFrameFrequency = true;
  
  		if (!this.tank.isRemote)
  		{
  			this.saveTarget();
  
  			for (int i = 0; i < this.xTargets.size(); i++)
  			{
  				Game.eventsOut.add(new EventBulletInstantWaypoint(this, this.xTargets.get(i), this.yTargets.get(i)));
  			}
  
  			Game.eventsOut.add(new EventBulletDestroyed(this));
  		}
  
  		freeIDs.add(this.networkID);
  		idMap.remove(this.networkID);
  
  		if (this.affectsMaxLiveBullets && this.reboundSuccessor == null && !this.failedRebound)
  			this.item.liveBullets--;
  
  		if (!this.isRemote)
  			this.onDestroy();
  
  		this.addDestroyEffect();
  		this.expired = true;
  	}
  
  	@Override
  	public void collided()
  	{
  		if (this.hitStun > 0)
  			this.addElectricEffect();
  
          Laser l = new Laser(this.lastX, this.lastY, this.lastZ, this.collisionX, this.collisionY, this.posZ, this.size / 2, this.getAngleInDirection(this.lastX, this.lastY), this.baseColor);
  
          if (this.effect.overrideGlowColor)
              l.glowColor = this.effect.glowColor;
  
          l.glowIntensity = this.effect.glowIntensity;
          l.glows = this.effect.glowIntensity > 0;
          l.glowSize = this.effect.glowSize;
          l.glowGlowy = this.effect.glowGlowy;
          l.luminance = this.effect.luminance;
  
          this.segments.add(l);
  		this.lastX = this.collisionX;
  		this.lastY = this.collisionY;
  		this.lastZ = this.posZ;
  
  		if (!this.isRemote)
  		{
  			this.xTargets.add(this.collisionX);
  			this.yTargets.add(this.collisionY);
  		}
  	}
  
  	public void addElectricEffect()
  	{
  		double dist = Math.sqrt(Math.pow(this.collisionX - this.lastX, 2) + Math.pow(this.collisionY - this.lastY, 2));
  
  		boolean glows = false;
  		double size = 0.25;
  
  		if (Game.bulletTrails)
  		{
  			for (int j = 0; j < 2; j++)
  			{
  				int segs = (int) Math.min(1000, (Math.random() * 0.4 + 0.8) * dist / 50);
  
  				double lX = this.lastX;
  				double lY = this.lastY;
  				double lZ = this.lastZ;
  
  				for (int i = 0; i < segs; i++)
  				{
  					double frac = (i + 1.0) / (segs + 1);
  					double nX = (1 - frac) * this.lastX + frac * this.collisionX + (Math.random() - 0.5) * 50;
  					double nY = (1 - frac) * this.lastY + frac * this.collisionY + (Math.random() - 0.5) * 50;
  					double nZ = (1 - frac) * this.lastZ + frac * this.posZ + (Math.random() - 0.5) * 30;
  					Laser l = new Laser(lX, lY, lZ, nX, nY, nZ, this.size * size, this.getAngleInDirection(this.lastX, this.lastY), this.outlineColor);
  					l.glows = glows;
  					this.segments.add(l);
  					lX = nX;
  					lY = nY;
  					lZ = nZ;
  				}
  				Laser l = new Laser(lX, lY, lZ, this.collisionX, this.collisionY, this.posZ, this.size * size, this.getAngleInDirection(this.lastX, this.lastY), this.outlineColor);
  				l.glows = glows;
  				this.segments.add(l);
  			}
  		}
  	}
  
  	@Override
  	public void collidedWithNothing()
  	{
  		if (this.damage < 0)
  		{
  			if (this.item.item.cooldownBase > 0)
  				Drawing.drawing.playGlobalSound("heal_impact_1.ogg");
  			else
  			{
  				float freq = (float) (this.frameDamageMultipler / 10);
  				if (Game.game.window.touchscreen)
  					freq = 1;
  				Drawing.drawing.playGlobalSound("heal1.ogg", 1, freq);
  			}
  		}
  	}
  
  	public void remoteShoot()
  	{
  		for (int i = 0; i < xTargets.size() - 1; i++)
  		{
  			double iX = xTargets.get(i);
  			double iY = yTargets.get(i);
  			double dX = xTargets.get(i + 1) - iX;
  			double dY = yTargets.get(i + 1) - iY;
  
  			this.posX = iX + dX;
  			this.posY = iY + dY;
  
  			double z = Game.tile_size / 4;
  			if (i == 0)
  				z = this.iPosZ;
  
  			this.segments.add(new Laser(iX, iY, z, iX + dX, iY + dY, Game.tile_size / 4, this.size / 2, this.getAngleInDirection(iX, iY), this.baseColor));
  			this.expired = true;
  
  			if (this.hitStun > 0)
  			{
  				this.lastX = iX;
  				this.lastY = iY;
  				this.lastZ = z;
  				this.collisionX = iX + dX;
  				this.collisionY = iY + dY;
  				this.posZ = Game.tile_size / 4;
  				this.addElectricEffect();
  			}
  		}
  
  		Game.movables.add(this);
  		this.addDestroyEffect();
  	}
  
  	@Override
  	public void update()
  	{
  		if (this.delay > 0)
  		{
  			this.delay -= Panel.frameFrequency;
  			return;
  		}
  
  		if (!this.expired)
  			this.shoot();
  
  		boolean finished = true;
  
  		for (Laser s: this.segments)
  		{
  			s.age += Panel.frameFrequency;
  
  			if (s.age > s.maxAge)
  				s.expired = true;
  
  			if (!s.expired)
  				finished = false;
  		}
  
  		if (finished)
  			Game.removeMovables.add(this);
  	}
  
  	@Override
  	public void draw()
  	{
  		for (Laser s: this.segments)
  		{
  			s.draw();
  		}
  	}
  
  	@Override
  	public boolean disableRayCollision()
  	{
  		return true;
  	}
  
  	public void superUpdate()
  	{
          preUpdate();
  		super.update();
          postUpdate();
  	}
  
  	public void addTrail(boolean redirect)
  	{
  
  	}
  
      public void drawForInterface(double x, double width, double y, double size, ArrayList<Effect> effects, Random r, Color base, Color turret)
      {
          double l = 800;
          double start = x - l / 2;
          base = this.baseColor;
  
          Drawing.drawing.setColor(base.red, base.green, base.blue, 255, this.effect.luminance);
          Drawing.drawing.fillInterfaceOval(start, y, size, size);
          Drawing.drawing.fillInterfaceOval(start + l, y, size, size);
          Drawing.drawing.fillInterfaceRect(start + l / 2, y, l, size);
  
          if (!this.effect.overrideGlowColor)
              Drawing.drawing.setColor(base.red, base.green, base.blue, 255* this.effect.glowIntensity, this.effect.glowGlowy ? 1 : 0);
          else
              Drawing.drawing.setColor(this.effect.glowColor.red, this.effect.glowColor.green, this.effect.glowColor.blue, 255 * this.effect.glowIntensity, this.effect.glowGlowy ? 1 : 0);
  
          double cr = Drawing.drawing.currentColorR;
          double cg = Drawing.drawing.currentColorG;
          double cb = Drawing.drawing.currentColorB;
          double ca = Drawing.drawing.currentColorA;
          double mul = this.effect.glowSize;
  
          size /= 2;
          Game.game.window.shapeRenderer.setBatchMode(true, false, false, this.effect.glowGlowy);
          for (int i = 10; i < 30; i++)
          {
              Drawing.drawing.setColor(cr, cg, cb, 0, this.effect.glowGlowy ? 1 : 0);
              Drawing.drawing.addInterfaceVertex(start + mul * Math.cos(i / 20.0 * Math.PI) * size, y + mul * Math.sin(i / 20.0 * Math.PI) * size, 0);
              Drawing.drawing.addInterfaceVertex(start + mul * Math.cos((i + 1) / 20.0 * Math.PI) * size, y + mul * Math.sin((i + 1) / 20.0 * Math.PI) * size, 0);
              Drawing.drawing.setColor(cr, cg, cb, ca, this.effect.glowGlowy ? 1 : 0);
              Drawing.drawing.addVertex(start, y, 0);
  
              Drawing.drawing.setColor(cr, cg, cb, 0, 1);
              Drawing.drawing.addInterfaceVertex(start + l + mul * Math.cos((i + 20) / 20.0 * Math.PI) * size, y + mul * Math.sin((i + 20) / 20.0 * Math.PI) * size, 0);
              Drawing.drawing.addInterfaceVertex(start + l + mul * Math.cos((i + 21) / 20.0 * Math.PI) * size, y + mul * Math.sin((i + 21) / 20.0 * Math.PI) * size, 0);
              Drawing.drawing.setColor(cr, cg, cb, ca, this.effect.glowGlowy ? 1 : 0);
              Drawing.drawing.addVertex(start + l, y, 0);
          }
          Game.game.window.shapeRenderer.setBatchMode(false, false, false, this.effect.glowGlowy);
  
          Game.game.window.shapeRenderer.setBatchMode(true, true, false, this.effect.glowGlowy);
  
          Drawing.drawing.setColor(cr, cg, cb, 0, this.effect.glowGlowy ? 1 : 0);
          Drawing.drawing.addInterfaceVertex(start, y + mul * size, 0);
          Drawing.drawing.addInterfaceVertex(start + l, y + mul * size, 0);
          Drawing.drawing.setColor(cr, cg, cb, ca, this.effect.glowGlowy ? 1 : 0);
          Drawing.drawing.addInterfaceVertex(start + l, y, 0);
          Drawing.drawing.addInterfaceVertex(start, y, 0);
  
          Drawing.drawing.addInterfaceVertex(start + l, y, 0);
          Drawing.drawing.addInterfaceVertex(start, y, 0);
          Drawing.drawing.setColor(cr, cg, cb, 0, this.effect.glowGlowy ? 1 : 0);
          Drawing.drawing.addInterfaceVertex(start, y - mul * size, 0);
          Drawing.drawing.addInterfaceVertex(start + l, y - mul * size, 0);
  
  
          Game.game.window.shapeRenderer.setBatchMode(false, true, false, this.effect.glowGlowy);
  
      }
  }
  