Beispiel #1
0
 //This method performs the actual "hold" action. The argument is the piece entering hold. The method sends the piece leaving hold (if any) to Orchestrator.SpawnPiece().
 public void HoldPieceAction(BagPiece incomingPiece)
 {
     if (cooldown <= 0)
     {
         PersistantVars.pVars.PlaySound(SoundEffects.PIECE_HOLD);
         //Check for spiked hold. Note: This must be done before the actual hold action. Were it the other way around, it would be possible to spawn a piece then push a mino up inside that spawned piece with the garbage.
         if (ref_Orchestrator.ref_CurseManager.IsCurseActive(Curse.SPIKED_HOLD))
         {
             spikes++;
             if (spikes >= SPIKED_HOLD_THRESHOLD)
             {
                 spikes = 0;
                 Stats.stats.IncStat("Garbage added from Spiked Hold");
                 ref_Orchestrator.ref_Board.AddCleanGarbage();
             }
             UpdateSpikeDisplay();
         }
         //Now handle the actual hold action.
         if (piecePrototype.HasProperty(BagPiece.EMPTY_HOLD)) //If there is no hold piece...
         {
             ref_Orchestrator.SpawnNextPiece();               //...just spawn the next piece.
         }
         else //If there is a hold piece...
         {
             ref_Orchestrator.SpawnPiece(piecePrototype, true);                                           //...Spawn that hold piece. //true argument means that the piece to be spawned DID come from hold.
         }
         piecePrototype = incomingPiece;                                                                  //Place the incoming piece into hold.
         cooldown       = 1 + (ref_Orchestrator.ref_CurseManager.IsCurseActive(Curse.SLOW_HOLD) ? 1 : 0); //Sets cooldown to 1 normally, or 2 if slow hold curse is active.
         UpdateDisplay();
     }
 }
Beispiel #2
0
    /*
     * // Update is called once per frame
     * void Update()
     * {
     *
     * } */


    public void UpdateDisplay(BagPiece piece, int numInQueue, bool isFogActive)
    {
        Vector2Int displayOffset = new Vector2Int(0, 0); //As the piece is drawn relative to the center-of-rotation mino, it needs to be shifted right and down so it doesn't collide with other pieces or the board. This indicates how much.

        //^The above was a class field, I don't think it needs to be a class field.
        //Set base properties
        minoes  = PIECE_DATA[piece.pieceID].minoes;
        texture = PIECE_DATA[piece.pieceID].DetermineQueueTexture(piece, numInQueue, isFogActive);
        //Calculate displayOffset and displayHeight
        int minX = 0; //We don't need maxX because we don't actually care how far right the piece stretches.
        int minY = 0;
        int maxY = 0;

        foreach (Vector2Int mino in minoes) //Find the leftmost, topmost, and bottommost minoes.
        {
            minX = Mathf.Min(minX, mino.x);
            minY = Mathf.Min(minY, mino.y);
            maxY = Mathf.Max(maxY, mino.y);
        }
        //Set display height
        float displayHeight = (maxY - minY + 2) * MINO_SIZE; //Add two; one for an off-by-one error, one for padding.

        ownTransform.sizeDelta = new Vector2(QUEUE_DISPLAY_WIDTH, displayHeight);
        //Set the display offset accordingly.
        displayOffset.x = minX * -1;
        displayOffset.y = maxY * -1;
        //Set displayMinoes.
        displayMinoes = new Vector2Int[minoes.Length];
        for (int i = 0; i < minoes.Length; i++)
        {
            displayMinoes[i] = minoes[i] + displayOffset;
        }
    }
Beispiel #3
0
 //ResetObject is a method that appears in several object scripts that resets it to start-of-game values.
 public void ResetObject()
 {
     piecePrototype = new BagPiece(0, BagPiece.EMPTY_HOLD); //Initialize hold with a "hold is empty" piece.
     cooldown       = 0;
     spikes         = 0;
     ephemeral      = 0;
     UpdateDisplay();
 }
