StartCoroutine within StartCoroutine with WaitForSeconds () make weird behavioral process flow?

Hi, guys, I have a problem, but it kinda hard to explain, so I will go with the title and images instead, here we go:

You see, I’m trying to make a script named ‘HellBulletManager.cs’

They are almost complete, but have some bugs/unexpected results in some parts…

So, here my observation of the flow while debugging, and I found out the problem, but I don’t know how will I fix this:
(For example: The bug starts when I set the linearAmount atleast 3 or more and together with delayLinear more than 0…) Zoom the image to see where are the problem…

The complete script is here; the code is long, but I just want you to focus on the image above: (and I recommend (if you want) to download the project I attached in zip file below)

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class BulletModification {
    [Header("Modify Cluster:")]
    public float startSpeed = 1f;
    public enum generateAcceleration {
        byUnit,
        byPercentage
    } public generateAcceleration accelerationType;
    public float acceleration;
    public float speedRange = 1f;
    public int damage = 20;
    public float lifeSpan = 5f;
}

[System.Serializable]
public class TransformFormula {
    //[Header("Stir Bullet:")]
    [Header("Mirror Bullet:")]
    [Tooltip("0 means all copies will be on sync, beyond that will make delay offset speed; 100 makes the last delay copy to stationary, 200 makes go to opposite direction. Set delayAmount above 0 to see result")]
    [Range(0,200)] public float speedOffset;
    [Tooltip("Number of clone bullets for offset speed. Set speedOffset to work with")]
    [Range(0,3)] public int delayAmount;
    [Tooltip("Number of clone bullets shoot parallel to each other")]
    [Range(1,128)] public int linearAmount = 1;
    public enum spaceType {
        byUnitAway,
        byOverallWidth
    }; [Tooltip("How parallel bullets take up space")] public spaceType areaOccupy;
    [Tooltip("The amount of parallel bullets away each other or their general width as one group")]
    public float spacingValue;
    [Tooltip("Number in seconds; parallel from the middle will start immediately, then delay start to the next neighbor line")]
    [Range(0,20)] public float delayLinear;

    [Header("Spray Bullet:")]
    [Tooltip("Spread the rays exact to spreadAngle")]
    public bool angleFilled;
    [Tooltip("The degree angle of an arc be made for rayAmount")]
    [Range(0,360)] public float spreadAngle;
    [Tooltip("The number of copy bullet as rays restricted by spreadAngle")]
    [Range(1,32)] public int rayAmount = 1;
    [Tooltip("The radius offset of the center of the ray")]
    public float spawnOffsetRadius;
    [Tooltip("Number in seconds; the first ray will start immediately, then delay start to the next neighbor ray")]
    [Range(0,20)] public float delayRay;
}

[System.Serializable]
public class TransformPattern {
    [Header("Bullet Patterns:")]
    public Vector2 respawnOffset;
    [Tooltip("Sliding the respawn origin of bullet sideward from left to right length-based over given duration")]
    public float linearMagnitude;
    public enum linearMotionType{
        Linear,
        Wave
    }; public linearMotionType linearFlow;
    public enum linearDirection{
        left_Right,
        right_Left,
        center_Right,
        center_Left
    }; public linearDirection linearPoint;
    [Tooltip("Move with one direction or play ping pong")]
    public bool pingPong = true;
    [Tooltip("The spin progress over given duration; Note: clinch with 'Linear Magnitude'")]
    public float spinMotion;
    public enum spinMotionType {
        Linear,
        Wave
    }; public spinMotionType spinFlow;
    public enum spinDirection{
        left_Right,
        right_Left,
        center_Right,
        center_Left
    }; public spinDirection spinPoint;
    [Tooltip("Merry-go-around or not")]
    public bool swingBack = false;
    [Tooltip("As it says; offset vertically and/or horizontally -_-")]
    public Vector2 masterOffset;
    [Tooltip("Offset overall rotation with parent object, but only in z-axis, any problem with that?! Note: doesn't spin over time, use spinMotion or bullet formula instead, or use emitter and make it spin via other script (or animation?)")]
    public float masterRotation;
    [Tooltip("Offset rotation disregarding linear orientation")]
    public float offsetRotation;
}

[System.Serializable]
public class TimeLine {
    [Header("Bullet Time:")]
    [Tooltip("Ready to execute one time once timeCode reaches")]
    public bool active = true;
    [Tooltip("Time in seconds to start the bullet party")]
    public float start = 0f;
    [Tooltip("Time in seconds to finish one pattern")]
    public float duration = 1f;
    [Tooltip("Multiply the duration to continue executing the pattern")]
    public int execute = 1;
    [Tooltip("Number of bullet emits in one span of duration harmonizing with pattern; Note: minimum fire rate will not less than 0.01 sec, or else actionPulse will be deducted")]
    public int actionPulse = 1;

    [Header("Bullet Element:")]
    [Tooltip("To certainly choose none, input less than 0")]
    public int pattern;
    [Tooltip("To certainly choose none, input less than 0")]
    public int formula;
    [Tooltip("To certainly choose none, input less than 0")]
    public int modification;
}

[System.Serializable]
public class BulletSpawn {
    [Tooltip("Your title, definition, description, speech, message, or whatever; :Optional:")]
    public string name;
    public GameObject bulletPrefab;
    [Tooltip("Spawn point: object attached with this script act as default emitter, if leave empty")]
    public List<GameObject> emitter;
    public List<TimeLine> bulletTime;
}

[System.Serializable]
public class BulletFlow {
    /* Note: for the future viewer; why no 'public bool active'?
     * No need, I found it useless; use/code timeHalt + reset = inactive (if you want to extend this code)... */
    public bool reset;
    public bool timeHalt;
    public bool looping;
    [Tooltip("Set loopQuantity to zero for infinite loop")]
    public int loopQuantity;
    [Tooltip("What for? Delay the start time of timeCode")]
    public float delayStart;
    [Tooltip("Behold the time holder! NOLI ME TANGERE, if you don't know me what I am for")]
    public float timeCode;
}

public class ProcessResults {
    public bool patternExist = false;
    public Vector3 totalPosition = Vector3.zero;
    public Quaternion totalRotation = Quaternion.identity;

    public bool formulaExist = false;
    public bool modificationExist = false;
    public int j, k, l = 0;

    public bool primaryRay = false;
    public float raySpacing = 0;

    public bool primaryLinear = false;
    public float linearSpacing = 0;

    public bool primaryBullet = false;
    public float baseSpeed, baseAcceleration, baseMaxSpeed = 0f;
}

public class HellBulletManager : MonoBehaviour {

    [Header("Bullet Manager:")]
    public BulletFlow bulletRush;
    public float _totalDuration;
    private float _loopQuantity;
    public List<BulletSpawn> hellBullets;

    [Header("Bullet Transform:")]
    public List<TransformPattern> bulletPattern = new List<TransformPattern> ();

    [Header("Bullet Properties:")]
    public List<TransformFormula> bulletFormula;
    public List<BulletModification> bulletModification;

    // Use this for initialization
    void Start () {
        _totalDuration = 0f;
        _loopQuantity = bulletRush.loopQuantity;

        if (bulletFormula.Count > 0)
            foreach (TransformFormula thisFormula in bulletFormula)
            {
                //using [Range(min,max)] and min set to 1, but the default stay to 0; this is use to fix the min when game starts
                if (thisFormula.linearAmount == 0)
                    thisFormula.linearAmount = 1;
                if (thisFormula.rayAmount == 0)
                    thisFormula.rayAmount = 1;
            }
    }

    void FixedUpdate () {
        if (bulletRush.reset)
        {
            bulletRush.reset = !bulletRush.reset;
            bulletRush.timeCode = 0f;

            foreach (BulletSpawn thisBullet in hellBullets)
            {
                foreach (TimeLine thisTime in thisBullet.bulletTime)
                {
                    thisTime.active = true;
                }
            }
        }

        if (bulletRush.timeHalt)
        {
            return;
        }

        if (bulletRush.delayStart > 0f)
        {
            bulletRush.delayStart -= Time.deltaTime;
            if (bulletRush.delayStart < 0f)
                bulletRush.delayStart = 0f;
        }
        else
        {
            bulletRush.timeCode += Time.deltaTime;
        }

        //Make sure taken out all List with null bulletSpawn.bulletPrefab --- Lambda syntax 'COOL AND POWERFUL' they say!
        hellBullets.RemoveAll (BulletSpawn => BulletSpawn.bulletPrefab == null);
        if (hellBullets.Count > 0)
        {
            foreach (BulletSpawn thisBullet in hellBullets)
            {
                if (thisBullet.bulletTime.Count > 0)
                {
                    foreach (TimeLine thisTime in thisBullet.bulletTime)
                    {
                        if (thisTime.duration > 0f && _totalDuration < thisTime.start + (thisTime.duration * thisTime.execute))
                        {
                            _totalDuration = thisTime.start + (thisTime.duration * thisTime.execute);
                        }

                        if (thisTime.active && bulletRush.timeCode >= thisTime.start && thisTime.duration > 0f)
                        {
                            thisTime.active = false;
                            float pulseGap = thisTime.duration / thisTime.actionPulse;
                            if (pulseGap < 0.01f) {
                                thisTime.actionPulse = Mathf.FloorToInt(thisTime.duration / 0.01f);

                                if (thisTime.actionPulse == 0)
                                    return;

                                pulseGap = thisTime.duration / thisTime.actionPulse;
                            }
                            StartCoroutine (startRespawn (thisBullet.bulletPrefab, thisBullet.emitter, thisTime.duration, pulseGap, thisTime.execute, thisTime.pattern, thisTime.formula, thisTime.modification));
                        }
                    }
                }
            }
        }

        if (bulletRush.timeCode >= _totalDuration)
        {
            if (bulletRush.looping)
            {
                if (bulletRush.loopQuantity > 0)
                    bulletRush.loopQuantity -= 1;

                if (bulletRush.loopQuantity > 0 || _loopQuantity == 0)
                {
                    bulletRush.reset = true;
                }
                else
                {
                    bulletRush.timeHalt = true;
                    bulletRush.reset = true;
                }
            }
            else
            {
                bulletRush.timeHalt = true;
                bulletRush.reset = true;
            }
        }
    }

