using UnityEngine;
using System.Collections;
using System.Security.AccessControl;
using System.Security.Policy;

public class MasterControllerScript : MonoBehaviour
{

    public float fGroundMovespeedBase = 5.0f;

    private float moveSpeedModifierFromPlayerInput;

    public GameObject[] GroundBlockTypePrefabs;

    private float fPlayerDeltaFromOrigin;

    private GroundBlockMovementScript LastPlacedBlock;

    public bool bJimAFK;

    public int iWhatWaveIsIt;
    public int iBlockCountThisWave;

    public PlayerController playerScript;

    public int ActiveCages;

    public bool bIsBonusStage;
    public bool bIsBossStage;

    public GameObject ActiveBoss;

    public int iScore;

    public GameObject PlayerPrefab;

    public float fTimeSincePlayerDied;
    public bool bPlayerDead;

    public bool bAttractScreen;

    // Use this for initialization
    private void Start()
    {
        if (iWhatWaveIsIt < 1)
            iWhatWaveIsIt = 1;

        iBlockCountThisWave = -15;

        PrepareLevelWithBlocks();

        playerScript = GameObject.Find("TestMans").GetComponent<PlayerController>();

        ActiveCages = 0;

        bAttractScreen = true;
    }

    // Update is called once per frame
    private void Update()
    {
        if( Input.GetKeyDown(KeyCode.Escape))
            Application.Quit();

        if (bPlayerDead)
            fTimeSincePlayerDied += Time.deltaTime;

        if( bAttractScreen )
            if (Input.GetKey(KeyCode.Space))
                bAttractScreen = false;

        if (LastPlacedBlock == null)
            return;

        if (LastPlacedBlock.transform.position.x < 24.0f)
        {
            GenerateNewBlockAtTail(LastPlacedBlock.transform.position);
        }
    }

    public void OnPlayerDied()
    {
        fTimeSincePlayerDied = 0.0f;
        bPlayerDead = true;
    }

    public void SpawnNewPlayer()
    {
        if (playerScript != null)
        {
            if (playerScript.gameObject != null)
                Destroy(playerScript.gameObject);

            Destroy(playerScript);

            GameObject newmans = Instantiate(PlayerPrefab);
            newmans.name = "TestMans";
        }

        playerScript = GameObject.Find("TestMans").GetComponent<PlayerController>();

        iWhatWaveIsIt = 1;
        iScore = 0;
        iBlockCountThisWave = 0;

    }

    public void SetPlayerDeltaFromRootPosition(float fDelta)
    {
        fPlayerDeltaFromOrigin = fDelta;
        moveSpeedModifierFromPlayerInput = 2.0f*fDelta;
    }

    public float GetGroundMoveSpeed()
    {
        if (playerScript == null ||  playerScript.IsDead())
            return 0;

        float fSpeed = fGroundMovespeedBase + moveSpeedModifierFromPlayerInput;
        if (bIsBonusStage)
            fSpeed *= 2.0f;
        if (bIsBossStage)
            fSpeed *= 3.0f;
        
        return fSpeed;
    }

    public float GetEnemySpeedMultiplier()
    {
        return fPlayerDeltaFromOrigin;
    }

    public void AddScore(int thesePoints)
    {
        if( playerScript.iCrushedBuildingsCombo > 0)
            iScore += thesePoints*playerScript.iCrushedBuildingsCombo;
        else
        {
            iScore += thesePoints;
        }
    }

    public void PrepareLevelWithBlocks()
    {
        Vector2 vBlockPos = new Vector2(0.1f, -4.0f);
        GameObject newBlock;

        for (int t = 0; t < 12; t++)
        {
            newBlock = GameObject.Instantiate(GroundBlockTypePrefabs[0]);
            newBlock.transform.position = vBlockPos;
            vBlockPos.x += 2.0f;

            LastPlacedBlock = newBlock.GetComponent<GroundBlockMovementScript>();
            LastPlacedBlock.bMadeFirstMove = true;
        }

    }

