// Update is called once per frame
    void Update()
    {
        fElapsedSeconds = Time.deltaTime; // seconds
        destHouseInds.Clear();

        IndieDevBehavior[] indieDevs = GlobalObjects.GetIndieDevs();
        foreach (IndieDevBehavior indieDev in indieDevs)
        {
            if (!indieDev.alive)
                continue;
            indieDev.aiDevGuy.waiting = false;
            indieDev.aiDevGuy.forcedNoWait = false;
        }

        for (int h = 0; h < GlobalObjects.indieHouseLocations.Count; h++)
        {
            GlobalObjects.indieHouseLocations[h].UpdateCurseState(fElapsedSeconds);

            if (!GlobalObjects.indieHouseLocations[h].isPresent && !GlobalObjects.indieHouseLocations[h].cursed)
            {
                int waitingCount = 0;
                IndieDevBehavior[] indies = GlobalObjects.GetIndieDevs();
                List<IndieDevBehavior> waitingDevs = new List<IndieDevBehavior>();
                bool enough = false;
                foreach (IndieDevBehavior indieDev in indies)
                {
                    if (!indieDev.alive)
                        continue;
                    int devBlock = waver.PositionToBlockIndex(indieDev.aiDevGuy.Position);
                    if (devBlock == GlobalObjects.indieHouseLocations[h].houseTileInd)
                    {
                        if (enough)
                        {
                            indieDev.aiDevGuy.waiting = false;
                        }
                        else
                        {
                            if (indieDev.aiDevGuy.dontWait > 0)
                            {
                                indieDev.aiDevGuy.dontWait -= fElapsedSeconds;
                                indieDev.aiDevGuy.waiting = false;
                                indieDev.aiDevGuy.forcedNoWait = true;
                            }
                            else
                            {
                                ++waitingCount;
                                indieDev.aiDevGuy.waiting = true;
                                indieDev.aiDevGuy.waited += fElapsedSeconds;
                                indieDev.aiDevGuy.dontWait = 0f;
                                waitingDevs.Add(indieDev);
                                if (waitingCount >= IndieHouseLocation.MAX_DEVS_IN_INDIE_HOUSE)
                                {
                                    enough = true;
                                }
                            }
                        }
                    }
                }
                if (waitingCount >= IndieHouseLocation.MIN_DEVS_TO_CREATE_A_HOUSE)
                {
                    GlobalObjects.indieHouseLocations[h].CreateHouse(waitingDevs);
                }
                else
                {
                    foreach (IndieDevBehavior waitingDev in waitingDevs)
                    {
                        if (waitingDev.aiDevGuy.waited >= DevGuy.MAX_WAIT)
                        {
                            GlobalObjects.indieHouseLocations[h].HouseDestroyed(); // to curse it
                            break;
                        }
                    }
                }
            }

            if ((!GlobalObjects.indieHouseLocations[h].isPresent && !GlobalObjects.indieHouseLocations[h].cursed)
                || !GlobalObjects.indieHouseLocations[h].IsFull())
            {
                destHouseInds.Add(new HouseIndices(GlobalObjects.indieHouseLocations[h].houseTileInd, h));
            }
        }

        indieDevs = GlobalObjects.GetIndieDevs();
        List<DevToProcess> devsToProcess = new List<DevToProcess>();

        foreach (IndieDevBehavior indieDev in indieDevs)
        {
            if (!indieDev.alive)
                continue;

            if (indieDev.aiDevGuy.waiting)
            {
                if (indieDev.aiDevGuy.waited >= DevGuy.MAX_WAIT)
                {
                    indieDev.aiDevGuy.waited = 0f;
                    indieDev.aiDevGuy.waiting = false;
                    indieDev.aiDevGuy.dontWait = DevGuy.DONT_WAIT;
                    indieDev.aiDevGuy.lastHousePointInd = waver.PositionToBlockIndex(indieDev.aiDevGuy.Position);
                    indieDev.StartAnim();
                }
                else
                {
                    indieDev.StopAnim();
                    continue;
                }
            }
            else
            {
                if (!indieDev.aiDevGuy.forcedNoWait)
                {
                    indieDev.aiDevGuy.waited = 0f;
                    indieDev.aiDevGuy.waiting = false;
                    indieDev.aiDevGuy.dontWait = 0f;
                }
                indieDev.StartAnim();
            }

            DevToProcess d = new DevToProcess();
            d.devGuy = indieDev.aiDevGuy;
            d.currentBlock = waver.PositionToBlockIndex(d.devGuy.Position);

            for (int h = 0; h < destHouseInds.Count; h++)
            {
                bool bSkip = CheckImmediateProximity(d.devGuy, d.currentBlock, destHouseInds[h]);
                if (bSkip)
                    continue;
            }

            // update the track if it needs to
            if (d.devGuy.currentTrack != null && d.devGuy.currentTrack.Length() == 0)
            {
                d.devGuy.currentTrack = null;
            }

            int p1SPInd = startSpawnPointInd;
            int p2SPInd = d.devGuy.lastHousePointInd >= 0 ? d.devGuy.lastHousePointInd : startSpawnPointInd;

            d.hasTrack = d.devGuy.currentTrack != null;
            //UnityEngine.Debug.Log(string.Format("pos {0} {1}", devGuy.Position.x, devGuy.Position.y));
            //UnityEngine.Debug.Log(string.Format("current block ind {0}", d.currentBlock));
            d.p1SPInd = p1SPInd;
            d.p2SPInd = p2SPInd;

            devsToProcess.Add(d);
        }
        devsToProcess.Sort(DevToProcessComparison);
        int i=0;
        while (i<devsToProcess.Count && devsToProcess[i].hasTrack)
        {
            ++i;
            continue;
        }
        while (i<devsToProcess.Count)
        {
            int j=i+1;
            while (j<devsToProcess.Count && devsToProcess[i].currentBlock == devsToProcess[j].currentBlock)
                ++j;

            Waver useWaver = waver;
            useWaver.needsRun = true;

            if (devsToProcess[i].currentBlock == startLocation.houseTileInd)
            {
                useWaver = startLocation.waver;
            }
            else
            {
                for (int h = 0; h < GlobalObjects.indieHouseLocations.Count; h++)
                {
                    if (GlobalObjects.indieHouseLocations[h].houseTileInd == devsToProcess[i].currentBlock)
                    {
                        useWaver = GlobalObjects.indieHouseLocations[h].waver;
                        break;
                    }
                }
            }

            bool hasTracks = useWaver.needsRun ? useWaver.StartWave(devsToProcess[i].currentBlock, levelMatrix) : useWaver.HasTracks();
            if (hasTracks)
            {
                List<Track> tracks = useWaver.ChooseTracks(j-i, devsToProcess[i].p1SPInd, devsToProcess[i].p2SPInd, devsToProcess[i].devGuy.lastVisitedBlockIndex);
                if (tracks.Count == 0)
                {
                    UnityEngine.Debug.Log("NO Tracks???");
                    for (int k = i; k < j; ++k)
                    {
                        devsToProcess[k].devGuy.currentTrack = null;
                    }
                }
                else
                {
                    System.Diagnostics.Debug.Assert(tracks.Count == j - i);
                    for (int k = i; k < j; ++k)
                    {
                        devsToProcess[k].devGuy.currentTrack = tracks[k-i];
                    }
                }

                /*
                for (int k = i; k < j; ++k)
                {
                    devsToProcess[k].devGuy.currentTrack = useWaver.ChooseTrack(devsToProcess[k].p1SPInd, devsToProcess[k].p2SPInd, devsToProcess[k].devGuy.lastVisitedBlockIndex);
                    if (devsToProcess[k].devGuy.currentTrack != null)
                    {
                        devsToProcess[k].devGuy.currentTrack = devsToProcess[k].devGuy.currentTrack.Clone();
                    }
                    System.Diagnostics.Debug.Assert(devsToProcess[k].devGuy.currentTrack == null || !devsToProcess[k].devGuy.currentTrack.HasBlock(devsToProcess[k].p1SPInd));
                    System.Diagnostics.Debug.Assert(devsToProcess[k].devGuy.currentTrack == null || !devsToProcess[k].devGuy.currentTrack.HasBlock(devsToProcess[k].p2SPInd));
                    //UnityEngine.Debug.Log(string.Format("Gave track to {0}", k));
                    /*
                    for (int ii = 0; ii < devsToProcess[k].devGuy.currentTrack.track.Count; ++ii)
                    {
                        int ind1, ind2;
                        waver.BlockIndexToCoords(devsToProcess[k].devGuy.currentTrack.track[ii], out ind1, out ind2);
                        Vector3 baseWorldPos = MathUtil.GetWorldPositionFromGridCoordinate(GetComponent<MeshFilter>(), ind1 + .5f, ind2 + .5f, MapWidth, MapHeight);
                        Transform newDev = (Transform)Instantiate(debugPrefab, baseWorldPos, Quaternion.identity);
                        newDev.position = baseWorldPos;
                        GlobalObjects.GetGlobbalGameState().ScaleInstance(newDev);
                    }
                    UnityEngine.Debug.Log(string.Format("{0}", devsToProcess[k].devGuy.currentTrack.ToSrting()));
                }
                */
            }
            i=j;
        }

        foreach (DevToProcess d in devsToProcess)
        {
            if (d.devGuy.currentTrack == null)
            {
                continue;
            }
            // do smooth movement
            int nextBlockInd = d.devGuy.currentTrack.PeekNext();

            //UnityEngine.Debug.Log(string.Format("next block ind {0}", nextBlockInd));
            //Debug.Print(String.Format("{0}, cur {1}, next {2}, track: {3}", devGuy.type, currentBlock, nextBlockInd, devGuy.currentTrack.ToSrting()));
            bool areWeThereYet = nextBlockInd != d.currentBlock ? MoveTowards(d.devGuy, d.currentBlock, nextBlockInd, (d.devGuy.currentTrack.makeHaste ? hasteSpeedMultiplier * calmSpeed : calmSpeed)) : true;
            if (areWeThereYet)
            {
                if (nextBlockInd != d.currentBlock)
                    d.devGuy.lastVisitedBlockIndex = d.currentBlock;
                d.currentBlock = d.devGuy.currentTrack.PopNext();
            }
        }
    }
 static int CompareDevsToProcess(DevToProcess a, DevToProcess b)
 {
     int ai = !a.hasTrack ? -1 : a.currentBlock;
     int bi = !b.hasTrack ? -1 : b.currentBlock;
     return bi - ai;
 }