    IEnumerator startRespawn (GameObject bullet, List<GameObject> emitters, float duration, float fireRate, int execute, int pattern, int formula, int modification)
    {
        TransformPattern patternApply = new TransformPattern ();
        TransformFormula formulaApply = new TransformFormula ();
        BulletModification modApply = new BulletModification ();
        ProcessResults result = new ProcessResults ();

        float localTime = 0f;
        float readyFire = 0f;

        result.patternExist = false;
        //bool patternExist = false;
        patternApply.respawnOffset = Vector2.zero;
        Vector2 respawnOffset = Vector2.zero;
        patternApply.linearMagnitude = 0f;
        patternApply.linearFlow = TransformPattern.linearMotionType.Linear;
        patternApply.linearPoint = TransformPattern.linearDirection.left_Right;
        patternApply.pingPong = false;
        patternApply.spinMotion = 0f;
        patternApply.spinFlow = TransformPattern.spinMotionType.Linear;
        patternApply.spinPoint = TransformPattern.spinDirection.left_Right;
        patternApply.swingBack = false;
        patternApply.masterOffset = Vector2.zero;
        patternApply.masterRotation = 0f;
        patternApply.offsetRotation = 0f;

        result.formulaExist = false;
        //bool formulaExist = false;
        formulaApply.speedOffset = 0f;
        formulaApply.delayAmount = 0;
        formulaApply.linearAmount = 1;
        formulaApply.areaOccupy = TransformFormula.spaceType.byUnitAway;
        formulaApply.spacingValue = 0f;
        formulaApply.delayLinear = 0f;
        formulaApply.spreadAngle = 0f;
        formulaApply.rayAmount = 1;
        formulaApply.spawnOffsetRadius = 0f;
        formulaApply.delayRay = 0f;

        result.modificationExist = false;
        //bool modificationExist = false;
        modApply.startSpeed = 0f;
        modApply.accelerationType = BulletModification.generateAcceleration.byUnit;
        modApply.acceleration = 0f;
        modApply.speedRange = 0f;

        //The game will run but gives me a message error, I don't know where cause of this specifically, may here or above there? Error: ArgumentOutOfRangeException: Argument is out of range. Parameter name: index
        if (pattern >= 0 && pattern < bulletPattern.Count) { //Checking... if (bulletPattern[pattern] == null) never assigned 'patternApply = bulletPattern [pattern];'...
            result.patternExist = true;
            patternApply = bulletPattern [pattern];

            /*
            patternApply.respawnOffset = bulletPattern[pattern].respawnOffset;
            patternApply.linearMagnitude = bulletPattern[pattern].linearMagnitude;
            patternApply.linearFlow = bulletPattern[pattern].linearFlow;
            patternApply.linearPoint = bulletPattern[pattern].linearPoint;
            patternApply.pingPong = bulletPattern[pattern].pingPong;
            patternApply.spinMotion = bulletPattern[pattern].spinMotion;
            patternApply.spinFlow = bulletPattern[pattern].spinFlow;
            patternApply.spinPoint = bulletPattern[pattern].spinPoint;
            patternApply.swingBack = bulletPattern[pattern].swingBack;
            patternApply.masterOffset = bulletPattern[pattern].masterOffset;
            patternApply.masterRotation = bulletPattern[pattern].masterRotation;
            patternApply.offsetRotation = bulletPattern[pattern].offsetRotation;
            */
        }

        if (formula >= 0 && formula <= bulletFormula.Count - 1) { //if (bulletFormula.Exists(BulletSpawn => bulletFormula[formula])) /* <- Sample only: trying '.Exists' for alternatives, but give me some errors; I don't know really how to use it... or how about some '.Contain'? I don't know about it, please help me... THANKS */
            result.formulaExist = true;
            formulaApply = bulletFormula [formula];
        }

        if (modification >= 0 && modification <= bulletModification.Count - 1) { //if (bulletModification.Exists(bulletModification[modification]))
            result.modificationExist = true;
            modApply = bulletModification [modification];
        }

        //Transform bulletDirector;

        float motionPoint;
        Vector3 transformPosition = transform.position;
        float transformRotation = 0f;
        while (localTime < duration * execute && duration > 0f)
        {
            if (!bulletRush.timeHalt)
            {
                emitters.RemoveAll (GameObject => GameObject == null);

                if (result.patternExist)
                {
                    float respawnOffsetX = Random.Range (-bulletPattern[pattern].respawnOffset.x, bulletPattern[pattern].respawnOffset.x);
                    float respawnOffsetY = Random.Range (-bulletPattern[pattern].respawnOffset.y, bulletPattern[pattern].respawnOffset.y);
                    //patternApply.respawnOffset = new Vector2 (respawnOffsetX, respawnOffsetY);
                    respawnOffset = new Vector2 (respawnOffsetX, respawnOffsetY);
                }

                bool once = true;
                for (int i = 0; i < emitters.Count || once; i++, once = false)
                {
                    int inverse;

                    inverse = 0;
                    if (!patternApply.pingPong)
                    {
                        if ((patternApply.linearPoint == TransformPattern.linearDirection.left_Right ||
                            patternApply.linearPoint == TransformPattern.linearDirection.right_Left)
                            && Mathf.FloorToInt (localTime * (1f / duration)) % 2 == 1f)
                        {
                            inverse = 1;
                        }
                        else if ((patternApply.linearPoint == TransformPattern.linearDirection.center_Right ||
                            patternApply.linearPoint == TransformPattern.linearDirection.center_Left)
                            && Mathf.FloorToInt ((localTime * (1f / duration)) + 0.5f) % 2 == 1f)
                        {
                            inverse = 1;
                        }
                    }

                    motionPoint = 0f;
                    Vector3 linearOrientation;
                    if (emitters.Count == 0)
                    {
                        linearOrientation = new Vector3 (Mathf.Cos (Mathf.Deg2Rad * (transform.eulerAngles.z + patternApply.masterRotation)), Mathf.Sin (Mathf.Deg2Rad * (transform.eulerAngles.z + patternApply.masterRotation)), 0f);
                    }
                    else
                    {
                        linearOrientation = new Vector3 (Mathf.Cos(Mathf.Deg2Rad * (emitters[i].transform.eulerAngles.z + patternApply.masterRotation)), Mathf.Sin(Mathf.Deg2Rad * (emitters[i].transform.eulerAngles.z + patternApply.masterRotation)), 0f);
                    }

                    if (patternApply.linearFlow == TransformPattern.linearMotionType.Linear)
                    {
                        if (patternApply.linearPoint == TransformPattern.linearDirection.left_Right)
                        {
                            motionPoint = Mathf.PingPong ((localTime * patternApply.linearMagnitude * (1f / duration)) + (inverse * patternApply.linearMagnitude), patternApply.linearMagnitude) - (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.right_Left)
                        {
                            motionPoint = Mathf.PingPong ((localTime * patternApply.linearMagnitude * (1f / duration)) + (patternApply.linearMagnitude) + (inverse * patternApply.linearMagnitude), patternApply.linearMagnitude) - (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.center_Right)
                        {
                            motionPoint = Mathf.PingPong ((localTime * patternApply.linearMagnitude * (1f / duration)) + (patternApply.linearMagnitude * 0.5f) + (inverse * patternApply.linearMagnitude), patternApply.linearMagnitude) - (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.center_Left)
                        {
                            motionPoint = Mathf.PingPong ((localTime * patternApply.linearMagnitude * (1f / duration)) - (patternApply.linearMagnitude * 0.5f) + (inverse * patternApply.linearMagnitude), patternApply.linearMagnitude) - (patternApply.linearMagnitude * 0.5f);
                        }

                        if (!(System.Single.IsNaN (motionPoint) || System.Single.IsInfinity (motionPoint)))
                            transformPosition = motionPoint * linearOrientation;
                        else
                            transformPosition = Vector3.zero;
                    }
                    else if (patternApply.linearFlow == TransformPattern.linearMotionType.Wave)
                    {
                        if (patternApply.linearPoint == TransformPattern.linearDirection.left_Right)
                        {
                            motionPoint = Mathf.Sin (((localTime - (0.5f * duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.right_Left)
                        {
                            motionPoint = Mathf.Sin (((localTime + (0.5f * duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.center_Right)
                        {
                            motionPoint = Mathf.Sin (((localTime + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.center_Left)
                        {
                            motionPoint = Mathf.Sin (((localTime + (duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.linearMagnitude * 0.5f);
                        }

                        transformPosition = motionPoint * linearOrientation;
                    }
                    result.totalPosition = transformPosition + new Vector3 (patternApply.masterOffset.x, patternApply.masterOffset.y) + new Vector3 (respawnOffset.x, respawnOffset.y);// + new Vector3 (patternApply.respawnOffset.x, patternApply.respawnOffset.y);;

                    if (emitters.Count == 0)
                    {
                        result.totalPosition += transform.position;
                    }
                    else
                    {
                        result.totalPosition += emitters [i].transform.position;
                    }

                    int multiplier;

                    multiplier = 0;
                    inverse = 0;
                    if (!patternApply.swingBack)
                    {
                        if ((patternApply.spinPoint == TransformPattern.spinDirection.left_Right ||
                            patternApply.spinPoint == TransformPattern.spinDirection.right_Left)
                            && Mathf.FloorToInt (localTime * (1f / duration)) % 2 == 1f)
                        {
                            inverse = 1;
                        }
                        else if ((patternApply.spinPoint == TransformPattern.spinDirection.center_Right ||
                            patternApply.spinPoint == TransformPattern.spinDirection.center_Left)
                            && Mathf.FloorToInt ((localTime * (1f / duration)) + 0.5f) % 2 == 1f)
                        {
                            inverse = 1;
                        }
                        multiplier = Mathf.FloorToInt (localTime * (1f / duration));
                    }

                    motionPoint = 0f;
                    if (patternApply.spinFlow == TransformPattern.spinMotionType.Linear)
                    {
                        if (patternApply.spinPoint == TransformPattern.spinDirection.left_Right)
                        {
                            motionPoint = (Mathf.PingPong ((localTime * patternApply.spinMotion * (1f / duration)) + (patternApply.spinMotion) + (inverse * patternApply.spinMotion), patternApply.spinMotion) - (patternApply.spinMotion * 0.5f)) - (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.right_Left)
                        {
                            motionPoint = (Mathf.PingPong ((localTime * patternApply.spinMotion * (1f / duration)) + (inverse * patternApply.spinMotion), patternApply.spinMotion) - (patternApply.spinMotion * 0.5f)) + (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.center_Right)
                        {
                            motionPoint = (Mathf.PingPong ((localTime * patternApply.spinMotion * (1f / duration)) - (patternApply.spinMotion * 0.5f) + (inverse * patternApply.spinMotion), patternApply.spinMotion) - (patternApply.spinMotion * 0.5f)) - (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.center_Left)
                        {
                            motionPoint = (Mathf.PingPong ((localTime * patternApply.spinMotion * (1f / duration)) + (patternApply.spinMotion * 0.5f) + (inverse * patternApply.spinMotion), patternApply.spinMotion) - (patternApply.spinMotion * 0.5f)) + (multiplier * patternApply.spinMotion);
                        }

                        if (!(System.Single.IsNaN (motionPoint) || System.Single.IsInfinity (motionPoint)))
                            transformRotation = motionPoint;
                        else
                            transformRotation = 0f;
                    }
                    else if (patternApply.spinFlow == TransformPattern.spinMotionType.Wave)
                    {
                        if (patternApply.spinPoint == TransformPattern.spinDirection.left_Right)
                        {
                            motionPoint = (Mathf.Sin (((localTime + (0.5f * duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.spinMotion * 0.5f)) - (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.right_Left)
                        {
                            motionPoint = (Mathf.Sin (((localTime - (0.5f * duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.spinMotion * 0.5f)) + (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.center_Right)
                        {
                            motionPoint = (Mathf.Sin (((localTime + (duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.spinMotion * 0.5f)) - (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.center_Left)
                        {
                            motionPoint = (Mathf.Sin (((localTime + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.spinMotion * 0.5f)) + (multiplier * patternApply.spinMotion);
                        }

                        transformRotation = motionPoint;
                    }
                    result.totalRotation = Quaternion.Euler (0f, 0f, transformRotation + patternApply.masterRotation + patternApply.offsetRotation);

                    if (emitters.Count == 0)
                    {
                        result.totalRotation *= transform.rotation;
                    }
                    else
                    {
                        result.totalRotation *= emitters[i].transform.rotation;
                    }

                    if (readyFire <= localTime)
                    {
                        //Formulate the bullet if formula exist
                        if (result.formulaExist)
                        {
                            result.primaryLinear = true;
                            result.primaryRay = true;

                            result.baseSpeed = 0f;
                            result.baseAcceleration = 0f;
                            result.baseMaxSpeed = 0f;

                            result.linearSpacing = 0f;

                            if (formulaApply.linearAmount > 1f)
                            {
                                if (formulaApply.areaOccupy == TransformFormula.spaceType.byUnitAway)
                                {
                                    result.linearSpacing = formulaApply.spacingValue;
                                }
                                else if (formulaApply.areaOccupy == TransformFormula.spaceType.byOverallWidth)
                                {
                                    result.linearSpacing = formulaApply.spacingValue / (formulaApply.linearAmount - 1);
                                }
                            }

                            if (formulaApply.rayAmount > 1f && formulaApply.spreadAngle > 0f)
                            {
                                if (formulaApply.angleFilled)
                                    result.raySpacing = formulaApply.spreadAngle / (formulaApply.rayAmount - 1);
                                else
                                    result.raySpacing = formulaApply.spreadAngle / formulaApply.rayAmount;
                            }

                            StartCoroutine (DelayRayFormula (bullet, formulaApply, modApply, result));
                        }
                        else
                        {
                            GameObject currentClone;

                            //Instantiate the bullet
                            currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject;

                            //Initialize the bullet if modification exist
                            ModSetup (currentClone, modApply, result.modificationExist);
                            Debug.Log ("INSIDE-else");
                        }
                    }
                }

                if (readyFire <= localTime)
                    readyFire = localTime + fireRate;
                localTime += Time.deltaTime;
            }
            yield return null;
        }
        yield return null;
    }

    void ModSetup (GameObject currentClone, BulletModification modApply, bool modificationExist)
    {
        ProjectileController projectileController = currentClone.GetComponent<ProjectileController> ();

        //Initialize the bullet if modification exist
        if (modificationExist) {
            Debug.Log ("modApply.startSpeed: " + modApply.startSpeed + " [" + gameObject.name + "->HellBulletManager/ModSetup()]");
            projectileController.Modify (modApply.startSpeed, modApply.acceleration, modApply.speedRange, modApply.damage, modApply.lifeSpan);
        }
    }

    IEnumerator DelayRayFormula (GameObject bullet, TransformFormula formulaApply, BulletModification modApply, ProcessResults result)
    {
        for (result.j = 0; result.j < formulaApply.rayAmount; result.j += 2)
        {
            if (!result.primaryRay && formulaApply.delayRay > 0f)
                yield return new WaitForSeconds (formulaApply.delayRay);

            StartCoroutine(DelayLinearFormula (bullet, formulaApply, modApply, result));

            if (result.primaryRay)
            {
                result.primaryRay = false;
            }
            result.primaryLinear = true;
        }
    }

    IEnumerator DelayLinearFormula (GameObject bullet, TransformFormula formulaApply, BulletModification modApply, ProcessResults result)
    {
        for (result.k = 0; result.k < formulaApply.linearAmount; result.k += 2)
        {
            if (!result.primaryLinear && formulaApply.delayLinear > 0f)
                yield return new WaitForSeconds (formulaApply.delayLinear);

            StartCoroutine (DelayBulletFormula (bullet, formulaApply, modApply, result));

            if (result.primaryLinear)
            {
                result.primaryLinear = false;
            }
        }
    }

    IEnumerator DelayBulletFormula (GameObject bullet, TransformFormula formulaApply, BulletModification modApply, ProcessResults result)
    {
        GameObject currentClone;
        List<GameObject> cloneList = new List<GameObject> ();
        bool primaryBullet = true;

        float speed;
        float acceleration;
        float maxSpeed;

        for (result.l = 0; result.l < formulaApply.delayAmount + 1; result.l++) {
            //Instantiate the bullet
            if (formulaApply.rayAmount % 2 == 1)
            {
                if (formulaApply.linearAmount % 2 == 1)
                {
                    cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (result.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (result.k * 0.5f)));

                    if (!result.primaryLinear)
                    {
                        cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, result.raySpacing * (result.j * 0.5f));
                        currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (-result.k * 0.5f)));
                    }

                    if (!result.primaryRay)
                    {
                        cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-result.j * 0.5f));
                        currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (result.k * 0.5f)));

                        if (!result.primaryLinear)
                        {
                            cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                            currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-result.j * 0.5f));
                            currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (-result.k * 0.5f)));
                        }
                    }
                }
                else //if (formulaApply.linearAmount % 2 == 0)
                {
                    cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (result.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (result.k * 0.5f)) + (result.linearSpacing * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (result.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (-result.k * 0.5f)) - (result.linearSpacing * 0.5f)));

                    if (!result.primaryRay)
                    {
                        cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-result.j * 0.5f));
                        currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (result.k * 0.5f)) + (result.linearSpacing * 0.5f)));

                        cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-result.j * 0.5f));
                        currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (-result.k * 0.5f)) - (result.linearSpacing * 0.5f)));
                    }
                }
            }
            else //if (formulaApply.rayAmount % 2 == 0)
            {
                if (formulaApply.linearAmount % 2 == 1)
                {
                    cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, (result.raySpacing * (result.j * 0.5f)) + (result.raySpacing * 0.5f));
                    currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (result.k * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, (result.raySpacing * (-result.j * 0.5f)) - (result.raySpacing * 0.5f));
                    currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (-result.k * 0.5f)));

                    if (!result.primaryLinear)
                    {
                        cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, (result.raySpacing * (result.j * 0.5f)) + (result.raySpacing * 0.5f));
                        currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (-result.k * 0.5f)));

                        cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, (result.raySpacing * (-result.j * 0.5f)) - (result.raySpacing * 0.5f));
                        currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (result.k * 0.5f)));
                    }
                }
                else //if (formulaApply.linearAmount % 2 == 0)
                {
                    cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (result.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (result.k * 0.5f)) + (result.linearSpacing * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (result.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (-result.k * 0.5f)) - (result.linearSpacing * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-result.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (result.k * 0.5f)) + (result.linearSpacing * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, result.totalPosition, result.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-result.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (-result.k * 0.5f)) - (result.linearSpacing * 0.5f)));
                }
            }

            foreach (GameObject thisClone in cloneList)
                ModSetup (thisClone, modApply, result.modificationExist);
          
            if (primaryBullet) {
                ProjectileController projectileController = currentClone.GetComponent<ProjectileController> ();

                primaryBullet = false;
                result.baseSpeed = projectileController.getSpeed ();
                result.baseAcceleration = projectileController.getAcceleration ();
                result.baseMaxSpeed = projectileController.getMaxSpeed ();
            }

            if (formulaApply.delayAmount > 0)
            {
                // 100 setSpeed * 1 - (bulletIndexNum * ((1 - (1 - (100 setValue / 100 valueRange))) / (4 bulletCount - 1)));  /* Sample! */
                speed = result.baseSpeed * (1 - (result.l * ((1 - (1 - (formulaApply.speedOffset / 100))) / (formulaApply.delayAmount))));
                acceleration = result.baseAcceleration * (1 - (result.l * ((1 - (1 - (formulaApply.speedOffset / 100))) / (formulaApply.delayAmount))));
                maxSpeed = result.baseMaxSpeed * (1 - (result.l * ((1 - (1 - (formulaApply.speedOffset / 100))) / (formulaApply.delayAmount))));
            }
            else
            {
                speed = result.baseSpeed;
                acceleration = result.baseAcceleration;
                maxSpeed = result.baseMaxSpeed;
            }

            foreach (GameObject thisClone in cloneList)
            {
                ProjectileController projectileController = thisClone.GetComponent<ProjectileController> ();

                if (result.modificationExist)
                    projectileController.Modify (speed, acceleration, maxSpeed, modApply.damage, modApply.lifeSpan);
                else
                    projectileController.ModifyMotion (speed, acceleration, maxSpeed);
            }

            cloneList.Clear ();
        }
        yield return null;
    }
}

I will also attach my simplified project here, to see it first hand:
Hell Bullet Tester.zip

Thank you… :smile: your help are greatly appreciated!


3212212--245938--My_Buggy_Hell_Bullet_Illustrate.gif
3212212–245939–Hell Bullet Tester.zip (1.24 MB)

It’s a little hard to follow the huge amount of code and the intended result, but if I understand correctly: Are you under the belief that this:

Debug.Log("A");
StartCoroutine(PrintBAfterOneSecond() );
yield return new WaitForSeconds(0.5f);
Debug.Log("C");

Will print A, wait a second, print B, wait 0.5 sec, then print C?

StartCoroutine launches a new coroutine, and if left alone, that coroutine will be run in parallel. If you want your current coroutine to wait for that one before proceeding, you need to use the syntax:

yield return StartCoroutine(PrintBAfterOneSecond() );

Again, I’m not sure if I correctly understand your question, but this seems like a likely issue to be having.

2 Likes

I think I get it what’s going on my code process:

There’s nothing weird with Coroutine but the WaitForSeconds makes it complicated especially dealing with multiple inner looping:

My mistake is not the Coroutine/WaitForSeconds, but the Instant variables… I’m just dealing with 1 instance, instead of making instant holder every inner loop:

Coroutine within Coroutine.zip
Look for the code below with >>>>4th attempt<<<<, which fixed my hell bullet script…
The >>>>2nd/3rd attempt<<<< what’s with my old script’s flaws…

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class Ninja {
    public string figureName = "shadowEye";

    public int itemQuatity = 10;
    public string itemName = "Dagger";
}

public class CoroutineNestedTricks : MonoBehaviour {