    void DrawWaveInfo()
    {
        if (iWhatWaveIsIt >= 1 && iWhatWaveIsIt < 9)
        {
            GameObject WIS = GameObject.Find("WaveInfoSprite");
            SpriteRenderer sr = WIS.GetComponent<SpriteRenderer>();
            sr.enabled = true;

            WaveInfoManager wim = WIS.GetComponent<WaveInfoManager>();
            sr.sprite = wim.WaveInfoSprites[iWhatWaveIsIt-1];
        }
    }

    public void GenerateNewBlockAtTail(Vector2 vOldPos)
    {
        if( !bAttractScreen)
            iBlockCountThisWave++;

        if (iBlockCountThisWave < 10 && !bAttractScreen && !bPlayerDead)
        {
            //display wave info
            DrawWaveInfo();
        }
        else
        {
            GameObject WIS = GameObject.Find("WaveInfoSprite");
            SpriteRenderer sr = WIS.GetComponent<SpriteRenderer>();
            sr.enabled = false;
        }

        if (iBlockCountThisWave < 0 || bAttractScreen)
        {
            SpawnNewBlock(0, vOldPos);
            return;
        }

        if (playerScript.IsDead())
            return;

        iScore += 10;

        switch (iWhatWaveIsIt)
        {
            case 1:
                SpawnWave1(vOldPos);
                break;
            case 2:
                SpawnWave2(vOldPos);
                break;
            case 3:
                SpawnWave3(vOldPos);
                break;
            case 4:
                SpawnWave4(vOldPos);
                break;
            case 5:
                SpawnWave5(vOldPos);
                break;
            case 6:
                SpawnWave6(vOldPos);
                break;
            case 7:
                SpawnWave7(vOldPos);
                break;
            default:
                SpawnWave8OrHigher(vOldPos);
                break;
        }



    }

    private Vector3 SpawnNewBlock(int iBlockID, Vector3 newBlockPosition)
    {
        //Get the very right edge of the most recent block
        newBlockPosition.x += LastPlacedBlock.WidthInUnits / 2;

        //slight height variant
        newBlockPosition.y = -4.0f + Random.value * 0.1f - 0.05f;

        GameObject newBlock;
        newBlock = GameObject.Instantiate(GroundBlockTypePrefabs[iBlockID]);
        GroundBlockMovementScript gbms = newBlock.GetComponent<GroundBlockMovementScript>();

        //adjust for this new block's size
        newBlockPosition.x += gbms.WidthInUnits * 0.5f;
        newBlockPosition.y += gbms.PlacementOffset.y;
        

        newBlock.transform.position = newBlockPosition;

        //hack: if block is ID 1, it's mines-- kid friendly UN mines <3
        if (iBlockID == 1 && LastPlacedBlock != null)
        {
            //if the last placed block is also a mine field, don't put down a sign
            HurtTrigger ht = LastPlacedBlock.GetComponentInChildren<HurtTrigger>();

            if (ht == null)
            {
                GameObject warningSign = Instantiate(Resources.Load("MineWarning")) as GameObject;
                Vector3 vSignPos = newBlockPosition;
                vSignPos.y += 0.75f;
                warningSign.transform.position = vSignPos;
                warningSign.transform.parent = newBlock.transform;
            }
        }

        LastPlacedBlock = gbms;
        return newBlockPosition;
        
    }

    private void MakeBuilding(Vector3 newBlockPosition)
    {
        string badCode = "";

        switch (Random.Range(1, 5))
        {
            case 1:
                badCode = "building_babies";
                break;
            case 2:
                badCode = "building_justice";
                break;
            case 3:
                badCode = "building_medicine";
                break;
            case 4:
                badCode = "building_puppies";
                break;
        }

        GameObject building = Instantiate(Resources.Load(badCode) as GameObject);
        Vector3 vBuildingPos = newBlockPosition;
        vBuildingPos.y += 1.25f;
        building.transform.position = vBuildingPos;
        building.transform.parent = LastPlacedBlock.transform;
    }

