From 3dce8456b3b810c7adf1cb29b3e72445d1e21d4f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lubo=C5=A1=20Hor=C3=A1=C4=8Dek?= <horaceklubos@gmail.com>
Date: Mon, 22 Jun 2015 20:21:58 +0200
Subject: [PATCH] #31 Shooting range code base

---
 .../game/games/shooting_range/Properties.java |  19 +++
 .../shooting_range/ShootingRangeGame.java     |  56 ++++++-
 .../shooting_range/media/TextureType.java     |  82 ++++++++++
 .../games/shooting_range/model/Direction.java |   8 +
 .../games/shooting_range/model/GameState.java |   7 +
 .../games/shooting_range/model/Target.java    | 112 +++++++++++++
 .../game/games/shooting_range/model/Wave.java | 144 +++++++++++++++++
 .../shooting_range/tools/TargetGenerator.java | 148 ++++++++++++++++++
 8 files changed, 575 insertions(+), 1 deletion(-)
 create mode 100644 core/src/cz/nic/tablexia/game/games/shooting_range/Properties.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/shooting_range/media/TextureType.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/shooting_range/model/Direction.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/shooting_range/model/GameState.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/shooting_range/model/Target.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/shooting_range/model/Wave.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/shooting_range/tools/TargetGenerator.java

diff --git a/core/src/cz/nic/tablexia/game/games/shooting_range/Properties.java b/core/src/cz/nic/tablexia/game/games/shooting_range/Properties.java
new file mode 100644
index 000000000..bca45f5c2
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/shooting_range/Properties.java
@@ -0,0 +1,19 @@
+package cz.nic.tablexia.game.games.shooting_range;
+
+/**
+ * Created by lhoracek on 6/22/15.
+ */
+public class Properties {
+    public static final String BASE_DIR = "strelnice/";
+
+    public static final  int FLOWERS_WAVE1_ZINDEX = 35;
+    public static final  int FLOWERS_WAVE2_ZINDEX = 25;
+    public static final  int FLOWERS_WAVE3_ZINDEX = 15;
+
+    public static final int[] CUPS_EASY   = {25, 45, 75};
+    public static final int[] CUPS_MEDIUM = {20, 40, 70};
+    public static final int[] CUPS_HARD   = {20, 35, 60};
+
+    static final String[] RESULT_SOUNDS        = new String[]{"result/result_0", "result/result_1", "result/result_2", "result/result_3"};
+    static final String[] RESULT_TEXT          = new String[]{"game_kidnapping_result_0", "game_kidnapping_result_1", "game_kidnapping_result_2", "game_kidnapping_result_3"};
+}
diff --git a/core/src/cz/nic/tablexia/game/games/shooting_range/ShootingRangeGame.java b/core/src/cz/nic/tablexia/game/games/shooting_range/ShootingRangeGame.java
index a188cf8af..f95c85635 100644
--- a/core/src/cz/nic/tablexia/game/games/shooting_range/ShootingRangeGame.java
+++ b/core/src/cz/nic/tablexia/game/games/shooting_range/ShootingRangeGame.java
@@ -1,9 +1,63 @@
 package cz.nic.tablexia.game.games.shooting_range;
 
+import com.badlogic.gdx.scenes.scene2d.Actor;
+
+import java.util.List;
+
 import cz.nic.tablexia.game.AbstractTablexiaGame;
+import cz.nic.tablexia.game.games.shooting_range.model.GameState;
 
 /**
  * Created by lhoracek
  */