    public Ninja shadowEye;
    private bool finishingBlow = false;

    void Start () {
        shadowEye.figureName = "shadowEye(Human)";

        StartCoroutine (NinjaMove (shadowEye)); //line 21
    }
  
    IEnumerator NinjaMove (Ninja shadowEye) { //line 24

        //CHOOSE ONLY 1 of attempts below:

        // >>>>1st attempt<<<< (Maybe successful but a big pain)
        /* I have to declare new varaible and initialize them individually and send them to parameter individually
         * Imagine if I have many variable need to send as parameter to the next function and to the next and next...
         * To my 'Hell Bullet Script': I might end up sending 14 parameters; that's why I put them to class, like a package send as 1 parameter called 'ProcessResults' class
         * If I do my 1st attemp; I don't actually need to make Ninja class
         * ...And change 'public Ninja shadowEye;' from line 15 to:
         * public string figureName = "shadowEye";
         * public int itemQuatity = 10;
         * public string itemName = "Dagger";
         * and also need to change the parameter of line 21 and 24...
         */

        /*[/] <-- add/delete 1 slash to uncomment/comment...

        string figureName = shadowEye.figureName;            //# 1st attempt: Copying the value with local variable
        int itemQuatity = shadowEye.itemQuatity;            //# 1st attempt: Copying the value with local variable
        string itemName = shadowEye.itemName;                //# 1st attempt: Copying the value with local variable
        //type var1 = shadowEye.var1                         //(Assuming if there's more variables)

        //StartCoroutine (SummonClone_withLongParameter (figureName, itemQuatity, itemName, var1, var2, var3, var_so_on, var9999joke);

        StartCoroutine (SummonClone_withLongParameter (figureName, itemQuatity, itemName));    //# 1st attempt: StartCoroutine
        //*/


        // >>>>2nd attempt<<<< (Fail)
        /* This line of code makes [shadowEye_Clone] pointer to [shadowEye] instead of making a new instance of variable...
         * In other word: changing [shadowEye.figureName] value will change [shadowEye_Clone.figureName] value same as [shadowEye.figureName] and vice versa
         * It does not make different dimension, because it makes [shadowEye_Clone] alias to [shadowEye], in other words they're the same...
         * But this is good used for real time changes...
         */

        /*[/] <-- add/delete 1 slash to uncomment/comment...

        Ninja shadowEye_Clone = shadowEye;                     //# 2nd attempt: Copying the value as new instance? NO! But a pointer... YES
        StartCoroutine (SummonClone (shadowEye_Clone));        //# 2nd attempt: StartCoroutine
        //*/


        // >>>>3rd attempt<<<< (Fail)
        /*
         * I'm being stupid, still the same as my 1st attempt;
         * I just made a new instance, but then I had overwrite [shadowEye_Clone] back being a pointer to [shadowEye], they're the same again
         */

        /*[/] <-- add/delete 1 slash to uncomment/comment...

        Ninja shadowEye_Clone = new Ninja();                //# 3rd attempt: Making a new instance...
        shadowEye_Clone = shadowEye;                        //# 3rd attempt: Copying the value as new instance? NO! Have overwrite to pointer... YES
        StartCoroutine (SummonClone (shadowEye_Clone));     //# 3rd attempt: StartCoroutine
        //*/


        // >>>>4th attempt<<<< (Successful with half of pain)
        /*
         * Like my 1st attemp: I have to declare new, a new class instead of new local variables
         * Then I have to initailize them individually (painful when many), but I can send them as 1 parameter
         * but, IT WILL BE SWEETER IF THERE'S A WAY TO COPY ALL VALUE WITHOUT MAKING IT A POINTER BUT A NEW INSTANCE... anyone? <--- Question to answer
         * If I attempt [shadowEye_Clone = shadowEye], I will end up making a pointer, so I need to assign them individually: look [//# 4th attempt] line of code...
         * This time [shadowEye_Clone] is a new instance and not a pointer to [shadowEye]... so they are independent!
         */

        //*[/] <-- add/delete 1 slash to uncomment/comment...

        Ninja shadowEye_Clone = new Ninja();                    //# 4th attempt: Making a new instance...
        shadowEye_Clone.figureName = shadowEye.figureName;        //# 4th attempt: Copying the value as new instance? YES!
        shadowEye_Clone.itemQuatity = shadowEye.itemQuatity;    //# 4th attempt: Copying the value as new instance? YES!
        shadowEye_Clone.itemName = shadowEye.itemName;            //# 4th attempt: Copying the value as new instance? YES!
        StartCoroutine (SummonClone (shadowEye_Clone));         //# 4th attempt: StartCoroutine
        //*/


        // >>>>5th attempt<<<< (Depend (Much better))
        /*
         * Your answer to this:
         * IT WILL BE SWEETER IF THERE'S A WAY TO COPY ALL VALUE WITHOUT MAKING IT A POINTER BUT A NEW INSTANCE...
         */
        //*[/] <-- add/delete 1 slash to uncomment/comment...

        //Put your code below here..........                                 //# 5th attempt



        //*/

        yield return new WaitForSeconds (2f);
        //Total time passed: 1 seconds...

        for (shadowEye.itemQuatity = shadowEye.itemQuatity; shadowEye.itemQuatity > 2; shadowEye.itemQuatity--) {
            Debug.Log (shadowEye.figureName+" throwing his "+shadowEye.itemName+" to his enemy... he have "+(shadowEye.itemQuatity-1)+" "+shadowEye.itemName+" left");
            yield return new WaitForSeconds (0.5f); //Time Lapse: 0.5 * (10 /*shadowEye.itemQuatity left*/ - 2) = 4 seconds...
        }
        //Total time passed: 5 seconds...
        Debug.Log (shadowEye.figureName+" is taking a break and let his clone attack...");

        yield return new WaitForSeconds (6f);
        //Total time passed: 11 seconds...
        //Debug.Log ("Main: "+Time.time);

        if (finishingBlow)
        {
            for (shadowEye.itemQuatity = shadowEye.itemQuatity; shadowEye.itemQuatity > 0; shadowEye.itemQuatity--) {
                Debug.Log (shadowEye.figureName+" finish his enemy with "+shadowEye.itemName+"... he have "+(shadowEye.itemQuatity-1)+" "+shadowEye.itemName+" left");
                yield return new WaitForSeconds (0.5f); //Time Lapse: 0.5 * (2 /*shadowEye.itemQuatity left*/ - 0) = 1 seconds...
            }
            //Total time passed: 12 seconds...
        }

        //If your playing with 2nd or 3rd attempt, this will take a while to display [wait for 10 sec after...]):
        Debug.Log ("The Main done!");
        //Debug.Log (shadowEye.figureName+" fist bump his clone "+figureName); //A failure        //for 1st attempt only... (Note: figureName is a local variable in this function)
        //Debug.Log (shadowEye.figureName+" fist bump his clone "+shadowEye_Clone.figureName);    //for all except the 1st attempt... (Note: shadowEye_Clone.figureName is a class variable)
    }