    private void SpawnActor(string creatureName, Vector3 newBlockPosition, float yOffset)
    {
        GameObject building = Instantiate(Resources.Load(creatureName) as GameObject);
        Vector3 vMonsterPos = newBlockPosition;
        vMonsterPos.y += yOffset;
        building.transform.position = vMonsterPos;

        //Only cling to terrain if we're static, like a wall
        EnemyController ec = building.GetComponent<EnemyController>();
        if( ec != null  && ec.bStaticObstacle ) 
            building.transform.parent = LastPlacedBlock.transform;
    }

    private void SpawnAlly(string creatureName, Vector3 newBlockPosition, float yOffset)
    {
        if (ActiveCages >= 3)
            return;

        SpawnActor(creatureName,newBlockPosition,yOffset);
    }

    public void IncrementWave()
    {
        iBlockCountThisWave = -30;
        iWhatWaveIsIt++;
        bIsBonusStage = false;
        bIsBossStage = false;

    }

    private float GetAllySpawnRate()
    {
        int count = playerScript.listAttachedAllies.Count;

        if (count > 10)
            return 0.98f;
        if (count > 3)
            return 0.95f;

        return 0.9f;
    }

    private void MakeBoss()
    {
        GameObject nose = Instantiate(Resources.Load("boss_nose")) as GameObject;
        nose.transform.position = new Vector3(30,3,-1);


        float fXValue = 33.0f;

        int iBossParts = iWhatWaveIsIt/10 + 1;
        for (int t = 0; t < iBossParts; t++)
        {
            int iRoll = Random.Range(0, 2);
            switch (iRoll)
            {
                case 0:
                    //two tall
                    MakeBossBody(new Vector3(fXValue, 4, -1), nose, false);
                    MakeBossBody(new Vector3(fXValue, 2, -1), nose, true);
                    break;

                case 1:
                    //three tall
                    MakeBossBody(new Vector3(fXValue, 3, -1), nose, false);
                    MakeBossBody(new Vector3(fXValue, 1, -1), nose, true);
                    MakeBossBody(new Vector3(fXValue, 5, -1), nose, false);
                    break;
            }
            fXValue += 4.0f;
        }

        ActiveBoss = nose;
    }

    private GameObject MakeBossBody( Vector3 vLoc, GameObject nose, bool bBottomPart)
    {
        GameObject body = Instantiate(Resources.Load("boss_body_0" + Random.Range(1,4).ToString() )) as GameObject;
        body.transform.position = vLoc;
        body.transform.parent = nose.transform;

        BossNose bn = nose.GetComponent<BossNose>();

        GameObject turret = null;

        turret = Instantiate(Resources.Load("boss_turret")) as GameObject;
        turret.transform.position = new Vector3(vLoc.x - 1.5f, vLoc.y + 0.5f, -1.5f);
        bn.AttachGunToMe(turret);

        turret = Instantiate(Resources.Load("boss_turret")) as GameObject;
        turret.transform.position = new Vector3(vLoc.x + 1.5f, vLoc.y + 0.5f, -1.5f);
        bn.AttachGunToMe(turret);


        if (bBottomPart)
        {
            turret = Instantiate(Resources.Load("boss_bomb_hatch")) as GameObject;
            turret.transform.position = new Vector3(vLoc.x - 1.5f, vLoc.y - 0.5f, -1.5f);
            bn.AttachGunToMe(turret);

            turret = Instantiate(Resources.Load("boss_bomb_hatch")) as GameObject;
            turret.transform.position = new Vector3(vLoc.x + 1.5f, vLoc.y - 0.5f, -1.5f);
            bn.AttachGunToMe(turret);
        }
        else
        {
            turret = Instantiate(Resources.Load("boss_turret")) as GameObject;
            turret.transform.position = new Vector3(vLoc.x - 1.5f, vLoc.y - 0.5f, -1.5f);
            bn.AttachGunToMe(turret);

            turret = Instantiate(Resources.Load("boss_turret")) as GameObject;
            turret.transform.position = new Vector3(vLoc.x + 1.5f, vLoc.y - 0.5f, -1.5f);
            bn.AttachGunToMe(turret);
        }

        return body;
    }