-public class ShootingRangeGame extends AbstractTablexiaGame<Void> {
+public class ShootingRangeGame extends AbstractTablexiaGame<GameState> {
+
+
+    private static final int CAMERA_WIDTH = 1280;
+
+    public static final int   GAME_TIME            = 60;
+    public static final int   WARNING_TIME         = 5;
+    public static final float WAVE_VERTICAL_OFFSET = 0.2f;                                   // procento výšky obrazovky
+
+    private static final int WATCH_HAND_ZINDEX    = 60;
+    private static final int WATCH_ZINDEX         = 60;
+    private static final int FRAME_ZINDEX         = 50;
+    private static final int CLOUD_ZINDEX         = 55;
+    private static final int WAVE1_ZINDEX         = 40;
+    private static final int WAVE2_ZINDEX         = 30;
+    private static final int WAVE3_ZINDEX         = 20;
+
+    public static final  int CAROUSEL_ZINDEX      = WATCH_HAND_ZINDEX;
+    public static final  int SCORE_ZINDEX         = WATCH_HAND_ZINDEX;
+
+
+    private Actor watch;
+    private Actor watchHand;
+    private Actor carousel;
+    private Actor scoreText;
+
+
+    @Override
+    protected void prepareScreenSoundAssetNames(List<String> soundsFileNames) {
+        super.prepareScreenSoundAssetNames(soundsFileNames);
+        // TODO prepare sound names
+    }
+
+    @Override
+    protected GameState prepareGameData() {
+        // TODO prepare round
+
+        // TODO generate flower rows
+        return null;
+    }
+
+    @Override
+    protected void gameLoaded() {
+        super.gameLoaded();
+        // TODO prepare scene
+        // TODO prepare carousel
+        // TODO prepare stopwatch
+
+        // TODO start game
+    }
 }
diff --git a/core/src/cz/nic/tablexia/game/games/shooting_range/media/TextureType.java b/core/src/cz/nic/tablexia/game/games/shooting_range/media/TextureType.java
new file mode 100644
index 000000000..ba646f585
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/shooting_range/media/TextureType.java
@@ -0,0 +1,82 @@
+package cz.nic.tablexia.game.games.shooting_range.media;
+
+/**
+ * Created by lhoracek on 6/22/15.
+ */
+public enum TextureType {
+
+    WATCH("hodinky.png"), //
+    WATCH_HAND("rucicka.png"), //
+
+    CAROUSEL("karusel.png"), //
+
+    POZADI("pozadi1.png"), //
+    FRAME("ramecek.png"), //
+
+    BOX_BAD("bedynkaBAD.png"), //
+    BOX_GOOD("bedynkaGOOD.png"), //
+
+    WAVE_1("herni_plan2.png"), //
+    WAVE_2("herni_plan1.png"), //
+    WAVE_3("herni_plan3.png"), //
+
+    FLOWER_1("kytky/kvitka1.png"), //
+    FLOWER_2("kytky/kvitka2.png"), //
+    FLOWER_3("kytky/kvitka3.png"), //
+    FLOWER_4("kytky/kvitka4.png"), //
+    FLOWER_5("kytky/kvitka5.png"), //
+    FLOWER_6("kytky/kvitka6.png"), //
+    FLOWER_7("kytky/kvitka7.png"), //
+    FLOWER_8("kytky/kvitka8.png"), //
+    FLOWER_9("kytky/kvitka9.png"), //
+    FLOWER_10("kytky/kvitka10.png"), //
+    FLOWER_11("kytky/kvitka11.png"), //
+    FLOWER_12("kytky/kvitka12.png"), //
+    FLOWER_13("kytky/kvitka13.png"), //
+    FLOWER_14("kytky/kvitka14.png"), //
+    FLOWER_15("kytky/kvitka15.png"), //
+    FLOWER_16("kytky/kvitka16.png"), //
+    FLOWER_17("kytky/kvitka17.png"), //
+    FLOWER_18("kytky/kvitka18.png"), //
+    FLOWER_19("kytky/kvitka19.png"), //
+    FLOWER_20("kytky/kvitka20.png"), //
+    FLOWER_21("kytky/kvitka21.png"), //
+    FLOWER_22("kytky/kvitka22.png"), //
+    FLOWER_23("kytky/kvitka23.png"), //
+    FLOWER_24("kytky/kvitka24.png"), //
+
+    BOX_SMOKE_1("effects/1dym.png"), //
+    BOX_SMOKE_2("effects/2dym.png"), //
+    BOX_SMOKE_3("effects/3dym.png"), //
+    BOX_SMOKE_4("effects/4dym.png"), //
+    BOX_SMOKE_5("effects/5dym.png"), //
+    BOX_HIT("effects/GOOD_plus1.png"), //
+    BOX_TIME_MINUS_7("effects/BAD_minus7.png"), //
+    BOX_TIME_MINUS_5("effects/BAD_minus5.png"), //
+    BOX_TIME_PLUS_5("effects/GOOD_plus5.png"), //
+    BOX_TIME_PLUS_7("effects/GOOD_plus7.png"), //
+    BOX_SPEED_UP("effects/BAD_zrychleni.png"), //
+    BOX_SPEED_DOWN("effects/GOOD_zpomaleni.png"), //
+
+    ; //
+
+    public static final float         WATCH_CENTER_X_OFFSET = 7;
+    public static final float         WATCH_CENTER_Y_OFFSET = -65;
+
+    public static final TextureType[] BOXES                 = { BOX_BAD, BOX_GOOD };
+    public static final TextureType[] EFFECTS               = { BOX_SMOKE_1, BOX_SMOKE_2, BOX_SMOKE_3, BOX_SMOKE_4, BOX_SMOKE_5, BOX_TIME_MINUS_5, BOX_TIME_MINUS_7, BOX_TIME_PLUS_5, BOX_TIME_PLUS_7, BOX_SPEED_UP, BOX_SPEED_DOWN };
+    public static final TextureType[] FLOWERS_LEVEL_EASY    = { FLOWER_1, FLOWER_6, FLOWER_9, FLOWER_13, FLOWER_17, FLOWER_21 };
+    public static final TextureType[] FLOWERS_LEVEL_MEDIUM  = { FLOWER_2, FLOWER_4, FLOWER_5, FLOWER_7, FLOWER_11, FLOWER_12, FLOWER_14, FLOWER_15, FLOWER_17, FLOWER_19, FLOWER_21, FLOWER_22 };
+    public static final TextureType[] FLOWERS_LEVEL_HARD    = { FLOWER_1, FLOWER_2, FLOWER_3, FLOWER_4, FLOWER_5, FLOWER_6, FLOWER_7, FLOWER_8, FLOWER_9, FLOWER_10, FLOWER_11, FLOWER_12, FLOWER_13, FLOWER_14, FLOWER_15, FLOWER_16, FLOWER_17, FLOWER_18, FLOWER_19, FLOWER_20, FLOWER_21, FLOWER_22, FLOWER_23, FLOWER_24 };
+
+    private final String              resource;
+
+    private TextureType(String resource) {
+        this.resource = resource;
+
+    }
+
+    public String getResource() {
+        return resource;
+    }
+}
\ No newline at end of file
diff --git a/core/src/cz/nic/tablexia/game/games/shooting_range/model/Direction.java b/core/src/cz/nic/tablexia/game/games/shooting_range/model/Direction.java
new file mode 100644
index 000000000..cd9513ea0
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/shooting_range/model/Direction.java
@@ -0,0 +1,8 @@
+package cz.nic.tablexia.game.games.shooting_range.model;
+
+/**
+ * Created by lhoracek on 6/22/15.
+ */
+public enum Direction {
+    LEFT, RIGHT;
+}
\ No newline at end of file
diff --git a/core/src/cz/nic/tablexia/game/games/shooting_range/model/GameState.java b/core/src/cz/nic/tablexia/game/games/shooting_range/model/GameState.java
new file mode 100644
index 000000000..2e48e7e09
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/shooting_range/model/GameState.java
@@ -0,0 +1,7 @@
+package cz.nic.tablexia.game.games.shooting_range.model;
+
+/**
+ * Created by lhoracek on 6/22/15.
+ */
+public class GameState {
+}
diff --git a/core/src/cz/nic/tablexia/game/games/shooting_range/model/Target.java b/core/src/cz/nic/tablexia/game/games/shooting_range/model/Target.java
new file mode 100644
index 000000000..e3279e178
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/shooting_range/model/Target.java
@@ -0,0 +1,112 @@
+package cz.nic.tablexia.game.games.shooting_range.model;
+
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.Sprite;
+import com.badlogic.gdx.scenes.scene2d.Actor;
+
+import cz.nic.tablexia.game.games.shooting_range.media.TextureType;
+
+/**
+ * Created by lhoracek on 6/22/15.
+ */
+public class Target extends Actor {
+    private final float       startTime;
+    private       TextureType textureType;
+    private final Wave        wave;
+    private boolean shot = false;
+    private Sprite effect;
+    private Sprite overlay;
+
+    public static interface PositionProvider {
+        public float getY(float elapseTime, float maxHeight);
+
+        public static final PositionProvider PROVIDER_FLAT = new PositionProvider() {
+            @Override
+            public float getY(float elapsedTime, float maxHeight) {
+                return 0;
+            }
+        };
+    }
+
+    public Target(float pX, float pY, float pWidth, float pHeight, Texture texture, Float startTime, Wave wave, TextureType textureType, VertexBufferObjectManager pVertexBufferObjectManager) {
+        this.startTime = startTime;
+        this.textureType = textureType;
+        this.wave = wave;
+        setZIndex(wave.getzIndex());
+
+        // TODO
+        //overlay = new Sprite(pWidth / 2, pHeight / 2, pWidth, pHeight, , pVertexBufferObjectManager);
+        //overlay.setColor(1, 1, 1, 1);
+        //overlay.setColor(1, 0, 0, 1);
+        //overlay.setAlpha(0);
+        //attachChild(overlay);
+    }
+
+
+    public float getStartTime() {
+        return startTime;
+    }
+
+    public void setTextureType(TextureType textureType) {
+        this.textureType = textureType;
+    }
+
+    public TextureType getTextureType() {
+        return textureType;
+    }
+
+    public Wave getWave() {
+        return wave;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = (prime * result) + Float.floatToIntBits(startTime);
+        result = (prime * result) + ((textureType == null) ? 0 : textureType.hashCode());
+        result = (prime * result) + ((wave == null) ? 0 : wave.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        Target other = (Target) obj;
+        if (Float.floatToIntBits(startTime) != Float.floatToIntBits(other.startTime)) {
+            return false;
+        }
+        if (textureType != other.textureType) {
+            return false;
+        }
+        if (wave != other.wave) {
+            return false;
+        }
+        return true;
+    }
+
+    public boolean isShot() {
+        return shot;
+    }
+
+    public void setShot(boolean shot) {
+        this.shot = shot;
+    }
+
+    public Sprite getEffect() {
+        return effect;
+    }
+
+    public void setEffect(Sprite effect) {
+        this.effect = effect;
+    }
+
+}
diff --git a/core/src/cz/nic/tablexia/game/games/shooting_range/model/Wave.java b/core/src/cz/nic/tablexia/game/games/shooting_range/model/Wave.java
new file mode 100644
index 000000000..163e52518
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/shooting_range/model/Wave.java
@@ -0,0 +1,144 @@
+package cz.nic.tablexia.game.games.shooting_range.model;
+
+import cz.nic.tablexia.game.difficulty.GameDifficulty;
+import cz.nic.tablexia.game.games.shooting_range.Properties;
+
+/**
+ * Created by lhoracek on 6/22/15.
+ */
+public enum Wave {
+    /* --------------- LEVEL EASY --------------------- */
+    WAVE_1_1(GameDifficulty.EASY, 0, 7, 5, Direction.LEFT, new Target.PositionProvider() {
+        @Override
+        public float getY(float elapsedTime, float maxHeight) {
+            return (float) ((Math.sin((((elapsedTime / WAVE_1_1.getRunningTime()) * Math.PI * 2) * 1.5f) - 0.5) * maxHeight) / 30);
+        }
+    }), //
+    WAVE_1_2(GameDifficulty.EASY, 1, 5, 7, Direction.LEFT, new Target.PositionProvider() {
+        @Override
+        public float getY(float elapsedTime, float maxHeight) {
+            return (float) ((Math.sin((((elapsedTime / WAVE_1_2.getRunningTime()) * Math.PI * 2) * 2.3f) + 0.5) * maxHeight) / 30);
+        }
+    }), //
+    WAVE_1_3(GameDifficulty.EASY, 2, 6, 7, Direction.LEFT, new Target.PositionProvider() {
+        @Override
+        public float getY(float elapsedTime, float maxHeight) {
+            return (float) ((Math.sin((((elapsedTime / WAVE_3_3.getRunningTime()) * Math.PI * 2) * 1.5f) - 0.5) * maxHeight) / 20);
+        }
+    }), //
+
+    /* --------------- LEVEL MEDIUM --------------------- */
+    WAVE_2_1(GameDifficulty.MEDIUM, 0, 6, 5, Direction.LEFT, new Target.PositionProvider() {
+        @Override
+        public float getY(float elapsedTime, float maxHeight) {
+            return (float) ((Math.sin((((elapsedTime / WAVE_2_1.getRunningTime()) * Math.PI * 2) * 1.5f) - 0.5) * maxHeight) / 30);
+        }
+    }), //
+    WAVE_2_2(GameDifficulty.MEDIUM, 1, 4, 7, Direction.RIGHT, new Target.PositionProvider() {
+        @Override
+        public float getY(float elapsedTime, float maxHeight) {
+            return (float) ((Math.sin((((elapsedTime / WAVE_2_2.getRunningTime()) * Math.PI * 2) * 2.3f) - 0.5) * maxHeight) / 30);
+        }
+    }), //
+    WAVE_2_3(GameDifficulty.MEDIUM, 2, 5, 7, Direction.RIGHT, new Target.PositionProvider() {
+        @Override
+        public float getY(float elapsedTime, float maxHeight) {
+            return (float) ((Math.sin((((elapsedTime / WAVE_3_3.getRunningTime()) * Math.PI * 2) * 1.5f) - 0.5) * maxHeight) / 20);
+        }
+    }), //
+
+    /* --------------- LEVEL MEDIUM --------------------- */
+    WAVE_3_1(GameDifficulty.HARD, 0, 4, 10, Direction.LEFT, new Target.PositionProvider() {
+        @Override
+        public float getY(float elapsedTime, float maxHeight) {
+            return (float) ((Math.sin((((elapsedTime / WAVE_3_1.getRunningTime()) * Math.PI * 2) * 1.5f) - 0.5) * maxHeight) / 30);
+        }
+    }), //
+    WAVE_3_2(GameDifficulty.HARD, 1, 3, 7, Direction.RIGHT, new Target.PositionProvider() {
+        @Override
+        public float getY(float elapsedTime, float maxHeight) {
+            return (float) ((Math.sin((((elapsedTime / WAVE_3_2.getRunningTime()) * Math.PI * 2) * 2.3f) - 0.5) * maxHeight) / 20);
+        }
+    }), //
+    WAVE_3_3(GameDifficulty.HARD, 2, 5, 5, Direction.LEFT, new Target.PositionProvider() {
+        @Override
+        public float getY(float elapsedTime, float maxHeight) {
+            return (float) ((Math.sin((((elapsedTime / WAVE_3_3.getRunningTime()) * Math.PI * 2) * 1.5f) - 0.5) * maxHeight) / 20);
+        }
+    }); //
+
+    private static final Wave[] EASY_WAVES   = new Wave[]{WAVE_1_1, WAVE_1_2, WAVE_1_3};
+    private static final Wave[] MEDIUM_WAVES = new Wave[]{WAVE_2_1, WAVE_2_2, WAVE_2_3};
+    private static final Wave[] HARD_WAVES   = new Wave[]{WAVE_3_1, WAVE_3_2, WAVE_3_3};
+
+    public static Wave getWave(GameDifficulty difficulty, int wavePosition) {
+        switch (difficulty) {
+            case EASY:
+                return EASY_WAVES[wavePosition];
+            case MEDIUM:
+                return MEDIUM_WAVES[wavePosition];
+            case HARD:
+                return HARD_WAVES[wavePosition];
+            default:
+                throw new IllegalStateException("Unknow difficulty");
+        }
+    }
+
+    private final int                     verticalOrder;
+    private final float                   runningTime;
+    private final Direction               direction;
+    private final Target.PositionProvider positionProvider;
+    private final int                     flowerOnScreen;
+    private final GameDifficulty          difficulty;
+
+    private Wave(GameDifficulty difficulty, int verticalOrder, float runningTime, int flowersOnScreen, Direction direction, Target.PositionProvider positionProvider) {
+        this.verticalOrder = verticalOrder;
+        this.runningTime = runningTime;
+        this.direction = direction;
+        this.positionProvider = positionProvider;
+        flowerOnScreen = flowersOnScreen;
+        this.difficulty = difficulty;
+    }
+
+    public float getRunningTime() {
+        return runningTime;
+    }
+
+    public int getVerticalOrder() {
+        return verticalOrder;
+    }
+
+    public float getY(float elapsedTime, float maxHeight) {
+        return positionProvider.getY(elapsedTime, maxHeight);
+    }
+
+    public float getX(float elapsedTime, float maxWidth) {
+        return ((Direction.LEFT == direction ? -1 : 1) * (maxWidth * (elapsedTime / getRunningTime()))) + (Direction.LEFT == direction ? maxWidth : 0);
+    }
+
+    public int getzIndex() {
+        switch (verticalOrder) {
+            // TODO
+            case 0:
+                return Properties.FLOWERS_WAVE1_ZINDEX;
+            case 1:
+                return Properties.FLOWERS_WAVE2_ZINDEX;
+            case 2:
+                return Properties.FLOWERS_WAVE3_ZINDEX;
+            default:
+                throw new IllegalArgumentException("Unknown z-index");
+        }
+    }
+
+    public int getFlowerOnScreen() {
+        return flowerOnScreen;
+    }
+
+    public Direction getDirection() {
+        return direction;
+    }
+
+    public GameDifficulty getDifficulty() {
+        return difficulty;
+    }
+}
diff --git a/core/src/cz/nic/tablexia/game/games/shooting_range/tools/TargetGenerator.java b/core/src/cz/nic/tablexia/game/games/shooting_range/tools/TargetGenerator.java
new file mode 100644
index 000000000..9665816e2
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/shooting_range/tools/TargetGenerator.java
@@ -0,0 +1,148 @@
+package cz.nic.tablexia.game.games.shooting_range.tools;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import cz.nic.tablexia.game.difficulty.GameDifficulty;
+import cz.nic.tablexia.game.games.shooting_range.media.TextureType;
+import cz.nic.tablexia.game.games.shooting_range.model.Target;
+import cz.nic.tablexia.game.games.shooting_range.model.Wave;
+
+/**
+ * Created by lhoracek on 6/22/15.
+ */
+public class TargetGenerator {
+    private static final String TAG                     = TargetGenerator.class.getSimpleName();
+
+    private static final float  EASY_BOX_PROBABILITY    = 0.05f;                                // 5% krabic
+    private static final float  MEDIUM_BOX_PROBABILITY  = 0.05f;                                // 5% krabic
+    private static final float  HARD_BOX_PROBABILITY    = 0.1f;                                 // 10% krabic
+
+    public static final float   EASY_GOOD_PROBABILITY   = 0.7f;
+    public static final float   MEDIUM_GOOD_PROBABILITY = 0.5f;
+    public static final float   HARD_GOOD_PROBABILITY   = 0.3f;
+
+    private GameDifficulty      gameDifficulty;
+    private Random              random                 ;
+
+    public TargetGenerator(GameDifficulty gameDifficulty, Random random) {
+        super();
+        this.random = random;
+        this.gameDifficulty = gameDifficulty;
+    }
+
+    public TextureType getRandomFlowerType(GameDifficulty gameDifficulty) {
+        List<TextureType> textureTypeBag = getTextureTypeBag(gameDifficulty);
+        int random = (int) (Math.random() * textureTypeBag.size());
+        return textureTypeBag.get(random);
+    }
+
+    private Map<Wave, Target> lastTargetsForWave = new HashMap<Wave, Target>();
+
+    public Target getLastTargetInWave(Wave wave) {
+        return lastTargetsForWave.get(wave);
+    }
+
+    public Target addNewTargetToWave(Wave wave,  TextureType requiredTextureType) {
+        Target prevLastTarget = getLastTargetInWave(wave);
+        float targetPeriod = wave.getRunningTime() / wave.getFlowerOnScreen();
+        return addNewTargetToWave(wave,  requiredTextureType, prevLastTarget.getStartTime() + targetPeriod);
+    }
+
+    public Target addNewTargetToWave(Wave wave, TextureType requiredTextureType, float startTime) {
+        return addNewTargetToWave(wave,  requiredTextureType, startTime, true);
+    }
+
+    public Target addNewTargetToWave(Wave wave,  TextureType requiredTextureType, float startTime, boolean asLast) {
+        List<TextureType> textureTypeBag = new ArrayList<TextureType>(requiredTextureType == null ? getTextureTypeBag(gameDifficulty) : Arrays.asList((new TextureType[]{requiredTextureType})));
+        Target target = getRandomTarget(textureTypeBag, startTime, wave);
+        if (asLast) {
+            lastTargetsForWave.put(wave, target);
+        }
+        return target;
+    }
+
+    /*
+     * Init row on start
+     */
+    public List<Target> generateFlowerRow(Wave wave) {
+        List<Target> flowers = new ArrayList<Target>();
+        List<TextureType> textureTypeBag = new ArrayList<TextureType>(getTextureTypeBag(gameDifficulty));
+
+        int flowerNumber = wave.getFlowerOnScreen();
+        float targetPeriod = wave.getRunningTime() / wave.getFlowerOnScreen();
+
+        // přidáme jeden terč za okraj na prvn obrazovce
+        for (int i = -flowerNumber; i <= 0; i++) {
+
+            Target target = getRandomTarget(textureTypeBag, targetPeriod * i, wave);
+            flowers.add(target);
+            if (i == 0) {
+                lastTargetsForWave.put(wave, target);
+            }
+        }
+        return flowers;
+    }
+
+    private TextureType getRandomBoxType() {
+        float boxTypeIndex = random.nextFloat();
+        if ((gameDifficulty == GameDifficulty.EASY) && (boxTypeIndex > EASY_GOOD_PROBABILITY)) {
+            return TextureType.BOX_BAD;
+        } else if ((gameDifficulty == GameDifficulty.MEDIUM) && (boxTypeIndex > HARD_GOOD_PROBABILITY)) {
+            return TextureType.BOX_BAD;
+        } else if ((gameDifficulty == GameDifficulty.HARD) && (boxTypeIndex > HARD_GOOD_PROBABILITY)) {
+            return TextureType.BOX_BAD;
+        }
+
+        return TextureType.BOX_GOOD;
+    }
+
+    private Target getRandomTarget(List<TextureType> textureTypeBag, float startTime, Wave wave) {
+        float boxIndex = random.nextFloat();
+        TextureType textureType = getRandomBoxType();
+        if (boxIndex > getBoxProbability(wave.getDifficulty())) {
+            int random = (int) (Math.random() * textureTypeBag.size());
+            textureType = textureTypeBag.get(random);
+        }
+        Target target = new Target(0, 0, gfxManager.get(textureType).second, startTime, wave, textureType);
+        return target;
+    }
+
+    private float getBoxProbability(GameDifficulty difficulty) {
+        switch (gameDifficulty) {
+            case EASY:
+                return EASY_BOX_PROBABILITY;
+            case MEDIUM:
+                return MEDIUM_BOX_PROBABILITY;
+            case HARD:
+                return HARD_BOX_PROBABILITY;
+            default:
+                throw new IllegalStateException("Unknown difficulty");
+        }
+    }
+
+    private List<TextureType> getTextureTypeBag(GameDifficulty gameDifficulty) {
+        switch (gameDifficulty) {
+            case EASY:
+                return Arrays.asList(TextureType.FLOWERS_LEVEL_EASY);
+            case MEDIUM:
+                return Arrays.asList(TextureType.FLOWERS_LEVEL_MEDIUM);
+            case HARD:
+                return Arrays.asList(TextureType.FLOWERS_LEVEL_HARD);
+            default:
+                throw new IllegalStateException("Unknown difficulty");
+        }
+    }
+
+    public List<Target> initWaves(GameDifficulty difficulty) {
+        List<Target> targets = new ArrayList<Target>();
+        for (int i = 0; i < 3; i++) {
+            targets.addAll(generateFlowerRow(Wave.getWave(gameDifficulty, i)));
+        }
+        return targets;
+    }
+}
\ No newline at end of file
-- 
GitLab