    IEnumerator SummonClone (Ninja shadowEye_Clone) {
        Debug.Log (shadowEye.figureName+" summoned his clone "+shadowEye_Clone.figureName+"," +
            " let's change the latter's name from (Human) to (Clone)..."); //Display test of [shadowEye.figureName] and [shadowEye_Clone.figureName]

        shadowEye_Clone.figureName = "shadowEye(Clone)"; //[shadowEye_Clone.figureName] value change to "shadowEye(Clone)"...
        yield return new WaitForSeconds (1f);
        //Total time passed: 1 seconds...

        Debug.Log (shadowEye.figureName+" start to attack, while his clone "+shadowEye_Clone.figureName+" is preparing to support"); //Display test again of [shadowEye.figureName] and [shadowEye_Clone.figureName]

        //You may nest another [StartCoroutine (SummonClone_2 (shadowEye_Clone_2));] here with some attempt...

        yield return new WaitForSeconds (5f);
        //Total time passed: 6 seconds...

        for (shadowEye_Clone.itemQuatity = shadowEye_Clone.itemQuatity; shadowEye_Clone.itemQuatity > 0; shadowEye_Clone.itemQuatity--) {
            Debug.Log (shadowEye_Clone.figureName+" throwing his "+shadowEye_Clone.itemName+" to his enemy... he have "+(shadowEye_Clone.itemQuatity-1)+" "+shadowEye_Clone.itemName+" left");
            yield return new WaitForSeconds (0.5f); //Time Lapse: 0.5 * (10 /*shadowEye.itemQuatity left*/ - 0) = 5 seconds...
        }
        //Total time passed: 11 seconds...
        //Debug.Log ("SummonClone: "+Time.time);
        Debug.Log ("The Clone done!");
        finishingBlow = true;
    }