Beispiel #4
0
    //BuildPseudoBag generates a bag for use in the Pseudo extra modes. A pseudo bag consists of all seven tetrominoes, two "very nice" pseudos, two "nice" pseudos, and one "mean" pseudo.
    public void BuildPseudoBag()
    {
        BagPiece[] bag = new BagPiece[12];
        //First, add the seven tetrominoes.
        for (int i = 0; i < TETRA_BAG.Length; i++)
        {
            bag[i] = new BagPiece(TETRA_BAG[i]);
        }
        //Add two "very nice" pseudos.
        int firstPiece = VERY_NICE_PSEUDOS[Random.Range(0, VERY_NICE_PSEUDOS.Length)];
        int secondPiece;

        while (true)
        {
            secondPiece = VERY_NICE_PSEUDOS[Random.Range(0, VERY_NICE_PSEUDOS.Length)];
            if (firstPiece != secondPiece)
            {
                break;
            }
        }
        bag[7] = new BagPiece(firstPiece);
        bag[8] = new BagPiece(secondPiece);
        //Add two "nice" pseudos.
        firstPiece = NICE_PSEUDOS[Random.Range(0, NICE_PSEUDOS.Length)];
        while (true)
        {
            secondPiece = NICE_PSEUDOS[Random.Range(0, NICE_PSEUDOS.Length)];
            if (firstPiece != secondPiece)
            {
                break;
            }
        }
        bag[9]  = new BagPiece(firstPiece);
        bag[10] = new BagPiece(secondPiece);
        //Add a "mean" pseudo.
        bag[11] = new BagPiece(MEAN_PSEUDOS[Random.Range(0, MEAN_PSEUDOS.Length)]);
        //Shuffle using the Fisher-Yates method, a shuffle proven to be the most efficient in both time (runs in O(n)) and memory (runs in-place with only one extra "swap" variable).
        for (int i = 0; i < bag.Length; i++)
        {
            int      selectedElement = Random.Range(i, bag.Length);
            BagPiece swap            = bag[selectedElement];
            bag[selectedElement] = bag[i];
            bag[i] = swap;
        }
        AddBag(bag);
    }
Beispiel #5
0
 // BuildSetBag() generates a bag with a given set of pieces. Used in extra modes.
 public void BuildSetBag(int[] pieces)
 {
     BagPiece[] bag = new BagPiece[pieces.Length];
     for (int i = 0; i < pieces.Length; i++)
     {
         bag[i] = new BagPiece(pieces[i]);
     }
     //Shuffle using the Fisher-Yates method, a shuffle proven to be the most efficient in both time (runs in O(n)) and memory (runs in-place with only one extra "swap" variable).
     for (int i = 0; i < pieces.Length; i++)
     {
         int      selectedElement = Random.Range(i, pieces.Length);
         BagPiece swap            = bag[selectedElement];
         bag[selectedElement] = bag[i];
         bag[i] = swap;
     }
     AddBag(bag);
 }
