From bdc40dfd7ef8da4965f6cb11202d056867b64beb Mon Sep 17 00:00:00 2001
From: David Lin <dllin@student.unimelb.edu.au>
Date: Sat, 13 Jun 2020 15:37:48 +1000
Subject: [PATCH] levels implemented

---
 src/{lists => }/Airplane.java      |  22 +-
 src/{lists => }/ApexSlicer.java    |  10 +-
 src/{lists => }/Explosive.java     |  14 +-
 src/{lists => }/MegaSlicer.java    |  10 +-
 src/{lists => }/Projectile.java    |  10 +-
 src/{lists => }/RegularSlicer.java |   9 +-
 src/ShadowDefend.java              | 750 +++++++++++++++++++++++++++++
 src/{lists => }/Slicer.java        |  35 +-
 src/{lists => }/Sprite.java        |   2 -
 src/{lists => }/SuperSlicer.java   |   9 +-
 src/{lists => }/SuperTank.java     |   4 +-
 src/{lists => }/Tank.java          |  30 +-
 src/lists/ShadowDefend.java        | 557 ---------------------
 13 files changed, 845 insertions(+), 617 deletions(-)
 rename src/{lists => }/Airplane.java (88%)
 rename src/{lists => }/ApexSlicer.java (77%)
 rename src/{lists => }/Explosive.java (82%)
 rename src/{lists => }/MegaSlicer.java (77%)
 rename src/{lists => }/Projectile.java (93%)
 rename src/{lists => }/RegularSlicer.java (77%)
 create mode 100644 src/ShadowDefend.java
 rename src/{lists => }/Slicer.java (79%)
 rename src/{lists => }/Sprite.java (98%)
 rename src/{lists => }/SuperSlicer.java (77%)
 rename src/{lists => }/SuperTank.java (88%)
 rename src/{lists => }/Tank.java (67%)
 delete mode 100644 src/lists/ShadowDefend.java

diff --git a/src/lists/Airplane.java b/src/Airplane.java
similarity index 88%
rename from src/lists/Airplane.java
rename to src/Airplane.java
index 3bee4ac..f1c6785 100644
--- a/src/lists/Airplane.java
+++ b/src/Airplane.java
@@ -1,5 +1,3 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
 import bagel.util.Vector2;