    //For 1st attempt used only...
    IEnumerator SummonClone_withLongParameter (string figureName, int itemQuatity, string itemName) {
        Debug.Log (shadowEye.figureName+" summoned his clone "+figureName+"," +
            " let's change the latter's name from (Human) to (Clone)..."); //Display test of [shadowEye.figureName] and [figureName]

        figureName = "shadowEye(Clone)"; //[figureName] value change to "shadowEye(Clone)"... Note: the [figureName] variable from [NinjaMove()] function does not change...
        yield return new WaitForSeconds (1f);
        //Total time passed: 1 seconds...

        Debug.Log (shadowEye.figureName+" start to attack, while his clone "+figureName+" is preparing to support"); //Display test again of [shadowEye.figureName] and [figureName]

        yield return new WaitForSeconds (5f);
        //Total time passed: 6 seconds...

        for (int i = itemQuatity; i > 0; i--) {
            Debug.Log (figureName+" throwing his "+itemName+" to his enemy... he have "+(i-1)+" "+itemName+" left");
            yield return new WaitForSeconds (0.5f); //Time Lapse: 0.5 * (10 /*i left*/ - 0) = 5 seconds...
        }

        Debug.Log ("The Clone done!");
        finishingBlow = true;
    }
}

I thought StartCoroutine( ) make a new process to the called function and the function process who called other function continue to the next line of code
In other words, I thought there will be 2 processes simultaneously executing…
Because of that, I thought the var1 from the Function1 and Function2’s parameter var1 send from Function1 become different instance (dimension)
So I thought if var1 from Function1 change, the var1 from Function2 won’t and vice versa as it hold by different process, but in reality,
there’s only 1 process executing…

Here’s my fixed HellBullet Script: (Compare this to my old script, you’ll see the difference; …and put this to your script editor to make easier to read)

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class BulletModification {
    [Header("Modify Cluster:")]
    public float startSpeed = 1f;
    public enum generateAcceleration {
        byUnit,
        byPercentage
    } public generateAcceleration accelerationType;
    public float acceleration;
    public float speedRange = 1f;
    public int damage = 20;
    public float lifeSpan = 5f;
}

[System.Serializable]
public class TransformFormula {
    //[Header("Stir Bullet:")]
    [Header("Mirror Bullet:")]
    [Tooltip("0 means all copies will be on sync, beyond that will make delay offset speed; 100 makes the last delay copy to stationary, 200 makes go to opposite direction. Set delayAmount above 0 to see result")]
    [Range(0,200)] public float speedOffset;
    [Tooltip("Number of clone bullets for offset speed. Set speedOffset to work with")]
    [Range(0,3)] public int delayAmount;
    [Tooltip("Number of clone bullets shoot parallel to each other")]
    [Range(1,128)] public int linearAmount = 1;
    public enum spaceType {
        byUnitAway,
        byOverallWidth
    }; [Tooltip("How parallel bullets take up space")] public spaceType areaOccupy;
    [Tooltip("The amount of parallel bullets away each other or their general width as one group")]
    public float spacingValue;
    [Tooltip("Number in seconds; parallel from the middle will start immediately, then delay start to the next neighbor line")]
    [Range(0,20)] public float delayLinear;

    [Header("Spray Bullet:")]
    [Tooltip("Spread the rays exact to spreadAngle")]
    public bool angleFilled;
    [Tooltip("The degree angle of an arc be made for rayAmount")]
    [Range(0,360)] public float spreadAngle;
    [Tooltip("The number of copy bullet as rays restricted by spreadAngle")]
    [Range(1,32)] public int rayAmount = 1;
    [Tooltip("The radius offset of the center of the ray")]
    public float spawnOffsetRadius;
    [Tooltip("Number in seconds; the first ray will start immediately, then delay start to the next neighbor ray")]
    [Range(0,20)] public float delayRay;
}

[System.Serializable]
public class TransformPattern {
    [Header("Bullet Patterns:")]
    public Vector2 respawnOffset;
    [Tooltip("Sliding the respawn origin of bullet sideward from left to right length-based over given duration")]
    public float linearMagnitude;
    public enum linearMotionType{
        Linear,
        Wave
    }; public linearMotionType linearFlow;
    public enum linearDirection{
        left_Right,
        right_Left,
        center_Right,
        center_Left
    }; public linearDirection linearPoint;
    [Tooltip("Move with one direction or play ping pong")]
    public bool pingPong = true;
    [Tooltip("The spin progress over given duration; Note: clinch with 'Linear Magnitude'")]
    public float spinMotion;
    public enum spinMotionType {
        Linear,
        Wave
    }; public spinMotionType spinFlow;
    public enum spinDirection{
        left_Right,
        right_Left,
        center_Right,
        center_Left
    }; public spinDirection spinPoint;
    [Tooltip("Merry-go-around or not")]
    public bool swingBack = false;
    [Tooltip("As it says; offset vertically and/or horizontally -_-")]
    public Vector2 masterOffset;
    [Tooltip("Offset overall rotation with parent object, but only in z-axis, any problem with that?! Note: doesn't spin over time, use spinMotion or bullet formula instead, or use emitter and make it spin via other script (or animation?)")]
    public float masterRotation;
    [Tooltip("Offset rotation disregarding linear orientation")]
    public float offsetRotation;
}

[System.Serializable]
public class TimeLine {
    [Header("Bullet Time:")]
    [Tooltip("Ready to execute one time once timeCode reaches")]
    public bool active = true;
    [Tooltip("Time in seconds to start the bullet party")]
    public float start = 0f;
    [Tooltip("Time in seconds to finish one pattern")]
    public float duration = 1f;
    [Tooltip("Multiply the duration to continue executing the pattern")]
    public int execute = 1;
    [Tooltip("Number of bullet emits in one span of duration harmonizing with pattern; Note: minimum fire rate will not less than 0.01 sec, or else actionPulse will be deducted")]
    public int actionPulse = 1;

    [Header("Bullet Element:")]
    [Tooltip("To certainly choose none, input less than 0")]
    public int pattern;
    [Tooltip("To certainly choose none, input less than 0")]
    public int formula;
    [Tooltip("To certainly choose none, input less than 0")]
    public int modification;
}

[System.Serializable]
public class BulletSpawn {
    [Tooltip("Your title, definition, description, speech, message, or whatever; :Optional:")]
    public string name;
    public GameObject bulletPrefab;
    [Tooltip("Spawn point: object attached with this script act as default emitter, if leave empty")]
    public List<GameObject> emitter;
    public List<TimeLine> bulletTime;
}

[System.Serializable]
public class BulletFlow {
    /* Note: for the future viewer; why no 'public bool active'?
     * No need, I found it useless; use/code timeHalt + reset = inactive (if you want to extend this code)... */
    public bool reset;
    public bool timeHalt;
    public bool looping;
    [Tooltip("Set loopQuantity to zero for infinite loop")]
    public int loopQuantity;
    [Tooltip("What for? Delay the start time of timeCode")]
    public float delayStart;
    [Tooltip("Behold the time holder! NOLI ME TANGERE, if you don't know me what I am for")]
    public float timeCode;
}

public class ProcessResults {
    public bool patternExist = false;
    //public Vector3 totalPosition = Vector3.zero;
    //public Quaternion totalRotation = Quaternion.identity;