Beispiel #6
0
    // BuildCursedBag() generates a bag of pieces to be added to the queue, in the main "cursed" game mode.
    public void BuildCursedBag()
    {
        //First, we need a new list of curses for this bag. Ask CurseManager to generate that.
        int[]           bagCurses = ref_Orchestrator.ref_CurseManager.CreateNewCurses();
        List <BagPiece> bag       = new List <BagPiece>(INITIAL_BAG_LIST_SIZE);

        //Add the basic tetrominoes to the list.
        for (int i = 0; i < 7; i++)
        {
            bag.Add(new BagPiece(i));
        }
        //If serenity is active, add two monominoes.
        if (bagCurses[0] < 0)
        {
            int monoIndex = ref_Orchestrator.mirrorMonominoRotation ? MIRROR_MONOMINO_PIECE_INDEX : MONOMINO_PIECE_INDEX; //This takes care of the "mirror monomino teleportation" player setting.
            for (int i = 0; i < MONOMINOES_PER_SERENE_BAG; i++)
            {
                bag.Add(new BagPiece(monoIndex));
            }
        }
        //If pentomino curse is active, add pentominoes. Adds one "nice" pentomino then any other pentomino, and never the same one twice.
        if (IsCurseActiveThisBag(bagCurses, Curse.PENTA))
        {
            int nicePentomino = NICE_PENTOMINOES[Random.Range(0, NICE_PENTOMINOES.Length)];
            int otherPentomino;
            while (true)
            {
                otherPentomino = Random.Range(PENTOMINOES_START_INDEX, PENTOMINOES_END_INDEX + 1);
                if (otherPentomino != nicePentomino)
                {
                    break;
                }
            }
            bag.Add(new BagPiece(nicePentomino));
            bag.Add(new BagPiece(otherPentomino));
        }
        //If h curse is active, add h piece.
        if (IsCurseActiveThisBag(bagCurses, Curse.SMALL_H))
        {
            bag.Add(new BagPiece(H_PIECE_INDEX));
        }
        //If drought is active, add three more tetrominoes (three unique pieces, none of which may be I or T)
        if (IsCurseActiveThisBag(bagCurses, Curse.DROUGHT))
        {
            int[] pieceList = (int[])DROUGHT_FLOOD_PIECES.Clone();
            //Sorta hacky but effective way to pick three unique pieces; just shuffle the list and use the first three. Because we only care about the first three, we can stop the shuffle after three. The shuffle itself is the ever-famous Fisher-Yates shuffle.
            for (int i = 0; i < 3; i++)
            {
                int randomIndex = Random.Range(i, 5);
                int temp        = pieceList[i];
                pieceList[i]           = pieceList[randomIndex];
                pieceList[randomIndex] = temp;
            }
            //Add the pieces to the bag. (Note: Technically, this loop can be merged into the one above, and also a couple lines from the above loop are unnecessary, but in this case I'm choosing clean and easy-to-read-later code over fast code.
            for (int i = 0; i < 3; i++)
            {
                bag.Add(new BagPiece(pieceList[i]));
            }
        }
        //If pseudo is active, add two pseudo pieces (which can't be two of the same piece)
        if (IsCurseActiveThisBag(bagCurses, Curse.PSEUDO))
        {
            int firstPiece = Random.Range(PSEUDO_START_INDEX, PSEUDO_END_INDEX + 1);
            int secondPiece;
            while (true)
            {
                secondPiece = Random.Range(PSEUDO_START_INDEX, PSEUDO_END_INDEX + 1);
                if (firstPiece != secondPiece)
                {
                    break;
                }
            }
            bag.Add(new BagPiece(firstPiece));
            bag.Add(new BagPiece(secondPiece));
        }
        //If twin is active, add a twinned piece.
        if (IsCurseActiveThisBag(bagCurses, Curse.TWIN))
        {
            int piece = Random.Range(TWIN_START_INDEX, TWIN_END_INDEX + 1);
            bag.Add(new BagPiece(piece));
        }
        //If big is active, add a big piece.
        if (IsCurseActiveThisBag(bagCurses, Curse.BIG))
        {
            int piece = Random.Range(BIG_START_INDEX, BIG_END_INDEX + 1);
            bag.Add(new BagPiece(piece));
        }
        //If big O is active, add a big O piece.
        if (IsCurseActiveThisBag(bagCurses, Curse.BIG_O))
        {
            bag.Add(new BagPiece(BIG_O_PIECE_INDEX));
        }
        //If big H is active, add a big H piece.
        if (IsCurseActiveThisBag(bagCurses, Curse.BIG_H))
        {
            bag.Add(new BagPiece(BIG_H_PIECE_INDEX));
        }
        //Shuffle the bag. This is done by creating a new array, picking a random value from the list, putting it in the array, removing it from the list, and repeating.
        BagPiece[] shuffledBag;
        if (IsCurseActiveThisBag(bagCurses, Curse.FLOOD)) //If Flood is active, make space for the extra Flood pieces generated after shuffle.
        {
            shuffledBag = new BagPiece[bag.Count + 3];
        }
        else
        {
            shuffledBag = new BagPiece[bag.Count];
        }
        int length = bag.Count;

        //The actual shuffle
        for (int i = 0; i < length; i++)
        {
            int index = Random.Range(0, bag.Count);
            shuffledBag[i] = bag[index];
            bag.RemoveAt(index);
        }
        //If flood is active, add three of the same (non-I, non-T) piece. Must be done AFTER shuffle so they stay together in the queue.
        if (IsCurseActiveThisBag(bagCurses, Curse.FLOOD))
        {
            //Hoo boy, you know the off-by-one error potential is bad when you have to break out pencil and paper, but I'm about 80% sure this is all correct.
            int randomPiece    = DROUGHT_FLOOD_PIECES[Random.Range(0, DROUGHT_FLOOD_PIECES.Length)];
            int randomLocation = Random.Range(0, shuffledBag.Length - 2);     // Where Length-2 comes from: Start with Length becasue the flood can be inserted before any piece. Now add 1 because the flood can also be inserted at the end of the list as well. Now subtract 3 because the last three elements aren't pieces. Add 1 because Range() is exclusive on the upper bound. And subtract 1 because arrays index from 0. Len+1-3+1-1. Len-2. aaaaaaaaaaaaaaa.
            //Move everything in that randomLocation and onwards forward 3 places to make room for the flood pieces.
            for (int i = shuffledBag.Length - 1; i > randomLocation + 2; i--) // Where randomLocation+2 comes from: You need to clear out indices from randomLocation to randomLocation+2. If randomLocation+2 is clear, you're done.
            {
                shuffledBag[i] = shuffledBag[i - 3];
            }
            //Now add the flood pieces
            shuffledBag[randomLocation]     = new BagPiece(randomPiece);
            shuffledBag[randomLocation + 1] = new BagPiece(randomPiece);
            shuffledBag[randomLocation + 2] = new BagPiece(randomPiece);
        }
        //Handle disguise curse: If active, three random pieces are disguised and assigned the wrong color.
        if (IsCurseActiveThisBag(bagCurses, Curse.DISGUISE))
        {
            int i = 0;
            while (i < DISGUISES_PER_BAG)
            {
                int rand = Random.Range(0, shuffledBag.Length);
                if (!shuffledBag[rand].HasAnyCursedProperty())
                {
                    shuffledBag[rand].AddProperty(BagPiece.DISGUISED);
                    i++;
                }
            }
        }
        //Handle hard curse: If active, one random piece is made hard. Hard pieces must be cleared twice. The first time they are cleared, lines above them don't fall.
        if (IsCurseActiveThisBag(bagCurses, Curse.HARD))
        {
            int i = 0;
            while (i < HARDS_PER_BAG)
            {
                int rand = Random.Range(0, shuffledBag.Length);
                if (!shuffledBag[rand].HasAnyCursedProperty())
                {
                    shuffledBag[rand].AddProperty(BagPiece.HARD);
                    i++;
                }
            }
        }
        //Handle floating curse: If active, one random pieces is made floaty. Floaty pieces lock in one mino above where they would otherwise lock in, and cannot be soft-dropped and aren't affected by gravity.
        if (IsCurseActiveThisBag(bagCurses, Curse.FLOATING))
        {
            int i = 0;
            while (i < FLOATINGS_PER_BAG)
            {
                int rand = Random.Range(0, shuffledBag.Length);
                if (!shuffledBag[rand].HasAnyCursedProperty())
                {
                    shuffledBag[rand].AddProperty(BagPiece.FLOATING);
                    i++;
                }
            }
        }
        //Commit the bag to queue
        AddBag(shuffledBag);
    }