/**
     * Corutine
     * Return value type IEnumerator is because of "return waiting"
     */
    IEnumerator SpawnWaves()
    {
        yield return(new WaitForSeconds(startWait));

        while (true)
        {
            UpdateTextActualWave(levelCounterWave);

            for (int i = 0; i < (hazardCount + levelCounterWave); ++i)
            {
                Vector3 spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x),
                                                    spawnValues.y,
                                                    spawnValues.z);
                Quaternion spawnRotation = Quaternion.Euler(0.0f, 180.0f, 0.0f);

                int spaceObjProb = Random.Range(0, 99);

                if (spaceObjProb < (55 - levelCounterWave))
                {
                    GameObject tmpAsteroid = null;

                    int asterObjProb = Random.Range(1, 99);

                    if (asterObjProb <= 33)
                    {
                        tmpAsteroid = Instantiate(refHazardType1, spawnPosition, spawnRotation) as GameObject;
                    }
                    else if (asterObjProb > 33 && asterObjProb <= 66)
                    {
                        tmpAsteroid = Instantiate(refHazardType2, spawnPosition, spawnRotation) as GameObject;
                    }
                    else
                    {
                        tmpAsteroid = Instantiate(refHazardType3, spawnPosition, spawnRotation) as GameObject;
                    }

                    AsteroidController astroController = tmpAsteroid.GetComponent <AsteroidController>();
                    if (astroController != null)
                    {
                        if (astroController.InitAteroid(levelCounterWave))
                        {
                            // run the ship (!!)
                            tmpAsteroid.SetActive(true);
                        }
                        else
                        {
                            Destroy(tmpAsteroid);
                            Debug.LogWarning("LEVEL >> Unable to init asteroid");
                        }
                    }
                    else
                    {
                        Destroy(tmpAsteroid);
                        Debug.LogWarning("LEVEL >> Unable to obtain reference to asteroid");
                    }
                }
                else
                {
                    GameObject        tmpEnemy = null;
                    eScoreObjectTypes tmpEnemyType;

                    int enemyObjProb = Random.Range(0, 99);

                    if (enemyObjProb < (55 - levelCounterWave))
                    {
                        tmpEnemy     = Instantiate(refEnemyShipUWingBasic, spawnPosition, spawnRotation) as GameObject;
                        tmpEnemyType = eScoreObjectTypes.EnemyUWingBasic;
                    }
                    else
                    {
                        tmpEnemy     = Instantiate(refEnemyShipUWingMedium, spawnPosition, spawnRotation) as GameObject;
                        tmpEnemyType = eScoreObjectTypes.EnemyUWingMedium;
                    }

                    EnemyController enemyController = tmpEnemy.GetComponent <EnemyController>();
                    if (enemyController != null)
                    {
                        if (enemyController.InitEnemy(tmpEnemyType, levelCounterWave))
                        {
                            // run the ship (!!)
                            tmpEnemy.SetActive(true);
                        }
                        else
                        {
                            Destroy(tmpEnemy);
                            Debug.LogWarning("LEVEL >> Unable to init enemy ship");
                        }
                    }
                    else
                    {
                        Destroy(tmpEnemy);
                        Debug.LogWarning("LEVEL >> Unable to obtain reference to enemy ship");
                    }
                }

                // 4% probability of health bonus
                // --> generate health bonus ONLY if actualHealth is less then max
                if (!RuntimeContext.GetInst().nesActPlayer.isActHealthMax &&
                    Random.Range(0, 99) <= (4 - (levelCounterWave / 10)))
                {
                    spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x),
                                                spawnValues.y,
                                                spawnValues.z);

                    Instantiate(refBonusHealth, spawnPosition, spawnRotation);
                }
                // 8% probability of shield bonus
                // --> generate shield bonus ONLY if actualShield is less then max
                else if (!RuntimeContext.GetInst().nesActPlayer.isActShieldMax &&
                         Random.Range(0, 99) <= (8 - (levelCounterWave / 8)))
                {
                    spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x),
                                                spawnValues.y,
                                                spawnValues.z);

                    Instantiate(refBonusShield, spawnPosition, spawnRotation);
                }
                // 12% probability of energy bonus
                else if (Random.Range(0, 99) <= (12 - (levelCounterWave / 6)))
                {
                    spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x),
                                                spawnValues.y,
                                                spawnValues.z);

                    Instantiate(refBonusEnergy, spawnPosition, spawnRotation);
                }
                // 3% probability of generating better ammo type of current weapon type
                if ((RuntimeContext.GetInst().nesActPlayer.actAmmoType
                     < RuntimeContext.GetInst().nesActPlayer.topAmmoType) &&
                    Random.Range(0, 99) <= 3)
                {
                    // --> generate new ammo type ONLY if actualAmmoType is less then max ammo type of the selected ship

                    spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x),
                                                spawnValues.y,
                                                spawnValues.z);

                    if (RuntimeContext.GetInst().nesActPlayer.actAmmoType <= Weapon.eAmmoTypes.Better)
                    {
                        // ADVANCED AMMO
                        Instantiate(refFireModeAdvanced, spawnPosition, spawnRotation);
                    }
                    else if (RuntimeContext.GetInst().nesActPlayer.actAmmoType <= Weapon.eAmmoTypes.Advanced)
                    {
                        // HARDCORE AMMO
                        Instantiate(refFireModeHardcore, spawnPosition, spawnRotation);
                    }
                    else if (RuntimeContext.GetInst().nesActPlayer.actAmmoType <= Weapon.eAmmoTypes.Hardcore)
                    {
                        // ARMAGEDON AMMO
                        Instantiate(refFireModeArmagedon, spawnPosition, spawnRotation);
                    }
                    else
                    {
                        // you got the best of the best ammo type
                    }
                }
                // 1% probability of generating better weapon type
                if ((RuntimeContext.GetInst().nesActPlayer.actAmmoType
                     >= (RuntimeContext.GetInst().nesActPlayer.topAmmoType - 1)) &&
                    (RuntimeContext.GetInst().nesActPlayer.actWeaponType
                     < (RuntimeContext.GetInst().nesActPlayer.topWeaponType)) &&
                    Random.Range(0, 99) <= 1)
                {
                    // --> generate new weapon type ONLY if actualAmmoType is at least second best ammo type of ship
                    // --> generate new weapon type ONLY if actualWeaponType is less top weapons of the ship

                    spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x),
                                                spawnValues.y,
                                                spawnValues.z);

                    if (RuntimeContext.GetInst().nesActPlayer.actWeaponType <= WeaponSystems.eWeaponTypes.ForwardBasic)
                    {
                        // FORWARD BASIC
                        Instantiate(refWeaponForwardBetter, spawnPosition, spawnRotation);
                    }
                    else if (RuntimeContext.GetInst().nesActPlayer.actWeaponType <= WeaponSystems.eWeaponTypes.ForwardBetter)
                    {
                        // FORWARD BETTER
                        Instantiate(refWeaponForwardAdvanced, spawnPosition, spawnRotation);
                    }
                    else if (RuntimeContext.GetInst().nesActPlayer.actWeaponType <= WeaponSystems.eWeaponTypes.ForwardAdvanced)
                    {
                        // DIRECTIONAL BASIC
                        Instantiate(refWeaponDirectionalBasic, spawnPosition, spawnRotation);
                    }
                    else
                    {
                        // you got the best of the best weapon type
                    }
                }

                if (flagGameOver || flagShipDestroyed)
                {
                    break;
                }

                float realWait = spawnWait - (0.1f * levelCounterWave);
                if (realWait < 0.5f)
                {
                    realWait = 0.5f;
                }

                yield return(new WaitForSeconds(realWait));
            }

            if (flagGameOver)
            {
                // text "Game Over" is already shown

                yield return(new WaitForSeconds(gameOverWait));

                // show text "press `R` for restart, activate listening to key R
                RestartLevel();
                break;
            }
            else if (flagShipDestroyed)
            {
                int counter = shipDestroyedWaitCount;
                while (counter > 0)
                {
                    // show text "Your ship was destroyed..."
                    UpdateTextShipDestroyed(counter);
                    yield return(new WaitForSeconds(1.0f));

                    counter -= 1;
                }
                // clear text "Your ship was destroyed..."
                UpdateTextShipDestroyed(0);

                InitLevel();
                break;
            }
            else
            {
                levelCounterWave += 1;

                int counter = wavesWaitCount;
                while (counter > 0)
                {
                    // show text "prepare for next wave X"
                    UpdateTextNewWaveInfo(counter);
                    yield return(new WaitForSeconds(1.0f));

                    counter -= 1;
                }
                // clear text "prepare for next wave X"
                UpdateTextNewWaveInfo(0);
            }
        }
    }