    public bool formulaExist = false;
    public bool modificationExist = false;
    //public int j, k, l = 0;

    //public bool primaryRay = false;
    public float raySpacing = 0;

    //public bool primaryLinear = false;
    public float linearSpacing = 0;

    public bool primaryBullet = false;
    public float baseSpeed, baseAcceleration, baseMaxSpeed = 0f;
}

public class InstantProcessResults {
    public Vector3 totalPosition = Vector3.zero;
    public Quaternion totalRotation = Quaternion.identity;

    public int j, k, l = 0;

    public bool primaryRay = false;

    public bool primaryLinear = false;
}

public class HellBulletManager : MonoBehaviour {

    [Header("Bullet Manager:")]
    public BulletFlow bulletRush;
    public float _totalDuration;
    private float _loopQuantity;
    public List<BulletSpawn> hellBullets;

    [Header("Bullet Transform:")]
    public List<TransformPattern> bulletPattern = new List<TransformPattern> ();

    [Header("Bullet Properties:")]
    public List<TransformFormula> bulletFormula;
    public List<BulletModification> bulletModification;

    // Use this for initialization
    void Start () {
        _totalDuration = 0f;
        _loopQuantity = bulletRush.loopQuantity;

        if (bulletFormula.Count > 0)
            foreach (TransformFormula thisFormula in bulletFormula)
            {
                //using [Range(min,max)] and min set to 1, but the default stay to 0; this is use to fix the min when game starts
                if (thisFormula.linearAmount == 0)
                    thisFormula.linearAmount = 1;
                if (thisFormula.rayAmount == 0)
                    thisFormula.rayAmount = 1;
            }
    }

    void FixedUpdate () {
        if (bulletRush.reset)
        {
            bulletRush.reset = !bulletRush.reset;
            bulletRush.timeCode = 0f;

            foreach (BulletSpawn thisBullet in hellBullets)
            {
                foreach (TimeLine thisTime in thisBullet.bulletTime)
                {
                    thisTime.active = true;
                }
            }
        }

        if (bulletRush.timeHalt)
        {
            return;
        }

        if (bulletRush.delayStart > 0f)
        {
            bulletRush.delayStart -= Time.deltaTime;
            if (bulletRush.delayStart < 0f)
                bulletRush.delayStart = 0f;
        }
        else
        {
            bulletRush.timeCode += Time.deltaTime;
        }

        //Make sure taken out all List with null bulletSpawn.bulletPrefab --- Lambda syntax 'COOL AND POWERFUL' they say!
        hellBullets.RemoveAll (BulletSpawn => BulletSpawn.bulletPrefab == null);
        if (hellBullets.Count > 0)
        {
            foreach (BulletSpawn thisBullet in hellBullets)
            {
                if (thisBullet.bulletTime.Count > 0)
                {
                    foreach (TimeLine thisTime in thisBullet.bulletTime)
                    {
                        if (thisTime.duration > 0f && _totalDuration < thisTime.start + (thisTime.duration * thisTime.execute))
                        {
                            _totalDuration = thisTime.start + (thisTime.duration * thisTime.execute);
                        }

                        if (thisTime.active && bulletRush.timeCode >= thisTime.start && thisTime.duration > 0f)
                        {
                            thisTime.active = false;
                            float pulseGap = thisTime.duration / thisTime.actionPulse;
                            if (pulseGap < 0.01f) {
                                thisTime.actionPulse = Mathf.FloorToInt(thisTime.duration / 0.01f);

                                if (thisTime.actionPulse == 0)
                                    return;

                                pulseGap = thisTime.duration / thisTime.actionPulse;
                            }
                            StartCoroutine (startRespawn (thisBullet.bulletPrefab, thisBullet.emitter, thisTime.duration, pulseGap, thisTime.execute, thisTime.pattern, thisTime.formula, thisTime.modification));
                        }
                    }
                }
            }
        }

        if (bulletRush.timeCode >= _totalDuration)
        {
            if (bulletRush.looping)
            {
                if (bulletRush.loopQuantity > 0)
                    bulletRush.loopQuantity -= 1;

                if (bulletRush.loopQuantity > 0 || _loopQuantity == 0)
                {
                    bulletRush.reset = true;
                }
                else
                {
                    bulletRush.timeHalt = true;
                    bulletRush.reset = true;
                }
            }
            else
            {
                bulletRush.timeHalt = true;
                bulletRush.reset = true;
            }
        }
    }