@@ -18,10 +16,12 @@ public class Airplane extends Sprite{
 
 
     private double speed;
+    private int damage;
     private boolean finished, isVertical;
     private double frameCount;
     private Random r = new Random();
     private double nothingTime;
+    private Point explode;
 
 
 
@@ -30,16 +30,25 @@ public class Airplane extends Sprite{
     public Airplane(Point point, boolean isVertical, String imageSrc){
         super(point,imageSrc);
         this.speed = 1.5;
+        this.damage = 500;
         this.finished = false;
         this.isVertical = isVertical;
         this.frameCount = Integer.MAX_VALUE;
         this.nothingTime = Math.round((TIME_MIN + (TIME_MAX - TIME_MIN) * r.nextDouble())*1000);
         this.explosives = new ArrayList<>();
+        this.explode = null;
 
     }
+    public Point getExplode(){
+        return this.explode;
+    }
+    public int getDamage(){
+        return this.damage;
 
+    }
     @Override
     public void update(Input input) {
+        explode = null;
         frameCount += ShadowDefend.getTimescale();
         if (finished) {
             return;
@@ -68,21 +77,26 @@ public class Airplane extends Sprite{
 
         // Check if we have reached the end
         if ((currentPoint.x >= WIDTH || currentPoint.y >= HEIGHT) && explosives.isEmpty()) {
-            System.out.println("out");
+            //System.out.println("out");
             finished = true;
             return;
         }
         for (int i = explosives.size() - 1; i >= 0; i--) {
             if(!explosives.isEmpty()){
-                System.out.println(explosives);
+                //System.out.println(explosives);
                 Explosive v = explosives.get(i);
                 v.update(input);
+
                 if (v.isFinished()) {
+
+                    explode = v.getPoint();
+
                     explosives.remove(i);
                 }
             }
 
         }
+
         // Move towards the target point
         // We do this by getting a unit vector in the direction of our target, and multiplying it
         // by the speed of the slicer (accounting for the timescale)
diff --git a/src/lists/ApexSlicer.java b/src/ApexSlicer.java
similarity index 77%
rename from src/lists/ApexSlicer.java
rename to src/ApexSlicer.java
index 3d29462..6172da7 100644
--- a/src/lists/ApexSlicer.java
+++ b/src/ApexSlicer.java
@@ -1,8 +1,6 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
-import bagel.util.Vector2;
+
 import java.util.List;
 
 /**
@@ -17,14 +15,14 @@ public class ApexSlicer extends Slicer {
      *
      * @param polyline The polyline that the slicer must traverse (must have at least 1 point)
      */
-    public ApexSlicer(List<Point> polyline,String imageSrc) {
-        super(polyline, imageSrc);
+    public ApexSlicer(List<Point> polyline,int targetPointIndex, Point point,String imageSrc) {
+        super(polyline, targetPointIndex, point, imageSrc);
 
         this.speed = 0.375;
         this.health = 25;
         this.reward = 150;
         this.penalty = 16;
-
+        this.spawnOnDeath = 4;
     }
 
     /**
diff --git a/src/lists/Explosive.java b/src/Explosive.java
similarity index 82%
rename from src/lists/Explosive.java
rename to src/Explosive.java
index 837b173..b70e162 100644
--- a/src/lists/Explosive.java
+++ b/src/Explosive.java
@@ -1,15 +1,12 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
 
-import java.util.Random;
-
 public class Explosive extends Sprite{
     private static final double COOLDOWN = 2000;
-    private double radius,damage,frameCount;
+    private double radius,frameCount;
     private boolean finished;
 
+    private Point point;
 
 
 
@@ -18,13 +15,16 @@ public class Explosive extends Sprite{
     public Explosive(Point point, String imageSrc){
         super(point,imageSrc);
         this.radius = 200;
-        this.damage = 500;
+
+        this.point = point;
 
         this.finished = false;
         this.frameCount = 0;
 
     }
-
+    public Point getPoint(){
+        return this.point;
+    }
     @Override
     public void update(Input input) {
         frameCount += ShadowDefend.getTimescale();
diff --git a/src/lists/MegaSlicer.java b/src/MegaSlicer.java
similarity index 77%
rename from src/lists/MegaSlicer.java
rename to src/MegaSlicer.java
index d356f07..f992cdc 100644
--- a/src/lists/MegaSlicer.java
+++ b/src/MegaSlicer.java
@@ -1,8 +1,6 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
-import bagel.util.Vector2;
+
 import java.util.List;
 
 /**
@@ -17,14 +15,14 @@ public class MegaSlicer extends Slicer {
      *
      * @param polyline The polyline that the slicer must traverse (must have at least 1 point)
      */
-    public MegaSlicer(List<Point> polyline,String imageSrc) {
-        super(polyline, imageSrc);
+    public MegaSlicer(List<Point> polyline, int targetPointIndex, Point point,String imageSrc) {
+        super(polyline, targetPointIndex, point,imageSrc);
 
         this.speed = 0.75;
         this.health = 2;
         this.reward = 10;
         this.penalty = 4;
-
+        this.spawnOnDeath = 2;
     }
 
     /**
diff --git a/src/lists/Projectile.java b/src/Projectile.java
similarity index 93%
rename from src/lists/Projectile.java
rename to src/Projectile.java
index 408e650..4a38e94 100644
--- a/src/lists/Projectile.java
+++ b/src/Projectile.java
@@ -1,5 +1,3 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
 import bagel.util.Vector2;
@@ -18,9 +16,15 @@ public class Projectile extends Sprite {
         this.speed = 5;
         this.damage = damage;
         this.slicerIndex = slicerIndex;
+    }
+    public int getSlicerIndex(){
+        return this.slicerIndex;
+    }
 
-
+    public int getDamage() {
+        return this.damage;
     }
+
     @Override
     public void update(Input input) {
         if (finished) {
diff --git a/src/lists/RegularSlicer.java b/src/RegularSlicer.java
similarity index 77%
rename from src/lists/RegularSlicer.java
rename to src/RegularSlicer.java
index 11a1e09..ca63d6b 100644
--- a/src/lists/RegularSlicer.java
+++ b/src/RegularSlicer.java
@@ -1,8 +1,6 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
-import bagel.util.Vector2;
+
 import java.util.List;
 
 /**
@@ -15,13 +13,14 @@ public class RegularSlicer extends Slicer {
      *
      * @param polyline The polyline that the slicer must traverse (must have at least 1 point)
      */
-    public RegularSlicer(List<Point> polyline,String imageSrc) {
-        super(polyline, imageSrc);
+    public RegularSlicer(List<Point> polyline, int targetPointIndex, Point point, String imageSrc) {
+        super(polyline, targetPointIndex, point, imageSrc);
 
         this.speed = 1;
         this.health = 1;
         this.reward = 2;
         this.penalty = 1;
+        this.spawnOnDeath = 0;
 
     }
 
diff --git a/src/ShadowDefend.java b/src/ShadowDefend.java
new file mode 100644
index 0000000..7f9742f
--- /dev/null
+++ b/src/ShadowDefend.java
@@ -0,0 +1,750 @@
+import bagel.*;
+import bagel.Font;
+import bagel.Image;
+
+import bagel.map.TiledMap;
+import bagel.util.Colour;
+import bagel.util.Point;
+import bagel.util.Rectangle;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+
+
+/**
+ * ShadowDefend, a tower defence game.
+ * Used Rohyl's template from Project 1
+ */
+public class ShadowDefend extends AbstractGame {
+    private static final String RSLICER = "res/images/slicer.png";
+    private static final String SSLICER = "res/images/superslicer.png";
+    private static final String MSLICER = "res/images/megaslicer.png";
+    private static final String ASLICER = "res/images/apexslicer.png";
+    private static final int HEIGHT = 768;
+    private static final int WIDTH = 1024;
+    private static final int HALF_WIDTH = WIDTH/2;
+    private static final int QUAR_WIDTH = WIDTH/4;
+    private static final int EXP_RADIUS = 200;
+
+    private static final String SHOP_FILE = "res/images/buypanel.png";
+    private static final String STATUS_FILE = "res/images/statuspanel.png";
+    private static final String TANK_FILE = "res/images/tank.png";
+    private static final String TANK_PROJ_FILE = "res/images/tank_projectile.png";
+    private static final String STANK_PROJ_FILE = "res/images/supertank_projectile.png";
+    private static final String STANK_FILE = "res/images/supertank.png";
+    private static final String PLANE_FILE = "res/images/airsupport.png";
+    private static final String FONT_FILE = "res/fonts/DejaVuSans-Bold.ttf";
+    private static final String INFO = "Key binds:\n\nS - Start Wave\nL - Increase Timescale\nK - Decrease Timescale";
+    private static final String WAVES_FILE = "res/levels/waves.txt";
+    private DrawOptions colour = new DrawOptions();
+    // Change to suit system specifications. This could be
+    // dynamically determined but that is out of scope.
+    public static final double FPS = 60;
+    // The spawn delay (in seconds) to spawn slicers
+
+    private static final int INTIAL_TIMESCALE = 1;
+
+    // Timescale is made static because it is a universal property of the game and the specification
+    // says everything in the game is affected by this
+    private static int timescale = INTIAL_TIMESCALE;
+
+    private final Image shop, statusPanel, tankIcon, stankIcon, planeIcon;
+
+    private final List<Slicer> slicers;
+    private final List<Projectile> projectiles;
+
+
+    private final List<Tank> tanks;
+
+    private final List<Airplane> planes;
+
+    private final Rectangle window;
+    private String map_file = "res/levels/1.tmx";
+    private TiledMap map;
+    private List<String> event;
+    private List<Point> polyline;
+
+    private List<List<String>> events;
+    private Font goldDisplay, keyInstruction, costText, statusText;
+    private Image placingIcon;
+    private double frameCount;
+    private double projCount;
+    private int spawnedSlicers;
+    private int nothingTime;
+    private int spawnDelay;
+    private int spawnCount;
+    private int eventType;
+    private int level;
+    private int waveCounter;
+    private int eventCounter;
+    private int prevWaveState;
+    private int slicerIndex;
+    private boolean eventWait;
+    private String enemyType;
+    private String placedImage;
+    private boolean tankBlocked;
+    private boolean mapSet;
+    private boolean waveStarted;
+    private boolean eventStarted = true;
+    private boolean isVertical = false;
+    private boolean hasTarget = false;
+    private static int gold, lives, waveNumber, waveState;
+
+
+    /**
+     * Creates a new instance of the ShadowDefend game
+     */
+    public ShadowDefend() {
+
+        super(WIDTH, HEIGHT, "ShadowDefend");
+
+        gold = 50000;
+        lives = 25;
+        waveNumber = 1;
+        waveState = 0;
+        this.window = new Rectangle(0,0,WIDTH,HEIGHT);
+        this.map = new TiledMap(map_file);
+        this.shop = new Image(SHOP_FILE);
+        this.statusPanel = new Image(STATUS_FILE);
+        this.tankIcon = new Image(TANK_FILE);
+        this.stankIcon = new Image(STANK_FILE);
+        this.planeIcon = new Image(PLANE_FILE);
+        this.goldDisplay = new Font(FONT_FILE,50);
+        this.keyInstruction = new Font(FONT_FILE,16);
+        this.costText = new Font(FONT_FILE,20);
+        this.statusText = new Font(FONT_FILE,16);
+        this.polyline = map.getAllPolylines().get(0);
+        this.slicers = new ArrayList<>();
+        this.projectiles = new ArrayList<>();
+
+        this.tanks = new ArrayList<>();
+
+        this.planes = new ArrayList<>();
+
+        this.events = new ArrayList<>();
+        this.event = new ArrayList<>();
+        this.level = 1;
+        this.spawnedSlicers = 0;
+        this.waveStarted = false;
+        this.frameCount = Integer.MAX_VALUE;
+        this.projCount = Integer.MAX_VALUE;
+        this.waveCounter = 1;
+        this.eventCounter = 0;
+        this.eventWait = false;
+        this.mapSet = false;
+        this.tankBlocked = false;
+
+        try {
+            File wavesText = new File(WAVES_FILE);
+            Scanner fr = new Scanner(wavesText);
+            while (fr.hasNextLine()) {
+                events.add(Arrays.asList(fr.nextLine().split(",")));
+            }
+            fr.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+
+
+
+        // Temporary fix for the weird slicer map glitch (might have to do with caching textures)
+        // This fix is entirely optional
+        //new Slicer(polyline);
+    }
+
+    /**
+     * The entry-point for the game
+     *
+     * @param args Optional command-line arguments
+     */
+    public static void main(String[] args) {
+        new ShadowDefend().run();
+    }
+
+    public static int getTimescale() {
+        return timescale;
+    }
+
+    /**
+     * Increases the timescale
+     */
+    private void increaseTimescale() {
+        if(timescale!=5){
+            timescale++;
+        }
+
+    }
+
+    /**
+     * Decreases the timescale but doesn't go below the base timescale
+     */
+    private void decreaseTimescale() {
+        if (timescale > INTIAL_TIMESCALE) {
+            timescale--;
+        }
+    }
+    /**
+     * Resets the game for new level but maintaining gold
+     */
+    private void resetLevel(){
+        map = new TiledMap(map_file);
+        mapSet = false;
+        level += 1;
+        slicers.clear();
+        tanks.clear();
+        planes.clear();
+        projectiles.clear();
+        polyline = map.getAllPolylines().get(0);
+        eventCounter = 0;
+        waveCounter = 1;
+        waveState = 0;
+        waveStarted = false;
+    }
+
+    /**
+     * Draws the shop panel
+     */
+    private void drawShopPanel(){
+        //Draw shop panel at top left
+        shop.drawFromTopLeft(0,0);
+
+        // Draw icons
+        tankIcon.draw(64,(shop.getHeight()/2)-10);
+        stankIcon.draw(184,(shop.getHeight()/2)-10);
+        planeIcon.draw(304,(shop.getHeight()/2)-10);
+
+        // Draw information
+        keyInstruction.drawString(INFO,(shop.getWidth()/2)-keyInstruction.getWidth(INFO)/2,20);
+
+        // Draw gold amount
+        if(gold >= 1000){
+            // Add comma if gold count over 4 digits, can use for loop for more than 7 digits
+            // not realistic to have over a million gold in this game
+            String extra = Integer.toString(gold).substring(Integer.toString(gold).length() -3);
+            String thousandth = Integer.toString(gold).substring(0,Integer.toString(gold).length() -3);
+            goldDisplay.drawString("$"+ thousandth + "," + extra,shop.getWidth()-200,65);
+
+        } else {
+            goldDisplay.drawString("$"+ gold,shop.getWidth()-200,65);
+        }
+
+        // Draw the cost text for Tank with colouring
+        // RED: gold not enough
+        if(gold < 250){
+            costText.drawString("$"+250,64-(tankIcon.getWidth()/2),
+                    (tankIcon.getHeight()/2)+(shop.getHeight()/2+5),
+                    colour.setBlendColour(Colour.RED));
+
+        } else {
+            costText.drawString("$"+250,64-(tankIcon.getWidth()/2),
+                    (tankIcon.getHeight()/2)+(shop.getHeight()/2+5),
+                    colour.setBlendColour(Colour.GREEN));
+        }
+
+        // Draw the cost text for SuperTank with colouring
+        // RED: gold not enough
+        if(gold < 600){
+            costText.drawString("$"+600,184-(stankIcon.getWidth()/2),
+                    (stankIcon.getHeight()/2)+(shop.getHeight()/2+5),
+                    colour.setBlendColour(Colour.RED));
+
+        } else {
+            costText.drawString("$"+600,184-(stankIcon.getWidth()/2),
+                    (stankIcon.getHeight()/2)+(shop.getHeight()/2+5),
+                    colour.setBlendColour(Colour.GREEN));
+
+        }
+
+        // Draw the cost text for Plane with colouring
+        // RED: gold not enough
+        if(gold < 500){
+            costText.drawString("$"+500,304-(planeIcon.getWidth()/2),
+                    (planeIcon.getHeight()/2)+(shop.getHeight()/2+5),
+                    colour.setBlendColour(Colour.RED));
+
+        } else {
+            costText.drawString("$"+500,304-(planeIcon.getWidth()/2),
+                    (planeIcon.getHeight()/2)+(shop.getHeight()/2+5),
+                    colour.setBlendColour(Colour.GREEN));
+
+        }
+    }
+
+    /**
+     * Draws the status panel
+     */
+    private void drawStatusPanel(){
+        //Draw status panel at bottom
+        statusPanel.drawFromTopLeft(0,HEIGHT - statusPanel.getHeight());
+
+        // Draw wave number on left side
+        statusText.drawString("Wave: " + waveNumber,5,HEIGHT-6);
+
+        // Draw timescale with colouring
+        // GREEN: over 1x timescale
+        if(timescale>1){
+            statusText.drawString("Timescale: " + timescale + ".0",
+                    QUAR_WIDTH,
+                    HEIGHT-6,
+                    colour.setBlendColour(Colour.GREEN));
+
+        } else {
+            statusText.drawString("Timescale: " + timescale + ".0",QUAR_WIDTH,HEIGHT-6);
+        }
+
+        // Draw wave state in middle of panel
+        switch(waveState) {
+            case 0:
+                statusText.drawString("Status: Awaiting Start",
+                        HALF_WIDTH,
+                        HEIGHT-6);
+                break;
+            case 1:
+                statusText.drawString("Status: Wave In Progress",
+                        HALF_WIDTH,
+                        HEIGHT-6);
+                break;
+            case 2:
+                statusText.drawString("Status: Placing",
+                        HALF_WIDTH,
+                        HEIGHT-6);
+                break;
+            case 3:
+                statusText.drawString("Status: Winner!",
+                        HALF_WIDTH,
+                        HEIGHT-6);
+                break;
+        }
+
+        // Draw number of remaining lives on right side
+        statusText.drawString("Lives: " + lives,
+                WIDTH-statusText.getWidth("Lives: " + lives)-5,
+                HEIGHT-6);
+
+    }
+    /**
+     * Get whether mouse pointer is hovering over an already placed tank
+     *
+     * @param input The current mouse/keyboard state
+     */
+    private void getTankBlocked(Input input){
+        tankBlocked = false;
+        // Loop through tanks
+        for (int j = tanks.size() - 1; j >= 0; j--) {
+            if (!tanks.isEmpty()) {
+                Tank v = tanks.get(j);
+                // Checks the mouse pointer does not intersect with a tank
+                if(v.getRect().intersects(input.getMousePosition())){
+                    tankBlocked = true;
+                }
+            }
+        }
+    }
+    /**
+     * Breakdown an event into usable data
+     */
+    private void getEventData(){
+        if(event.size() == 3){
+            // Delay event
+            eventType = 0;
+            waveNumber = Integer.parseInt(event.get(0));
+            nothingTime = Integer.parseInt(event.get(2));
+        } else {
+            // Spawn event
+            eventType = 1;
+            waveNumber = Integer.parseInt(event.get(0));
+            spawnCount = Integer.parseInt(event.get(2));
+            enemyType = event.get(3);
+            spawnDelay = Integer.parseInt(event.get(4));
+        }
+
+    }
+
+
+
+
+    /**
+     * Update the state of the game, potentially reading from input
+     *
+     * @param input The current mouse/keyboard state
+     */
+    @Override
+    protected void update(Input input) {
+        // Increase the frame counter by the current timescale
+        frameCount += getTimescale();
+        projCount += getTimescale();
+
+        // Draw map from the top left of the window
+        map.draw(0, 0, 0, 0, WIDTH, HEIGHT);
+
+
+        //----------------------- Handle key presses ------------------------------------------------------------
+        //                                      MOUSE KEY PRESSES
+        //_______________________________________________________________________________________________________
+        // User has left clicked
+        if(input.wasPressed(MouseButtons.LEFT)){
+            // Checks if mouse above the tank icon when left clicked and if enough gold
+            if(tankIcon.getBoundingBoxAt(new Point(64,(shop.getHeight()/2)-10)).intersects(input.getMousePosition())
+                    && gold >= 250){
+                // Create image of tank and set wave state to Placing
+                placingIcon = new Image(TANK_FILE);
+                placedImage = "tank";
+                prevWaveState = waveState;
+                waveState = 2;
+            }
+
+            // Checks if mouse above the super tank icon when left clicked and if enough gold
+            if(stankIcon.getBoundingBoxAt(new Point(184,(shop.getHeight()/2)-10)).intersects(input.getMousePosition())
+                    && gold >= 600){
+                // Create image of super tank and set wave state to Placing
+                placingIcon = new Image(STANK_FILE);
+                placedImage = "stank";
+                prevWaveState = waveState;
+                waveState = 2;
+            }
+
+            // Checks if mouse above the plane icon when left clicked and if enough gold
+            if(planeIcon.getBoundingBoxAt(new Point(304,(shop.getHeight()/2)-10)).intersects(input.getMousePosition())
+                    && gold >= 500){
+                // Create image of plane and set wave state to Placing
+                placingIcon = new Image(PLANE_FILE);
+                placedImage = "plane";
+                prevWaveState = waveState;
+                waveState = 2;
+            }
+        }
+
+        // User has selected an icon
+        if(input.isUp(MouseButtons.LEFT) && placingIcon != null){
+            // Check pointer still within window
+            if(window.intersects(input.getMousePosition())){
+                // Get whether pointer hovering over already placed tanks
+                getTankBlocked(input);
+                // Filter blocked areas
+                if(!map.hasProperty((int)Math.round(input.getMouseX()),(int)Math.round(input.getMouseY()),"blocked")
+                        && !shop.getBoundingBox().intersects(input.getMousePosition())
+                        && !statusPanel.getBoundingBoxAt(new Point(HALF_WIDTH,HEIGHT - statusPanel.getHeight()/2)).intersects(input.getMousePosition())
+                        && !tankBlocked){
+                    // Draw icon
+                    placingIcon.draw(input.getMouseX(),input.getMouseY());
+                }
+            }
+
+        }
+
+        // User has placed tower by left clicking again, filter blocked areas
+        if(input.wasPressed(MouseButtons.LEFT) && placingIcon != null
+                && !map.hasProperty((int)Math.round(input.getMouseX()),(int)Math.round(input.getMouseY()),"blocked")
+                && !shop.getBoundingBox().intersects(input.getMousePosition())
+                && !statusPanel.getBoundingBoxAt(new Point(HALF_WIDTH,HEIGHT - statusPanel.getHeight()/2)).intersects(input.getMousePosition())
+                && !tankBlocked){
+            // Add tank tower if tank and update gold
+            if(placedImage.equals("tank")){
+                tanks.add(new Tank(input.getMousePosition(),TANK_FILE));
+                gold-=250;
+            }
+            // Add super tank tower if super tank and update gold
+            if(placedImage.equals("stank")) {
+                tanks.add(new SuperTank(input.getMousePosition(), STANK_FILE));
+                gold-=600;
+            }
+            // Add plane if plane and update gold
+            if(placedImage.equals("plane")) {
+                // Create new plane object with direction given
+                if (isVertical) {
+                    planes.add(new Airplane(new Point(input.getMouseX(), 0), isVertical, PLANE_FILE));
+                    isVertical = false;
+                } else {
+                    planes.add(new Airplane(new Point(0, input.getMouseY()), isVertical, PLANE_FILE));
+                    isVertical = true;
+                }
+
+                gold -= 500;
+
+            }
+            // Reset wave state and placing image to previous wave state and null after placing is complete
+            waveState = prevWaveState;
+            placingIcon = null;
+        }
+        //                                      KEYBOARD KEY PRESSES
+        //_______________________________________________________________________________________________________
+        // User has pressed S
+        if (input.wasPressed(Keys.S)) {
+            // Start a wave if wave state is not Wave in progress
+            if(waveState != 1){
+                waveStarted = true;
+                // Set wave state to Wave in progress
+                if(waveState<=1){
+                    waveState = 1;
+                }
+
+            }
+
+        }
+
+        // User has pressed L
+        if (input.wasPressed(Keys.L)) {
+            increaseTimescale();
+        }
+
+        // User has pressed K
+        if (input.wasPressed(Keys.K)) {
+            decreaseTimescale();
+        }
+
+        // MAIN UPDATE ----------------------------------------------------------------------
+        // Checks if user has lives and not beaten the levels yet
+        if(waveState!=3 && lives>0){
+            // Checks if a wave has started and is in progress
+            if(waveStarted){
+                // Run through each event
+                if(eventCounter<events.size()){
+                    event = events.get(eventCounter);
+                    // Checks if event is part of a new wave and if event has completed
+                    if(waveCounter == Integer.parseInt(event.get(0)) && !eventWait){
+                        getEventData();
+                        eventStarted = true;
+                        eventCounter++;
+                    // Since it is a new wave, increment wave counter and wait for user to begin next wave
+                    } else if(waveCounter != Integer.parseInt(event.get(0)) && !eventWait){
+                        waveCounter++;
+                        waveStarted = false;
+                    }
+                // Events have reached the last event
+                } else {
+                    // Checks no slicers on map
+                    if(slicers.isEmpty()){
+                        // Set incremented level as new map, if not already set
+                        if(!mapSet){
+                            mapSet = true;
+                            map_file = map_file.split(String.valueOf(level))[0]+(level+1)
+                                    +map_file.split(String.valueOf(level))[1];
+                        }
+                        // If level does not exist, user has beaten all available levels
+                        if(!(new File(map_file).exists())){
+                            // Wave state set to Winner!
+                            waveState = 3;
+                        // Set up new level and reset
+                        } else {
+                            resetLevel();
+                        }
+
+                    }
+
+
+
+                }
+            // Wave has just finished so set to Awaiting and update gold
+            } else {
+                if(waveState == 1 && slicers.isEmpty()){
+                    gold += waveNumber*100+150;
+                    waveState = 0;
+                }
+            }
+
+            // Run an event
+            if(eventStarted){
+                // Event is a spawn event
+                if (eventType == 1) {
+                    // Event not yet complete
+                    eventWait = true;
+
+                    // Spawn slicers with specified spawn count and delay
+                    if (frameCount*1000 / FPS >= spawnDelay && spawnedSlicers != spawnCount) {
+                        switch(enemyType) {
+                            case "slicer":
+                                slicers.add(new RegularSlicer(polyline,1,polyline.get(0),RSLICER));
+                                break;
+                            case "superslicer":
+                                slicers.add(new SuperSlicer(polyline,1,polyline.get(0),SSLICER));
+                                break;
+                            case "megaslicer":
+                                slicers.add(new MegaSlicer(polyline,1,polyline.get(0),MSLICER));
+                                break;
+                            case "apexslicer":
+                                slicers.add(new ApexSlicer(polyline,1,polyline.get(0),ASLICER));
+                                break;
+                        }
+                        // Increment spawned slicer count
+                        spawnedSlicers += 1;
+                        // Reset frame counter
+                        frameCount = 0;
+
+                    // Event has spawned specified amount
+                    } else if (spawnedSlicers == spawnCount) {
+                        // Reset wait, started and spawned slicer count for next event
+                        eventWait = false;
+                        eventStarted = false;
+                        spawnedSlicers = 0;
+
+                    }
+                // Event is a delay event
+                } else if (eventType == 0) {
+                    eventWait = true;
+                    // Wait out specified delay
+                    if (frameCount*1000 / FPS >= nothingTime) {
+                        // Reset wait, started and frame count for next event
+                        eventWait = false;
+                        eventStarted = false;
+                        // Reset frame counter
+                        frameCount = 0;
+                    }
+                }
+
+            }
+        }
+
+
+
+
+
+
+        // Update all sprites, and remove them if they've finished
+
+        // Update all tanks
+        for (int j = tanks.size() - 1; j >= 0; j--) {
+            if (!tanks.isEmpty()) {
+                // Select a tank object
+                Tank v = tanks.get(j);
+                // Set tank target to null
+                v.setTarget(null);
+                // Find closest slicer
+                for (int i = 0; i <= slicers.size() - 1; i++) {
+                    if(!slicers.isEmpty()){
+                        Slicer s = slicers.get(i);
+                        // Checks if slicer within range and has health
+                        if (v.getCenter().distanceTo(s.getCenter()) < v.getRadius() && s.getHealth() > 0 && !hasTarget) {
+                            // Successfully found closest slicer and within tank range
+                            v.setTarget(s);
+                            slicerIndex = i;
+                            hasTarget = true;
+                        }
+                    }
+                }
+                // Checks if tank has target
+                if(hasTarget){
+                    // Shoot projectile at target once in every cooldown period
+                    if (projCount*1000 / FPS >= v.getCooldown()) {
+                        if(v.getDamage() == 1){
+                            // Tank projectile
+                            projectiles.add(new Projectile(v.getTankPoint(),v.getTarget(),v.getDamage(),slicerIndex,TANK_PROJ_FILE));
+                        } else {
+                            // Super Tank projectile
+                            projectiles.add(new Projectile(v.getTankPoint(),v.getTarget(),v.getDamage(),slicerIndex,STANK_PROJ_FILE));
+                        }
+                        // Reset projectile frame count
+                        projCount = 0;
+                    }
+
+                }
+
+                v.update(input);
+                hasTarget = false;
+
+
+            }
+        }
+        // Update all projectiles
+        for (int i = projectiles.size() - 1; i >= 0; i--) {
+            if(!projectiles.isEmpty()){
+                Projectile t = projectiles.get(i);
+
+                t.update(input);
+                // Projectile has hit a slicer
+                if (t.isFinished()) {
+                    if(t.getSlicerIndex()<slicers.size()){
+                        // Remove appropriate health from slicer
+                        slicers.get(t.getSlicerIndex()).setHealth(slicers.get(t.getSlicerIndex()).getHealth()-t.getDamage());
+                    }
+
+                    // Remove projectile
+                    projectiles.remove(i);
+                }
+
+            }
+
+        }
+        // Update all planes
+        for (int i = planes.size() - 1; i >= 0; i--) {
+            if(!planes.isEmpty()){
+                Airplane v = planes.get(i);
+                v.update(input);
+                // Check if any of the plane's explosives are going to explode
+                if(v.getExplode()!=null){
+                    // One of the planes explosives is ready to explode
+                    // Create a range for explosion to occur
+                    Rectangle r = new Rectangle(v.getExplode().x-EXP_RADIUS,
+                            v.getExplode().y-EXP_RADIUS,
+                            EXP_RADIUS*2,
+                            EXP_RADIUS*2);
+                    // Remove appropriate health from all slicers in range
+                    for (int j = slicers.size() - 1; j >= 0; j--) {
+                        if(slicers.get(j).getRect().intersects(r)){
+                            slicers.get(j).setHealth(slicers.get(j).getHealth()-v.getDamage());
+                        }
+                    }
+                }
+                // Remove plane
+                if (v.isFinished()) {
+                    planes.remove(i);
+                }
+            }
+
+        }
+        // Update all slicers
+        for (int i = slicers.size() - 1; i >= 0; i--) {
+            if(!slicers.isEmpty()){
+                Slicer s = slicers.get(i);
+
+                s.update(input);
+                // Checks if specified slicer is finished
+                if (s.isFinished()) {
+                    // Checks if slicer was finished by depleting health
+                    if(s.getHealth()<=0){
+                        // Spawn slicers on death if so
+                        if(s.getPenalty() == 2){
+                            for (int j = 0; j < s.getSpawnOnDeath(); j++) {
+                                slicers.add(new RegularSlicer(polyline, s.getTargetPointIndex(), s.getCurrentPoint(), RSLICER));
+                            }
+
+                        } else if(s.getPenalty() == 4){
+                            for (int j = 0; j < s.getSpawnOnDeath(); j++) {
+                                slicers.add(new SuperSlicer(polyline,s.getTargetPointIndex(),s.getCurrentPoint(),SSLICER));
+                            }
+
+                        } else if(s.getPenalty() == 16){
+                            for (int j = 0; j < s.getSpawnOnDeath(); j++) {
+                                slicers.add(new MegaSlicer(polyline,s.getTargetPointIndex(),s.getCurrentPoint(),MSLICER));
+                            }
+
+                        }
+                        // Update gold for slicer kill
+                        gold += s.getReward();
+                    } else {
+                        // Update lives if slicer completed the run
+                        lives -= s.getPenalty();
+                    }
+                    // Remove slicer
+                    slicers.remove(i);
+                }
+
+            }
+
+        }
+        //Draw shop panel
+        drawShopPanel();
+
+        // Draw status panel
+        drawStatusPanel();
+
+
+
+
+
+
+    }
+}
diff --git a/src/lists/Slicer.java b/src/Slicer.java
similarity index 79%
rename from src/lists/Slicer.java
rename to src/Slicer.java
index 1e3f6c8..29a9f45 100644
--- a/src/lists/Slicer.java
+++ b/src/Slicer.java
@@ -1,5 +1,3 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
 import bagel.util.Vector2;
@@ -12,7 +10,7 @@ public class Slicer extends Sprite {
 
 
     protected double speed,reward,penalty;
-    protected int health;
+    protected int health, spawnOnDeath;
     protected final List<Point> polyline;
     protected int targetPointIndex;
     protected boolean finished;
@@ -22,17 +20,41 @@ public class Slicer extends Sprite {
      *
      * @param polyline The polyline that the slicer must traverse (must have at least 1 point)
      */
-    public Slicer(List<Point> polyline,String imageSrc) {
-        super(polyline.get(0), imageSrc);
+    public Slicer(List<Point> polyline,int targetPointIndex, Point point,String imageSrc) {
+        super(point, imageSrc);
         this.polyline = polyline;
-        this.targetPointIndex = 1;
+        this.targetPointIndex = targetPointIndex;
         this.finished = false;
 
 
     }
+
+    public int getTargetPointIndex() {
+        return this.targetPointIndex;
+    }
+
+    public double getReward() {
+        return this.reward;
+    }
+
+    public int getSpawnOnDeath() {
+        return this.spawnOnDeath;
+    }
+
+    public int getHealth(){
+        return this.health;
+    }
+
+    public double getPenalty() {
+        return this.penalty;
+    }
+
     public void setHealth(int health){
         this.health = health;
     }
+    public Point getCurrentPoint(){
+        return getCenter();
+    }
     /**
      * Updates the current state of the slicer. The slicer moves towards its next target point in
      * the polyline at its specified movement rate.
@@ -64,6 +86,7 @@ public class Slicer extends Sprite {
         }
 
         if(health<=0){
+
             finished = true;
             return;
         }
diff --git a/src/lists/Sprite.java b/src/Sprite.java
similarity index 98%
rename from src/lists/Sprite.java
rename to src/Sprite.java
index 4e36d74..4ca3eee 100644
--- a/src/lists/Sprite.java
+++ b/src/Sprite.java
@@ -1,5 +1,3 @@
-package lists;
-
 import bagel.DrawOptions;
 import bagel.Image;
 import bagel.Input;
diff --git a/src/lists/SuperSlicer.java b/src/SuperSlicer.java
similarity index 77%
rename from src/lists/SuperSlicer.java
rename to src/SuperSlicer.java
index 7fe3b58..03f7aec 100644
--- a/src/lists/SuperSlicer.java
+++ b/src/SuperSlicer.java
@@ -1,8 +1,6 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
-import bagel.util.Vector2;
+
 import java.util.List;
 
 /**
@@ -17,13 +15,14 @@ public class SuperSlicer extends Slicer {
      *
      * @param polyline The polyline that the slicer must traverse (must have at least 1 point)
      */
-    public SuperSlicer(List<Point> polyline,String imageSrc) {
-        super(polyline, imageSrc);
+    public SuperSlicer(List<Point> polyline, int targetPointIndex, Point point,String imageSrc) {
+        super(polyline,targetPointIndex,point, imageSrc);
 
         this.speed = 0.75;
         this.health = 1;
         this.reward = 15;
         this.penalty = 2;
+        this.spawnOnDeath = 2;
 
     }
 
diff --git a/src/lists/SuperTank.java b/src/SuperTank.java
similarity index 88%
rename from src/lists/SuperTank.java
rename to src/SuperTank.java
index 2c3e7ae..4202cba 100644
--- a/src/lists/SuperTank.java
+++ b/src/SuperTank.java
@@ -1,5 +1,3 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
 
@@ -10,7 +8,7 @@ public class SuperTank extends Tank{
     public SuperTank(Point point, String imageSrc){
         super(point,imageSrc);
         this.radius = 150;
-        this.damage = 1;
+        this.damage = 3;
         this.cooldown = 500;
 
     }
diff --git a/src/lists/Tank.java b/src/Tank.java
similarity index 67%
rename from src/lists/Tank.java
rename to src/Tank.java
index 262c007..9a0e755 100644
--- a/src/lists/Tank.java
+++ b/src/Tank.java
@@ -1,12 +1,6 @@
-package lists;
-
 import bagel.Input;
 import bagel.util.Point;
 
-import java.util.ArrayList;
-
-import java.util.List;
-
 public class Tank extends Sprite{
     protected double radius,cooldown;
     protected int damage;
@@ -22,13 +16,23 @@ public class Tank extends Sprite{
         this.target = null;
 
     }
-
-    public void attack(Slicer slicer){
-        if (slicer.health > 0){
-            slicer.health-=damage;
-
-
-        }
+    public void setTarget(Slicer givenTarget){
+        this.target = givenTarget;
+    }
+    public Point getTankPoint(){
+        return this.tankPoint;
+    }
+    public Slicer getTarget(){
+        return this.target;
+    }
+    public int getDamage(){
+        return this.damage;
+    }
+    public double getRadius(){
+        return this.radius;
+    }
+    public double getCooldown(){
+        return this.cooldown;
     }
     @Override
     public void update(Input input) {
diff --git a/src/lists/ShadowDefend.java b/src/lists/ShadowDefend.java
deleted file mode 100644
index 91bf947..0000000
--- a/src/lists/ShadowDefend.java
+++ /dev/null
@@ -1,557 +0,0 @@
-package lists;
-
-import bagel.*;
-import bagel.Font;
-import bagel.Image;
-
-import bagel.map.TiledMap;
-import bagel.util.Colour;
-import bagel.util.Point;
-import bagel.util.Rectangle;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Scanner;
-
-
-/**
- * ShadowDefend, a tower defence game.
- * Used Rohyl's template from Project 1
- */
-public class ShadowDefend extends AbstractGame {
-    private static final String RSLICER = "res/images/slicer.png";
-    private static final String SSLICER = "res/images/superslicer.png";
-    private static final String MSLICER = "res/images/megaslicer.png";
-    private static final String ASLICER = "res/images/apexslicer.png";
-    private static final int HEIGHT = 768;
-    private static final int WIDTH = 1024;
-    private static final String MAP_FILE = "res/levels/1.tmx";
-    private static final String SHOP_FILE = "res/images/buypanel.png";
-    private static final String STATUS_FILE = "res/images/statuspanel.png";
-    private static final String TANK_FILE = "res/images/tank.png";
-    private static final String TANK_PROJ_FILE = "res/images/tank_projectile.png";
-    private static final String STANK_FILE = "res/images/supertank.png";
-    private static final String PLANE_FILE = "res/images/airsupport.png";
-    private static final String FONT_FILE = "res/fonts/DejaVuSans-Bold.ttf";
-    private static final String INFO = "Key binds:\n\nS - Start Wave\nL - Increase Timescale\nK - Decrease Timescale";
-    private static final String WAVES_FILE = "res/levels/waves.txt";
-    private DrawOptions colour = new DrawOptions();
-    private File wavesText = new File(WAVES_FILE);
-    private Scanner fr;
-    // Change to suit system specifications. This could be
-    // dynamically determined but that is out of scope.
-    public static final double FPS = 60;
-    // The spawn delay (in seconds) to spawn slicers
-    private static final int SPAWN_DELAY = 5;
-    private static final int INTIAL_TIMESCALE = 1;
-    private static final int MAX_SLICERS = 5;
-    // Timescale is made static because it is a universal property of the game and the specification
-    // says everything in the game is affected by this
-    private static int timescale = INTIAL_TIMESCALE;
-    private final TiledMap map;
-    private final Image shop, statusPanel, tankIcon, stankIcon, planeIcon;
-    private final List<Point> polyline;
-    private final List<Slicer> slicers;
-    private final List<Projectile> projectiles;
-
-    private final List<Tank> tanks;
-
-    private final List<Airplane> planes;
-
-    private final Rectangle window;
-    private Point p;
-    private List<String> event;
-    private String prev_event;
-    private List<List<String>> events;
-    private Font goldDisplay, keyInstruction, costText, statusText;
-    private Image placingIcon;
-    private double frameCount;
-    private double projCount;
-    private int spawnedSlicers;
-    private int nothingTime;
-    private int spawnDelay;
-    private int spawnCount;
-    private int eventType;
-    private int waveCounter;
-    private int eventCounter;
-    private int prevWaveState;
-    private int slicerIndex;
-    private boolean eventWait;
-    private String enemyType;
-    private String placedImage;
-    private boolean waveStarted;
-    private boolean eventStarted = true;
-    private boolean isVertical = false;
-    private boolean hasTarget = false;
-    private static int gold, lives, waveNumber, waveState;
-
-
-    /**
-     * Creates a new instance of the ShadowDefend game
-     */
-    public ShadowDefend() {
-
-        super(WIDTH, HEIGHT, "ShadowDefend");
-
-        gold = 50000;
-        lives = 25;
-        waveNumber = 1;
-        waveState = 0;
-        this.window = new Rectangle(0,0,WIDTH,HEIGHT);
-        this.map = new TiledMap(MAP_FILE);
-        this.shop = new Image(SHOP_FILE);
-        this.statusPanel = new Image(STATUS_FILE);
-        this.tankIcon = new Image(TANK_FILE);
-        this.stankIcon = new Image(STANK_FILE);
-        this.planeIcon = new Image(PLANE_FILE);
-        this.goldDisplay = new Font(FONT_FILE,50);
-        this.keyInstruction = new Font(FONT_FILE,16);
-        this.costText = new Font(FONT_FILE,20);
-        this.statusText = new Font(FONT_FILE,16);
-        this.polyline = map.getAllPolylines().get(0);
-        this.slicers = new ArrayList<>();
-        this.projectiles = new ArrayList<>();
-
-        this.tanks = new ArrayList<>();
-
-        this.planes = new ArrayList<>();
-
-        this.events = new ArrayList<>();
-        this.event = new ArrayList<>();
-
-        this.spawnedSlicers = 0;
-        this.waveStarted = false;
-        this.frameCount = Integer.MAX_VALUE;
-        this.projCount = Integer.MAX_VALUE;
-        this.waveCounter = 1;
-        this.eventCounter = 0;
-        this.eventWait = false;
-        try {
-            this.fr = new Scanner(wavesText);
-            while (fr.hasNextLine()) {
-                events.add(Arrays.asList(fr.nextLine().split(",")));
-            }
-            fr.close();
-        } catch (FileNotFoundException e) {
-            e.printStackTrace();
-        }
-
-
-
-        // Temporary fix for the weird slicer map glitch (might have to do with caching textures)
-        // This fix is entirely optional
-        //new Slicer(polyline);
-    }
-
-    /**
-     * The entry-point for the game
-     *
-     * @param args Optional command-line arguments
-     */
-    public static void main(String[] args) {
-        new ShadowDefend().run();
-    }
-
-    public static int getTimescale() {
-        return timescale;
-    }
-
-    /**
-     * Increases the timescale
-     */
-    private void increaseTimescale() {
-        timescale++;
-    }
-
-    /**
-     * Decreases the timescale but doesn't go below the base timescale
-     */
-    private void decreaseTimescale() {
-        if (timescale > INTIAL_TIMESCALE) {
-            timescale--;
-        }
-    }
-    private void getEventData(){
-        if(event.size() == 3){
-            // Delay event
-            eventType = 0;
-            waveNumber = Integer.parseInt(event.get(0));
-            nothingTime = Integer.parseInt(event.get(2));
-
-
-        } else {
-            // Spawn event
-            eventType = 1;
-            waveNumber = Integer.parseInt(event.get(0));
-            spawnCount = Integer.parseInt(event.get(2));
-            enemyType = event.get(3);
-            spawnDelay = Integer.parseInt(event.get(4));
-            System.out.println(waveNumber);
-            System.out.println(spawnCount);
-            System.out.println(enemyType);
-            System.out.println(spawnDelay);
-        }
-
-    }
-    /**
-     * Update the state of the game, potentially reading from input
-     *
-     * @param input The current mouse/keyboard state
-     */
-    @Override
-    protected void update(Input input) {
-        // Increase the frame counter by the current timescale
-        frameCount += getTimescale();
-        projCount += getTimescale();
-
-
-        // Draw map from the top left of the window
-        map.draw(0, 0, 0, 0, WIDTH, HEIGHT);
-
-        //Draw shop panel
-        shop.drawFromTopLeft(0,0);
-
-        tankIcon.draw(64,(shop.getHeight()/2)-10);
-        stankIcon.draw(184,(shop.getHeight()/2)-10);
-        planeIcon.draw(304,(shop.getHeight()/2)-10);
-        keyInstruction.drawString(INFO,(shop.getWidth()/2)-keyInstruction.getWidth(INFO)/2,20);
-        if(gold > 999){
-            String extra = Integer.toString(gold).substring(Integer.toString(gold).length() -3);
-            String thousandth = Integer.toString(gold).substring(0,Integer.toString(gold).length() -3);
-            goldDisplay.drawString("$"+ thousandth + "," + extra,shop.getWidth()-200,65);
-
-        } else {
-            goldDisplay.drawString("$"+ gold,shop.getWidth()-200,65);
-        }
-        if(gold < 250){
-            costText.drawString("$"+250,64-(tankIcon.getWidth()/2),
-                    (tankIcon.getHeight()/2)+(shop.getHeight()/2+5),
-                    colour.setBlendColour(Colour.RED));
-
-        } else {
-            costText.drawString("$"+250,64-(tankIcon.getWidth()/2),
-                    (tankIcon.getHeight()/2)+(shop.getHeight()/2+5),
-                    colour.setBlendColour(Colour.GREEN));
-        }
-
-        if(gold < 600){
-            costText.drawString("$"+600,184-(stankIcon.getWidth()/2),
-                    (stankIcon.getHeight()/2)+(shop.getHeight()/2+5),
-                    colour.setBlendColour(Colour.RED));
-
-        } else {
-            costText.drawString("$"+600,184-(stankIcon.getWidth()/2),
-                    (stankIcon.getHeight()/2)+(shop.getHeight()/2+5),
-                    colour.setBlendColour(Colour.GREEN));
-
-        }
-        if(gold < 500){
-            costText.drawString("$"+500,304-(planeIcon.getWidth()/2),
-                    (planeIcon.getHeight()/2)+(shop.getHeight()/2+5),
-                    colour.setBlendColour(Colour.RED));
-
-        } else {
-            costText.drawString("$"+500,304-(planeIcon.getWidth()/2),
-                    (planeIcon.getHeight()/2)+(shop.getHeight()/2+5),
-                    colour.setBlendColour(Colour.GREEN));
-
-        }
-
-        //Draw status panel
-        statusPanel.drawFromTopLeft(0,HEIGHT - statusPanel.getHeight());
-        statusText.drawString("Wave: " + waveNumber,5,HEIGHT-6);
-        if(timescale>1){
-            statusText.drawString("Timescale: " + timescale + ".0",
-                    WIDTH/4,
-                    HEIGHT-6,
-                    colour.setBlendColour(Colour.GREEN));
-
-        } else {
-            statusText.drawString("Timescale: " + timescale + ".0",WIDTH/4,HEIGHT-6);
-        }
-        switch(waveState) {
-            case 0:
-                statusText.drawString("Status: Awaiting Start",
-                        WIDTH/2,
-                        HEIGHT-6);
-                break;
-            case 1:
-                statusText.drawString("Status: Wave In Progress",
-                        WIDTH/2,
-                        HEIGHT-6);
-                break;
-            case 2:
-                statusText.drawString("Status: Placing",
-                        WIDTH/2,
-                        HEIGHT-6);
-                break;
-            case 3:
-                statusText.drawString("Status: Winner!",
-                        WIDTH/2,
-                        HEIGHT-6);
-                break;
-        }
-        statusText.drawString("Lives: " + lives,
-                WIDTH-statusText.getWidth("Lives: " + lives)-5,
-                HEIGHT-6);
-
-        // Handle key presses
-        if(input.wasPressed(MouseButtons.LEFT)){
-            System.out.println(input.getMousePosition());
-            if(tankIcon.getBoundingBoxAt(p = new Point(64,(shop.getHeight()/2)-10)).intersects(input.getMousePosition())
-                    && gold >= 250){
-                placingIcon = new Image(TANK_FILE);
-                placedImage = "tank";
-                prevWaveState = waveState;
-                waveState = 2;
-            }
-            if(stankIcon.getBoundingBoxAt(p = new Point(184,(shop.getHeight()/2)-10)).intersects(input.getMousePosition())
-                    && gold >= 600){
-                placingIcon = new Image(STANK_FILE);
-                placedImage = "stank";
-                prevWaveState = waveState;
-                waveState = 2;
-            }
-            if(planeIcon.getBoundingBoxAt(p = new Point(304,(shop.getHeight()/2)-10)).intersects(input.getMousePosition())
-                    && gold >= 500){
-                placingIcon = new Image(PLANE_FILE);
-                placedImage = "plane";
-                prevWaveState = waveState;
-                waveState = 2;
-            }
-        }
-        if(input.isUp(MouseButtons.LEFT)){
-            if(window.intersects(input.getMousePosition())){
-                if(placingIcon != null
-                        && !map.hasProperty((int)Math.round(input.getMouseX()),(int)Math.round(input.getMouseY()),"blocked")
-                        && !shop.getBoundingBox().intersects(input.getMousePosition())
-                        && !statusPanel.getBoundingBoxAt(p = new Point(WIDTH/2,HEIGHT - statusPanel.getHeight()/2)).intersects(input.getMousePosition())){
-
-                    placingIcon.draw(input.getMouseX(),input.getMouseY());
-                }
-            }
-
-        }
-        if(input.wasPressed(MouseButtons.LEFT) && placingIcon != null
-                && !map.hasProperty((int)Math.round(input.getMouseX()),(int)Math.round(input.getMouseY()),"blocked")
-                && !shop.getBoundingBox().intersects(input.getMousePosition())
-                && !statusPanel.getBoundingBoxAt(p = new Point(WIDTH/2,HEIGHT - statusPanel.getHeight()/2)).intersects(input.getMousePosition())){
-
-            if(placedImage.equals("tank")){
-                tanks.add(new Tank(input.getMousePosition(),TANK_FILE));
-                gold-=250;
-                System.out.println(tanks);
-            }
-            if(placedImage.equals("stank")) {
-                tanks.add(new SuperTank(input.getMousePosition(), STANK_FILE));
-                gold-=600;
-                System.out.println(tanks);
-            }
-            if(placedImage.equals("plane")) {
-                if(isVertical){
-                    planes.add(new Airplane(new Point(input.getMouseX(),0),isVertical, PLANE_FILE));
-                    isVertical = false;
-                } else {
-                    planes.add(new Airplane(new Point(0,input.getMouseY()),isVertical, PLANE_FILE));
-                    isVertical = true;
-                }
-
-                gold-=500;
-                System.out.println(planes);
-            }
-            waveState = prevWaveState;
-            placingIcon = null;
-
-
-
-        }
-        if (input.wasPressed(Keys.S)) {
-            if(waveState != 1){
-                waveStarted = true;
-                waveState = 1;
-            }
-
-        }
-
-        if (input.wasPressed(Keys.L)) {
-            increaseTimescale();
-        }
-
-        if (input.wasPressed(Keys.K)) {
-            decreaseTimescale();
-        }
-
-
-        if(waveStarted){
-            if(eventCounter<events.size()){
-                event = events.get(eventCounter);
-                if(waveCounter == Integer.parseInt(event.get(0)) && !eventWait){
-                    getEventData();
-                    eventStarted = true;
-                    eventCounter++;
-                } else if(waveCounter != Integer.parseInt(event.get(0))){
-                    waveCounter++;
-                    waveStarted = false;
-
-
-
-                }
-
-            } else {
-                if(lives>0 && slicers.isEmpty()){
-                    if(waveState != 3){
-                        gold += waveNumber*100+150;
-                    }
-                    waveState = 3;
-
-
-
-                }
-
-
-            }
-
-        }
-        if(waveState == 1 && !waveStarted && slicers.isEmpty()){
-            if(waveState != 0){
-                gold += waveNumber*100+150;
-            }
-
-            waveState = 0;
-
-        }
-        if(eventStarted){
-            if (eventType == 1) {
-                eventWait = true;
-                if (frameCount*1000 / FPS >= spawnDelay && spawnedSlicers != spawnCount) {
-                    switch(enemyType) {
-                        case "slicer":
-                            slicers.add(new RegularSlicer(polyline,RSLICER));
-                            break;
-                        case "superslicer":
-                            //System.out.println("in");
-                            slicers.add(new SuperSlicer(polyline,SSLICER));
-                            break;
-                        case "megaslicer":
-                            slicers.add(new MegaSlicer(polyline,MSLICER));
-                            break;
-                        case "apexslicer":
-                            slicers.add(new ApexSlicer(polyline,ASLICER));
-                            break;
-                    }
-
-                    spawnedSlicers += 1;
-                    // Reset frame counter
-                    frameCount = 0;
-                } else if (spawnedSlicers == spawnCount) {
-                    System.out.println("done");
-                    eventWait = false;
-                    eventStarted = false;
-                    spawnedSlicers = 0;
-
-                }
-            } else if (eventType == 0) {
-                eventWait = true;
-                if (frameCount*1000 / FPS >= nothingTime) {
-                    eventWait = false;
-                    eventStarted = false;
-                    // Reset frame counter
-                    frameCount = 0;
-                }
-            }
-
-        }
-
-        // Wave begin
-
-
-
-
-        // Close game if all slicers have finished traversing the polyline
-        /*if (spawnedSlicers == MAX_SLICERS && slicers.isEmpty()) {
-            Window.close();
-        }*/
-
-        // Update all sprites, and remove them if they've finished
-        for (int j = tanks.size() - 1; j >= 0; j--) {
-            if (!tanks.isEmpty()) {
-                Tank v = tanks.get(j);
-                v.target = null;
-
-                for (int i = 0; i <= slicers.size() - 1; i++) {
-                    if(!slicers.isEmpty()){
-                        Slicer s = slicers.get(i);
-                        if (v.getCenter().distanceTo(s.getCenter()) < v.radius && s.health > 0 && !hasTarget) {
-                            v.target = s;
-                            slicerIndex = i;
-                            hasTarget = true;
-                        }
-                    }
-                }
-                if(hasTarget){
-                    if (projCount*1000 / FPS >= v.cooldown) {
-
-                        projectiles.add(new Projectile(v.tankPoint,v.target,v.damage,slicerIndex,TANK_PROJ_FILE));
-                        projCount = 0;
-                    }
-
-                }
-
-                v.update(input);
-                hasTarget = false;
-
-
-            }
-        }
-        for (int i = projectiles.size() - 1; i >= 0; i--) {
-            if(!projectiles.isEmpty()){
-                Projectile t = projectiles.get(i);
-
-                t.update(input);
-                if (t.isFinished()) {
-
-                    slicers.get(t.slicerIndex).setHealth(slicers.get(t.slicerIndex).health-t.damage);
-                    System.out.println(slicers.get(t.slicerIndex).health);
-                    projectiles.remove(i);
-                }
-
-            }
-
-        }
-        for (int i = slicers.size() - 1; i >= 0; i--) {
-            if(!slicers.isEmpty()){
-                Slicer s = slicers.get(i);
-
-                s.update(input);
-                if (s.isFinished()) {
-                    if(s.health<=0){
-                        gold += s.reward;
-                    } else {
-                        lives -= s.penalty;
-                    }
-                    slicers.remove(i);
-                }
-
-            }
-
-        }
-
-
-
-
-
-        for (int i = planes.size() - 1; i >= 0; i--) {
-            if(!planes.isEmpty()){
-                Airplane v = planes.get(i);
-                v.update(input);
-                if (v.isFinished()) {
-                    planes.remove(i);
-                }
-            }
-
-        }
-    }
-}
-- 
GitLab