    private void SpawnWave1(Vector3 vOldBlockPos)
    {
        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        //spawn variant block
        if (Random.value > 0.9)
        {
            iBlockID = 1;
        }
        else if (Random.value > 0.75f )
        {
            bMakeBuilding = true;
        }

        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }

        if (iBlockCountThisWave > 40)
            IncrementWave();
    }

    private void SpawnWave2(Vector3 vOldBlockPos)
    {
        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        bool bMakeEnemy = false;
        bool bMakeCagedAlly = false;

        //spawn variant block
        if (Random.value > 0.95)
        {
            iBlockID = 1;
        }
        else if (Random.value > 0.8f )
        {
            bMakeBuilding = true;
        }

        //make caged x% of the time even if there's a building
        float fAlly = GetAllySpawnRate();
        if (Random.value > fAlly)
        {
            bMakeCagedAlly = true;
        }
        else if (!bMakeBuilding && iBlockID == 0 && Random.value > 0.9)
        {
            bMakeEnemy = true;
        }
        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }
        if (bMakeCagedAlly)
        {
            switch (Random.Range(1, 3))
            {
                case 1:
                    SpawnAlly("CagedCrab", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 2:
                    SpawnAlly("CagedBlood", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
            }
        }
        if (bMakeEnemy)
        {
//            Vector3 vJetSpawn = newBlockPosition;
//            vJetSpawn.x = 70.0f;
//            vJetSpawn.y = 2.0f + Random.value * 4.0f;
//            SpawnActor("enemy_jet", vJetSpawn, 3.5f);

            SpawnActor("enemy_spike_wall", newBlockPosition, 1.5f);
        }

        if (iBlockCountThisWave > 80)
            IncrementWave();

    }

    private void SpawnWave3(Vector3 vOldBlockPos)
    {
        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        bool bMakeEnemy = false;
        bool bMakeCagedAlly = false;

        //spawn variant block
        if (Random.value > 0.95)
        {
            iBlockID = 1;
        }
        else if (Random.value > 0.8f)
        {
            bMakeBuilding = true;
        }

        //make caged x% of the time even if there's a building
        float fAlly = GetAllySpawnRate();
        if (Random.value > fAlly)
        {
            bMakeCagedAlly = true;
        }
        else if (iBlockID == 0 && Random.value > 0.85)
        {
            bMakeEnemy = true;
        }
        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }
        if (bMakeCagedAlly)
        {
            switch (Random.Range(1, 5))
            {
                case 1:
                    SpawnAlly("CagedCrab", newBlockPosition, Random.value * 2.0f + 2.5f);
                    break;
                case 2:
                    SpawnAlly("CagedBlood", newBlockPosition, Random.value * 2.0f + 2.5f);
                    break;
                case 3:
                    SpawnAlly("CagedBee", newBlockPosition, Random.value * 2.0f + 2.5f);
                    break;
                case 4:
                    SpawnAlly("CagedPoot", newBlockPosition, Random.value * 2.0f + 2.5f);
                    break;
            }
        }
        if (bMakeEnemy)
        {
            switch (Random.Range(1, 3))
            {
                case 1:
                    if (bMakeBuilding) //no spikewall on top of building
                        SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    else
                        SpawnActor("enemy_spike_wall", newBlockPosition, 1.5f);
                    break;
                case 2:
                    SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    break;
            }
        }


        if (iBlockCountThisWave > 100)
            IncrementWave();
    }

    private void SpawnWave4(Vector3 vOldBlockPos)
    {
        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        bool bMakeEnemy = false;
        bool bMakeCagedAlly = false;

        //spawn variant block
        if (Random.value > 0.9)
        {
            iBlockID = 1;
        }
        else if (Random.value > 0.8f)
        {
            bMakeBuilding = true;
        }

        //make caged x% of the time even if there's a building
        float fAlly = GetAllySpawnRate();
        if (Random.value > fAlly)
        {
            bMakeCagedAlly = true;
        }
        else if (iBlockID == 0 && Random.value > 0.85)
        {
            bMakeEnemy = true;
        }
        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }
        if (bMakeCagedAlly)
        {
            switch (Random.Range(1, 6))
            {
                case 1:
                    SpawnAlly("CagedCrab", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 2:
                    SpawnAlly("CagedBlood", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 3:
                    SpawnAlly("CagedBee", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 4:
                    SpawnAlly("CagedPoot", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 5:
                    SpawnAlly("CagedFlappy", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
            }
        }
        if (bMakeEnemy)
        {
            switch (Random.Range(1, 4))
            {
                case 1:
                    if (bMakeBuilding) //no spikewall on top of building
                        SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    else
                        SpawnActor("enemy_spike_wall", newBlockPosition, 1.5f);
                    break;
                case 2:
                    SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    break;
                case 3:
                    Vector3 vHelispawn = newBlockPosition;
                    vHelispawn.x = -12.0f;
                    vHelispawn.y = 4.0f + Random.value*2.0f;
                    SpawnActor("enemy_chopper", vHelispawn, 0.0f);
                    break;
            }
        }

        if (iBlockCountThisWave > 100)
            IncrementWave();
    }

    private void SpawnWave5(Vector3 vOldBlockPos)
    {
        bIsBonusStage = true;

        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        bool bMakeCagedAlly = false;

        //spawn variant block
        if (Random.value > 0.9)
        {
            iBlockID = 2;
        }
        else if (Random.value > 0.5f)
        {
            bMakeBuilding = true;
        }

        //make caged x% of the time even if there's a building
        float fAlly = GetAllySpawnRate();
        fAlly -= 0.1f;
        if (Random.value > fAlly)
        {
            bMakeCagedAlly = true;
        }
        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }
        if (bMakeCagedAlly)
        {
            switch (Random.Range(1, 6))
            {
                case 1:
                    SpawnAlly("CagedCrab", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 2:
                    SpawnAlly("CagedBlood", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 3:
                    SpawnAlly("CagedBee", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 4:
                    SpawnAlly("CagedPoot", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 5:
                    SpawnAlly("CagedFlappy", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
            }
        }

        if (iBlockCountThisWave > 100)
            IncrementWave();
    }

    private void SpawnWave6(Vector3 vOldBlockPos)
    {
        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        bool bMakeEnemy = false;
        bool bMakeCagedAlly = false;

        //spawn variant block
        if (Random.value > 0.9)
        {
            iBlockID = 1;
        }
        else if (Random.value > 0.8f)
        {
            bMakeBuilding = true;
        }

        //make caged x% of the time even if there's a building
        float fAlly = GetAllySpawnRate();
        if (Random.value > fAlly)
        {
            bMakeCagedAlly = true;
        }
        else if (iBlockID == 0 && Random.value > 0.85)
        {
            bMakeEnemy = true;
        }
        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }
        if (bMakeCagedAlly)
        {
            switch (Random.Range(1, 7))
            {
                case 1:
                    SpawnAlly("CagedCrab", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 2:
                    SpawnAlly("CagedBlood", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 3:
                    SpawnAlly("CagedBee", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 4:
                    SpawnAlly("CagedPoot", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 5:
                    SpawnAlly("CagedFlappy", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 6:
                    SpawnAlly("CagedMouth", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
            }
        }
        if (bMakeEnemy)
        {
            switch (Random.Range(1, 6))
            {
                case 1:
                    if (bMakeBuilding) //no spikewall on top of building
                        SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    else
                        SpawnActor("enemy_spike_wall", newBlockPosition, 1.5f);
                    break;
                case 2:
                    SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    break;
                case 3:
                    Vector3 vHelispawn = newBlockPosition;
                    vHelispawn.x = -12.0f;
                    vHelispawn.y = 4.0f + Random.value * 2.0f;
                    SpawnActor("enemy_chopper", vHelispawn, 0.0f);
                    break;
                case 4:
                    SpawnActor("enemy_robot", newBlockPosition, 3.5f);
                    break;
                case 5:
                    SpawnActor("enemy_robot", newBlockPosition, 3.5f);
                    break;
            }
        }

        if (iBlockCountThisWave > 120)
            IncrementWave();
    }

    private void SpawnWave7(Vector3 vOldBlockPos)
    {
        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        bool bMakeEnemy = false;
        bool bMakeCagedAlly = false;

        //spawn variant block
        if (Random.value > 0.9)
        {
            iBlockID = 1;
        }
        else if (Random.value > 0.8f)
        {
            bMakeBuilding = true;
        }

        //make caged x% of the time even if there's a building
        float fAlly = GetAllySpawnRate();
        if (Random.value > fAlly)
        {
            bMakeCagedAlly = true;
        }
        else if (iBlockID == 0 && Random.value > 0.85)
        {
            bMakeEnemy = true;
        }
        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }
        if (bMakeCagedAlly)
        {
            switch (Random.Range(1, 7))
            {
                case 1:
                    SpawnAlly("CagedCrab", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 2:
                    SpawnAlly("CagedBlood", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 3:
                    SpawnAlly("CagedBee", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 4:
                    SpawnAlly("CagedPoot", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 5:
                    SpawnAlly("CagedFlappy", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 6:
                    SpawnAlly("CagedMouth", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
            }
        }
        if (bMakeEnemy)
        {
            switch (Random.Range(1, 7))
            {
                case 1:
                    if (bMakeBuilding) //no spikewall on top of building
                        SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    else
                        SpawnActor("enemy_spike_wall", newBlockPosition, 1.5f);
                    break;
                case 2:
                    SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    break;
                case 3:
                    Vector3 vHelispawn = newBlockPosition;
                    vHelispawn.x = -12.0f;
                    vHelispawn.y = 4.0f + Random.value * 2.0f;
                    SpawnActor("enemy_chopper", vHelispawn, 0.0f);
                    break;
                case 4:
                    SpawnActor("enemy_robot", newBlockPosition, 3.5f);
                    break;
                case 5:
                    SpawnActor("enemy_mortar", newBlockPosition, 3.5f);
                    break;
                case 6:
                    Vector3 vJetSpawn = newBlockPosition;
                    vJetSpawn.x = 70.0f;
                    vJetSpawn.y = 1.5f + Random.value * 4.5f;
                    SpawnActor("enemy_jet", vJetSpawn, 0.0f);
                    break;
            }
        }

        if (iBlockCountThisWave > 120)
            IncrementWave();
    }

    private void SpawnWave8OrHigher(Vector3 vOldBlockPos)
    {
        int iMod = iWhatWaveIsIt%5;
        if (iMod == 0)
        {
            SpawnHighEndBonusStage(vOldBlockPos);
        }
        else if( iMod == 4)
        {
            SpawnBossStage(vOldBlockPos);
        }
        else
        {
            SpawnHighEndRegularStage(vOldBlockPos);
        }
    }

    private void SpawnHighEndRegularStage(Vector3 vOldBlockPos)
    {
        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        bool bMakeEnemy = false;
        bool bMakeCagedAlly = false;

        //spawn variant block
        if (Random.value > 0.9)
        {
            iBlockID = 1;
        }
        else if (Random.value > 0.8f)
        {
            bMakeBuilding = true;
        }

        //make caged x% of the time even if there's a building
        float fAlly = GetAllySpawnRate();
        if (Random.value > fAlly)
        {
            bMakeCagedAlly = true;
        }
        else if (iBlockID == 0)
        {
            float fEnemyChance = 0.85f - (0.04f*(iWhatWaveIsIt-7));
            if (fEnemyChance < 0.3f)
                fEnemyChance = 0.3f;

            if( Random.value > fEnemyChance)
                bMakeEnemy = true;
        }
        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }
        if (bMakeCagedAlly)
        {
            switch (Random.Range(1, 8))
            {
                case 1:
                    SpawnAlly("CagedCrab", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 2:
                    SpawnAlly("CagedBlood", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 3:
                    SpawnAlly("CagedBee", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 4:
                    SpawnAlly("CagedPoot", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 5:
                    SpawnAlly("CagedFlappy", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 6:
                    SpawnAlly("CagedMouth", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 7:
                    SpawnAlly("CagedPurpleonian", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
            }
        }
        if (bMakeEnemy)
        {
            switch (Random.Range(1, 7))
            {
                case 1:
                    if (bMakeBuilding) //no spikewall on top of building
                        SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    else
                        SpawnActor("enemy_spike_wall", newBlockPosition, 1.5f);
                    break;
                case 2:
                    SpawnActor("enemy_tank", newBlockPosition, 1.5f);
                    break;
                case 3:
                    Vector3 vHelispawn = newBlockPosition;
                    vHelispawn.x = -12.0f;
                    vHelispawn.y = 4.0f + Random.value * 2.0f;
                    SpawnActor("enemy_chopper", vHelispawn, 0.0f);
                    break;
                case 4:
                    SpawnActor("enemy_robot", newBlockPosition, 3.5f);
                    break;
                case 5:
                    SpawnActor("enemy_mortar", newBlockPosition, 3.5f);
                    break;
                case 6:
                    Vector3 vJetSpawn = newBlockPosition;
                    vJetSpawn.x = 70.0f;
                    vJetSpawn.y = 2.0f + Random.value * 4.0f;
                    SpawnActor("enemy_jet", vJetSpawn, 3.5f);
                    break;
            }
        }

        if (iBlockCountThisWave > 120 + (iWhatWaveIsIt - 7 * 10))
            IncrementWave();
    
    }

    private void SpawnBossStage(Vector3 vOldBlockPos)
    {
        //if this flag is false, create the boss
        if( bIsBossStage == false)
            MakeBoss();

        bIsBossStage = true;

        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        bool bMakeCagedAlly = false;

        //spawn variant block
        if (Random.value > 0.95)
        {
            iBlockID = 2;
        }
        else if (Random.value > 0.95f)
        {
            bMakeBuilding = true;
        }

        //make caged x% of the time even if there's a building
        float fAlly = GetAllySpawnRate();
        if (Random.value > fAlly)
        {
            bMakeCagedAlly = true;
        }
        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }
        if (bMakeCagedAlly)
        {
            switch (Random.Range(1, 8))
            {
                case 1:
                    SpawnAlly("CagedCrab", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 2:
                    SpawnAlly("CagedBlood", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 3:
                    SpawnAlly("CagedBee", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 4:
                    SpawnAlly("CagedPoot", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 5:
                    SpawnAlly("CagedFlappy", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 6:
                    SpawnAlly("CagedMouth", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 7:
                    SpawnAlly("CagedPurpleonian", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
            }
        }

        //if the boss is dead, increment the wave
        if( ActiveBoss == null )
            IncrementWave();
        
    }

    private void SpawnHighEndBonusStage(Vector3 vOldBlockPos)
    {
        bIsBonusStage = true;

        //decide which block is next;
        int iBlockID = 0;
        bool bMakeBuilding = false;
        bool bMakeCagedAlly = false;

        //spawn variant block
        if (Random.value > 0.9)
        {
            iBlockID = 2;
        }
        else if (Random.value > 0.5f)
        {
            bMakeBuilding = true;
        }

        //make caged x% of the time even if there's a building
        float fAlly = GetAllySpawnRate();
        fAlly -= 0.1f;
        if (Random.value > fAlly)
        {
            bMakeCagedAlly = true;
        }
        Vector3 newBlockPosition = SpawnNewBlock(iBlockID, vOldBlockPos);

        if (bMakeBuilding)
        {
            MakeBuilding(newBlockPosition);
        }
        if (bMakeCagedAlly)
        {
            switch (Random.Range(1, 8))
            {
                case 1:
                    SpawnAlly("CagedCrab", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 2:
                    SpawnAlly("CagedBlood", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 3:
                    SpawnAlly("CagedBee", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 4:
                    SpawnAlly("CagedPoot", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 5:
                    SpawnAlly("CagedFlappy", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 6:
                    SpawnAlly("CagedMouth", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
                case 7:
                    SpawnAlly("CagedPurpleonian", newBlockPosition, Random.value * 2.0f + 3.5f);
                    break;
            }
        }

        if (iBlockCountThisWave > 100)
            IncrementWave();
    }
}