    IEnumerator startRespawn (GameObject bullet, List<GameObject> emitters, float duration, float fireRate, int execute, int pattern, int formula, int modification)
    {
        TransformPattern patternApply = new TransformPattern ();
        TransformFormula formulaApply = new TransformFormula ();
        BulletModification modApply = new BulletModification ();
        ProcessResults result = new ProcessResults ();
        InstantProcessResults instantResult = new InstantProcessResults ();

        float localTime = 0f;
        float readyFire = 0f;

        result.patternExist = false;
        //bool patternExist = false;
        patternApply.respawnOffset = Vector2.zero;
        Vector2 respawnOffset = Vector2.zero;
        patternApply.linearMagnitude = 0f;
        patternApply.linearFlow = TransformPattern.linearMotionType.Linear;
        patternApply.linearPoint = TransformPattern.linearDirection.left_Right;
        patternApply.pingPong = false;
        patternApply.spinMotion = 0f;
        patternApply.spinFlow = TransformPattern.spinMotionType.Linear;
        patternApply.spinPoint = TransformPattern.spinDirection.left_Right;
        patternApply.swingBack = false;
        patternApply.masterOffset = Vector2.zero;
        patternApply.masterRotation = 0f;
        patternApply.offsetRotation = 0f;

        result.formulaExist = false;
        //bool formulaExist = false;
        formulaApply.speedOffset = 0f;
        formulaApply.delayAmount = 0;
        formulaApply.linearAmount = 1;
        formulaApply.areaOccupy = TransformFormula.spaceType.byUnitAway;
        formulaApply.spacingValue = 0f;
        formulaApply.delayLinear = 0f;
        formulaApply.spreadAngle = 0f;
        formulaApply.rayAmount = 1;
        formulaApply.spawnOffsetRadius = 0f;
        formulaApply.delayRay = 0f;

        result.modificationExist = false;
        //bool modificationExist = false;
        modApply.startSpeed = 0f;
        modApply.accelerationType = BulletModification.generateAcceleration.byUnit;
        modApply.acceleration = 0f;
        modApply.speedRange = 0f;

        //The game will run but gives me a message error, I don't know where cause of this specifically, may here or above there? Error: ArgumentOutOfRangeException: Argument is out of range. Parameter name: index
        if (pattern >= 0 && pattern < bulletPattern.Count) { //Checking... if (bulletPattern[pattern] == null) never assigned 'patternApply = bulletPattern [pattern];'...
            result.patternExist = true;
            patternApply = bulletPattern [pattern];

            /*
            patternApply.respawnOffset = bulletPattern[pattern].respawnOffset;
            patternApply.linearMagnitude = bulletPattern[pattern].linearMagnitude;
            patternApply.linearFlow = bulletPattern[pattern].linearFlow;
            patternApply.linearPoint = bulletPattern[pattern].linearPoint;
            patternApply.pingPong = bulletPattern[pattern].pingPong;
            patternApply.spinMotion = bulletPattern[pattern].spinMotion;
            patternApply.spinFlow = bulletPattern[pattern].spinFlow;
            patternApply.spinPoint = bulletPattern[pattern].spinPoint;
            patternApply.swingBack = bulletPattern[pattern].swingBack;
            patternApply.masterOffset = bulletPattern[pattern].masterOffset;
            patternApply.masterRotation = bulletPattern[pattern].masterRotation;
            patternApply.offsetRotation = bulletPattern[pattern].offsetRotation;
            */
        }

        if (formula >= 0 && formula <= bulletFormula.Count - 1) { //if (bulletFormula.Exists(BulletSpawn => bulletFormula[formula])) /* <- Sample only: trying '.Exists' for alternatives, but give me some errors; I don't know really how to use it... or how about some '.Contain'? I don't know about it, please help me... THANKS */
            result.formulaExist = true;
            formulaApply = bulletFormula [formula];
        } else {
            result.formulaExist = false;
        }

        if (modification >= 0 && modification <= bulletModification.Count - 1) { //if (bulletModification.Exists(bulletModification[modification]))
            result.modificationExist = true;
            modApply = bulletModification [modification];
        } else {
            result.modificationExist = false;
        }

        //Transform bulletDirector;

        float motionPoint;
        Vector3 transformPosition = transform.position;
        float transformRotation = 0f;
        while (localTime < duration * execute && duration > 0f)
        {
            if (!bulletRush.timeHalt)
            {
                emitters.RemoveAll (GameObject => GameObject == null);

                if (result.patternExist)
                {
                    float respawnOffsetX = Random.Range (-bulletPattern[pattern].respawnOffset.x, bulletPattern[pattern].respawnOffset.x);
                    float respawnOffsetY = Random.Range (-bulletPattern[pattern].respawnOffset.y, bulletPattern[pattern].respawnOffset.y);
                    //patternApply.respawnOffset = new Vector2 (respawnOffsetX, respawnOffsetY);
                    respawnOffset = new Vector2 (respawnOffsetX, respawnOffsetY);
                }

                bool once = true;
                for (int i = 0; i < emitters.Count || once; i++, once = false)
                {
                    int inverse;

                    inverse = 0;
                    if (!patternApply.pingPong)
                    {
                        if ((patternApply.linearPoint == TransformPattern.linearDirection.left_Right ||
                            patternApply.linearPoint == TransformPattern.linearDirection.right_Left)
                            && Mathf.FloorToInt (localTime * (1f / duration)) % 2 == 1f)
                        {
                            inverse = 1;
                        }
                        else if ((patternApply.linearPoint == TransformPattern.linearDirection.center_Right ||
                            patternApply.linearPoint == TransformPattern.linearDirection.center_Left)
                            && Mathf.FloorToInt ((localTime * (1f / duration)) + 0.5f) % 2 == 1f)
                        {
                            inverse = 1;
                        }
                    }

                    motionPoint = 0f;
                    Vector3 linearOrientation;
                    if (emitters.Count == 0)
                    {
                        linearOrientation = new Vector3 (Mathf.Cos (Mathf.Deg2Rad * (transform.eulerAngles.z + patternApply.masterRotation)), Mathf.Sin (Mathf.Deg2Rad * (transform.eulerAngles.z + patternApply.masterRotation)), 0f);
                    }
                    else
                    {
                        linearOrientation = new Vector3 (Mathf.Cos(Mathf.Deg2Rad * (emitters[i].transform.eulerAngles.z + patternApply.masterRotation)), Mathf.Sin(Mathf.Deg2Rad * (emitters[i].transform.eulerAngles.z + patternApply.masterRotation)), 0f);
                    }

                    if (patternApply.linearFlow == TransformPattern.linearMotionType.Linear)
                    {
                        if (patternApply.linearPoint == TransformPattern.linearDirection.left_Right)
                        {
                            motionPoint = Mathf.PingPong ((localTime * patternApply.linearMagnitude * (1f / duration)) + (inverse * patternApply.linearMagnitude), patternApply.linearMagnitude) - (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.right_Left)
                        {
                            motionPoint = Mathf.PingPong ((localTime * patternApply.linearMagnitude * (1f / duration)) + (patternApply.linearMagnitude) + (inverse * patternApply.linearMagnitude), patternApply.linearMagnitude) - (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.center_Right)
                        {
                            motionPoint = Mathf.PingPong ((localTime * patternApply.linearMagnitude * (1f / duration)) + (patternApply.linearMagnitude * 0.5f) + (inverse * patternApply.linearMagnitude), patternApply.linearMagnitude) - (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.center_Left)
                        {
                            motionPoint = Mathf.PingPong ((localTime * patternApply.linearMagnitude * (1f / duration)) - (patternApply.linearMagnitude * 0.5f) + (inverse * patternApply.linearMagnitude), patternApply.linearMagnitude) - (patternApply.linearMagnitude * 0.5f);
                        }

                        if (!(System.Single.IsNaN (motionPoint) || System.Single.IsInfinity (motionPoint)))
                            transformPosition = motionPoint * linearOrientation;
                        else
                            transformPosition = Vector3.zero;
                    }
                    else if (patternApply.linearFlow == TransformPattern.linearMotionType.Wave)
                    {
                        if (patternApply.linearPoint == TransformPattern.linearDirection.left_Right)
                        {
                            motionPoint = Mathf.Sin (((localTime - (0.5f * duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.right_Left)
                        {
                            motionPoint = Mathf.Sin (((localTime + (0.5f * duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.center_Right)
                        {
                            motionPoint = Mathf.Sin (((localTime + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.linearMagnitude * 0.5f);
                        }
                        if (patternApply.linearPoint == TransformPattern.linearDirection.center_Left)
                        {
                            motionPoint = Mathf.Sin (((localTime + (duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.linearMagnitude * 0.5f);
                        }

                        transformPosition = motionPoint * linearOrientation;
                    }
                    instantResult.totalPosition = transformPosition + new Vector3 (patternApply.masterOffset.x, patternApply.masterOffset.y) + new Vector3 (respawnOffset.x, respawnOffset.y);// + new Vector3 (patternApply.respawnOffset.x, patternApply.respawnOffset.y);;

                    if (emitters.Count == 0)
                    {
                        instantResult.totalPosition += transform.position;
                    }
                    else
                    {
                        instantResult.totalPosition += emitters [i].transform.position;
                    }

                    int multiplier;

                    multiplier = 0;
                    inverse = 0;
                    if (!patternApply.swingBack)
                    {
                        if ((patternApply.spinPoint == TransformPattern.spinDirection.left_Right ||
                            patternApply.spinPoint == TransformPattern.spinDirection.right_Left)
                            && Mathf.FloorToInt (localTime * (1f / duration)) % 2 == 1f)
                        {
                            inverse = 1;
                        }
                        else if ((patternApply.spinPoint == TransformPattern.spinDirection.center_Right ||
                            patternApply.spinPoint == TransformPattern.spinDirection.center_Left)
                            && Mathf.FloorToInt ((localTime * (1f / duration)) + 0.5f) % 2 == 1f)
                        {
                            inverse = 1;
                        }
                        multiplier = Mathf.FloorToInt (localTime * (1f / duration));
                    }

                    motionPoint = 0f;
                    if (patternApply.spinFlow == TransformPattern.spinMotionType.Linear)
                    {
                        if (patternApply.spinPoint == TransformPattern.spinDirection.left_Right)
                        {
                            motionPoint = (Mathf.PingPong ((localTime * patternApply.spinMotion * (1f / duration)) + (patternApply.spinMotion) + (inverse * patternApply.spinMotion), patternApply.spinMotion) - (patternApply.spinMotion * 0.5f)) - (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.right_Left)
                        {
                            motionPoint = (Mathf.PingPong ((localTime * patternApply.spinMotion * (1f / duration)) + (inverse * patternApply.spinMotion), patternApply.spinMotion) - (patternApply.spinMotion * 0.5f)) + (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.center_Right)
                        {
                            motionPoint = (Mathf.PingPong ((localTime * patternApply.spinMotion * (1f / duration)) - (patternApply.spinMotion * 0.5f) + (inverse * patternApply.spinMotion), patternApply.spinMotion) - (patternApply.spinMotion * 0.5f)) - (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.center_Left)
                        {
                            motionPoint = (Mathf.PingPong ((localTime * patternApply.spinMotion * (1f / duration)) + (patternApply.spinMotion * 0.5f) + (inverse * patternApply.spinMotion), patternApply.spinMotion) - (patternApply.spinMotion * 0.5f)) + (multiplier * patternApply.spinMotion);
                        }

                        if (!(System.Single.IsNaN (motionPoint) || System.Single.IsInfinity (motionPoint)))
                            transformRotation = motionPoint;
                        else
                            transformRotation = 0f;
                    }
                    else if (patternApply.spinFlow == TransformPattern.spinMotionType.Wave)
                    {
                        if (patternApply.spinPoint == TransformPattern.spinDirection.left_Right)
                        {
                            motionPoint = (Mathf.Sin (((localTime + (0.5f * duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.spinMotion * 0.5f)) - (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.right_Left)
                        {
                            motionPoint = (Mathf.Sin (((localTime - (0.5f * duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.spinMotion * 0.5f)) + (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.center_Right)
                        {
                            motionPoint = (Mathf.Sin (((localTime + (duration) + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.spinMotion * 0.5f)) - (multiplier * patternApply.spinMotion);
                        }
                        if (patternApply.spinPoint == TransformPattern.spinDirection.center_Left)
                        {
                            motionPoint = (Mathf.Sin (((localTime + (inverse * duration)) * (1f / duration)) * Mathf.PI) * (patternApply.spinMotion * 0.5f)) + (multiplier * patternApply.spinMotion);
                        }

                        transformRotation = motionPoint;
                    }
                    instantResult.totalRotation = Quaternion.Euler (0f, 0f, transformRotation + patternApply.masterRotation + patternApply.offsetRotation);

                    if (emitters.Count == 0)
                    {
                        instantResult.totalRotation *= transform.rotation;
                    }
                    else
                    {
                        instantResult.totalRotation *= emitters[i].transform.rotation;
                    }

                    if (readyFire <= localTime)
                    {
                        //Formulate the bullet if formula exist
                        if (result.formulaExist)
                        {
                            instantResult.primaryLinear = true;
                            instantResult.primaryRay = true;

                            result.baseSpeed = 0f;
                            result.baseAcceleration = 0f;
                            result.baseMaxSpeed = 0f;

                            result.linearSpacing = 0f;

                            if (formulaApply.linearAmount > 1f)
                            {
                                if (formulaApply.areaOccupy == TransformFormula.spaceType.byUnitAway)
                                {
                                    result.linearSpacing = formulaApply.spacingValue;
                                }
                                else if (formulaApply.areaOccupy == TransformFormula.spaceType.byOverallWidth)
                                {
                                    result.linearSpacing = formulaApply.spacingValue / (formulaApply.linearAmount - 1);
                                }
                            }

                            if (formulaApply.rayAmount > 1f && formulaApply.spreadAngle > 0f)
                            {
                                if (formulaApply.angleFilled)
                                    result.raySpacing = formulaApply.spreadAngle / (formulaApply.rayAmount - 1);
                                else
                                    result.raySpacing = formulaApply.spreadAngle / formulaApply.rayAmount;
                            }

                            StartCoroutine (DelayRayFormula (bullet, formulaApply, modApply, result, instantResult));
                        }
                        else
                        {
                            GameObject currentClone;

                            //Instantiate the bullet
                            currentClone = Instantiate (bullet, instantResult.totalPosition, instantResult.totalRotation) as GameObject;

                            //Initialize the bullet if modification exist
                            ModSetup (currentClone, modApply, result.modificationExist);
                            Debug.Log ("INSIDE-else");
                        }
                    }
                }

                if (readyFire <= localTime)
                    readyFire = localTime + fireRate;
                localTime += Time.deltaTime;
            }
            yield return null;
        }
        yield return null;
    }

    void ModSetup (GameObject currentClone, BulletModification modApply, bool modificationExist)
    {
        ProjectileController projectileController = currentClone.GetComponent<ProjectileController> ();

        //Initialize the bullet if modification exist
        if (modificationExist) {
            projectileController.Modify (modApply.startSpeed, modApply.acceleration, modApply.speedRange, modApply.damage, modApply.lifeSpan);
        }
    }

    IEnumerator DelayRayFormula (GameObject bullet, TransformFormula formulaApply, BulletModification modApply, ProcessResults result, InstantProcessResults instantResult)
    {
        InstantProcessResults instantResult2D = new InstantProcessResults ();
        instantResult2D.totalPosition = instantResult.totalPosition;
        instantResult2D.totalRotation = instantResult.totalRotation;
        instantResult2D.j = instantResult.j;
        instantResult2D.k = instantResult.k;
        instantResult2D.l = instantResult.l;
        instantResult2D.primaryRay = instantResult.primaryRay;
        instantResult2D.primaryLinear = instantResult.primaryLinear;

        for (instantResult2D.j = 0; instantResult2D.j < formulaApply.rayAmount; instantResult2D.j += 2)
        {
            if (!instantResult2D.primaryRay && formulaApply.delayRay > 0f)
                yield return new WaitForSeconds (formulaApply.delayRay);

            StartCoroutine(DelayLinearFormula (bullet, formulaApply, modApply, result, instantResult2D));

            if (instantResult2D.primaryRay)
            {
                instantResult2D.primaryRay = false;
            }
            instantResult2D.primaryLinear = true;
        }
    }

    IEnumerator DelayLinearFormula (GameObject bullet, TransformFormula formulaApply, BulletModification modApply, ProcessResults result, InstantProcessResults instantResult2D)
    {
        InstantProcessResults instantResult3D = new InstantProcessResults ();
        instantResult3D.totalPosition = instantResult2D.totalPosition;
        instantResult3D.totalRotation = instantResult2D.totalRotation;
        instantResult3D.j = instantResult2D.j;
        instantResult3D.k = instantResult2D.k;
        instantResult3D.l = instantResult2D.l;
        instantResult3D.primaryRay = instantResult2D.primaryRay;
        instantResult3D.primaryLinear = instantResult2D.primaryLinear;

        for (instantResult3D.k = 0; instantResult3D.k < formulaApply.linearAmount; instantResult3D.k += 2)
        {
            if (!instantResult3D.primaryLinear && formulaApply.delayLinear > 0f)
                yield return new WaitForSeconds (formulaApply.delayLinear);

            StartCoroutine(DelayBulletFormula (bullet, formulaApply, modApply, result, instantResult3D));

            if (instantResult3D.primaryLinear)
            {
                instantResult3D.primaryLinear = false;
            }
        }
    }

    IEnumerator DelayBulletFormula (GameObject bullet, TransformFormula formulaApply, BulletModification modApply, ProcessResults result, InstantProcessResults instantResult3D)
    {
        InstantProcessResults instantResult4D = new InstantProcessResults ();
        instantResult4D.totalPosition = instantResult3D.totalPosition;
        instantResult4D.totalRotation = instantResult3D.totalRotation;
        instantResult4D.j = instantResult3D.j;
        instantResult4D.k = instantResult3D.k;
        instantResult4D.l = instantResult3D.l;
        instantResult4D.primaryRay = instantResult3D.primaryRay;
        instantResult4D.primaryLinear = instantResult3D.primaryLinear;

        GameObject currentClone;
        List<GameObject> cloneList = new List<GameObject> ();
        bool primaryBullet = true;

        float speed;
        float acceleration;
        float maxSpeed;

        for (instantResult4D.l = 0; instantResult4D.l < formulaApply.delayAmount + 1; instantResult4D.l++) {
            //Instantiate the bullet
            if (formulaApply.rayAmount % 2 == 1)
            {
                if (formulaApply.linearAmount % 2 == 1)
                {
                    cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (instantResult4D.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (instantResult4D.k * 0.5f)));

                    if (!instantResult4D.primaryLinear)
                    {
                        cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, result.raySpacing * (instantResult4D.j * 0.5f));
                        currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (-instantResult4D.k * 0.5f)));
                    }

                    if (!instantResult4D.primaryRay)
                    {
                        cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-instantResult4D.j * 0.5f));
                        currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (instantResult4D.k * 0.5f)));

                        if (!instantResult4D.primaryLinear)
                        {
                            cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                            currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-instantResult4D.j * 0.5f));
                            currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (-instantResult4D.k * 0.5f)));
                        }
                    }
                }
                else //if (formulaApply.linearAmount % 2 == 0)
                {
                    cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (instantResult4D.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (instantResult4D.k * 0.5f)) + (result.linearSpacing * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (instantResult4D.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (-instantResult4D.k * 0.5f)) - (result.linearSpacing * 0.5f)));

                    if (!instantResult4D.primaryRay)
                    {
                        cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-instantResult4D.j * 0.5f));
                        currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (instantResult4D.k * 0.5f)) + (result.linearSpacing * 0.5f)));

                        cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-instantResult4D.j * 0.5f));
                        currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (-instantResult4D.k * 0.5f)) - (result.linearSpacing * 0.5f)));
                    }
                }
            }
            else //if (formulaApply.rayAmount % 2 == 0)
            {
                if (formulaApply.linearAmount % 2 == 1)
                {
                    cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, (result.raySpacing * (instantResult4D.j * 0.5f)) + (result.raySpacing * 0.5f));
                    currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (instantResult4D.k * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, (result.raySpacing * (-instantResult4D.j * 0.5f)) - (result.raySpacing * 0.5f));
                    currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (-instantResult4D.k * 0.5f)));

                    if (!instantResult4D.primaryLinear)
                    {
                        cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, (result.raySpacing * (instantResult4D.j * 0.5f)) + (result.raySpacing * 0.5f));
                        currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (-instantResult4D.k * 0.5f)));

                        cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                        currentClone.transform.Rotate (0f, 0f, (result.raySpacing * (-instantResult4D.j * 0.5f)) - (result.raySpacing * 0.5f));
                        currentClone.transform.Translate (Vector3.left * (result.linearSpacing * (instantResult4D.k * 0.5f)));
                    }
                }
                else //if (formulaApply.linearAmount % 2 == 0)
                {
                    cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (instantResult4D.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (instantResult4D.k * 0.5f)) + (result.linearSpacing * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (instantResult4D.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (-instantResult4D.k * 0.5f)) - (result.linearSpacing * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-instantResult4D.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (instantResult4D.k * 0.5f)) + (result.linearSpacing * 0.5f)));

                    cloneList.Add (currentClone = Instantiate (bullet, instantResult4D.totalPosition, instantResult4D.totalRotation) as GameObject);
                    currentClone.transform.Rotate (0f, 0f, result.raySpacing * (-instantResult4D.j * 0.5f));
                    currentClone.transform.Translate (Vector3.left * ((result.linearSpacing * (-instantResult4D.k * 0.5f)) - (result.linearSpacing * 0.5f)));
                }
            }

            foreach (GameObject thisClone in cloneList)
                ModSetup (thisClone, modApply, result.modificationExist);
          
            if (primaryBullet) {
                ProjectileController projectileController = currentClone.GetComponent<ProjectileController> ();

                primaryBullet = false;
                result.baseSpeed = projectileController.getSpeed ();
                result.baseAcceleration = projectileController.getAcceleration ();
                result.baseMaxSpeed = projectileController.getMaxSpeed ();
            }

            if (formulaApply.delayAmount > 0)
            {
                // 100 setSpeed * 1 - (bulletIndexNum * ((1 - (1 - (100 setValue / 100 valueRange))) / (4 bulletCount - 1)));  /* Sample! */
                speed = result.baseSpeed * (1 - (instantResult4D.l * ((1 - (1 - (formulaApply.speedOffset / 100))) / (formulaApply.delayAmount))));
                acceleration = result.baseAcceleration * (1 - (instantResult4D.l * ((1 - (1 - (formulaApply.speedOffset / 100))) / (formulaApply.delayAmount))));
                maxSpeed = result.baseMaxSpeed * (1 - (instantResult4D.l * ((1 - (1 - (formulaApply.speedOffset / 100))) / (formulaApply.delayAmount))));
            }
            else
            {
                speed = result.baseSpeed;
                acceleration = result.baseAcceleration;
                maxSpeed = result.baseMaxSpeed;
            }

            foreach (GameObject thisClone in cloneList)
            {
                ProjectileController projectileController = thisClone.GetComponent<ProjectileController> ();

                if (result.modificationExist)
                    projectileController.Modify (speed, acceleration, maxSpeed, modApply.damage, modApply.lifeSpan);
                else
                    projectileController.ModifyMotion (speed, acceleration, maxSpeed);
            }

            cloneList.Clear ();
        }
        yield return null;
    }
}


3216861–246415–Coroutine within Coroutine.zip (1.51 MB)
3216861--246416--Nested_Coroutine_For_Rays_and_Linears.gif

Wow, that’s a massive post. I didn’t read it all, but I would suggest that you reduce the complexity of your example (+ question) dramatically to show your exact issue… :slight_smile:

1 Like