# Game logic

This section will detail how the player's action are interpreted into the game.  
We will only talk about pieces and not polyominoes. In this project, pieces are an abstraction of a polyomino. Though if you want to know more the polyominoes in this project, check [this other file](Pieces_representation.md).

## Order of operations

Each frame, the UI will translate the user's input into a series of action to apply to the game. The list of action is the following:

- Pause
- Retry
- Hold
- Move left
- Move right
- Rotate 0°
- Rotate clockwise (CW)
- Rotate 180°
- Rotate counter-clockwise (CCW)
- Soft drop
- Hard drop

Pausing and retrying are managed by the UI.  
IHS and IRS are always tested first (see the [leniency mechanics section](./game_logic.md#leniency-mechanics)).  
Then the rest of actions will be tested in the list's order. 
Finally, gravity and lock delay are applied last.  
Moving and soft dropping can be held but hard dropping, holding and rotating needs to be released and pressed again to happen.

Menu navigation is managed by the UI and uses static keybinds to prevent the user from softlocking themselves.

## ARR and DAS

The sidewise movement of the piece is defined by two parameters: DAS and ARR.  
**DAS** stands for Delayed Auto Shift and **ARR** for Auto Repeat Rate.
Theses can be changed by the player.
The parameters will be refered to as DAS and ARR, while the in-game values will be refered to as the piece's DAS ans ARR.

- Initially, both the piece DAS and piece ARR are at 0. When moving the piece in one direction,
the piece will move one position and then wait for the player to hold that direction as long as the DAS value.  
_So for exemple if DAS is set to 20, on the first frame piece DAS will be set to 1 and the piece will move once.
The next movement will be delayed by 20 frames, so the piece will move again 20 frames later, on the 21th frame, or when the piece DAS = (DAS +1)._
- Then, if the player still holds the same direction, ARR takes on.
The piece will move every ARR frames.  
_So in our exemple if ARR is set to 5, this means the piece will move every 5 frames after the 21th frame.
So on the 21th frame piece DAS = 21 and piece ARR = 0.
On the 26th frame, piece ARR = 5 so the piece moves and piece ARR is set back to 0._

Now DAS can be buffered, that is if a direction is held before the piece spawn, it will have an initial DAS value corresponding to the number of frames held.  
_So in our example where DAS = 20 and ARR = 5, if we held a direction during 30f then hold without releasing this direction, the piece will move instantly on the frame it spawns.
Then, ARR will start counting on the next frame. So the piece will move on frames 1, 6, 11, etc._

When trying to hold two directions at the same time, only the direction held last will be applied.
So for example if you were holding left and you suddendly start holding the two directions at the same time, the piece will go right.  
In the two directions are first pressed at the same frame, left will take priority.

## Leniency mechanics

In a general sense, we try to be kind to the players. Some of the following mechanics are just standards in a lot of stacker games, while other have been added because of this game using polyominoes of high sizes and thus being way harder to play.

When a piece touches the ground, there is a short time period before it automatically locks. This period is called _lock delay_. Lock delay is reset everytime the piece move. To not allow for infinite stalling, there is another longer period called _forced lock delay_ that does not reset when moving the piece.  
The player has a hold box in which they can temporarly store a piece. In this game, we allow the player to swap between the held piece and the active piece as much as they want. Once again to not allow for infinite stalling, forced lock delay does not reset when holding a piece.

If either holding or rotating happens during frames where no piece is in the board, they will be memorized and immediately applied upon spawning the next piece. This can sometime prevent the player from loosing when the default spawn would have lost the game. This is called IRS and IHS, for Instant Rotation/Hold System.  
IRS and IHS will fail if they actually loose the player the game when it would have not happened otherwise. In the same sense, holding always fails if it would loose the game.

## Kicking pieces

A common mechanic of stacker games is kicking. This happen when rotating a piece makes it collide with a wall. The game will try to move the piece in a few predetermined spot close to the current position until one of them allow the piece to not be in a wall again. If no positions allow for that, the rotation is simply cancelled.

This concept works very well for games with up to tetrominos or pentominos, but when using polyominoes of any size we can't choose a few predetermined spots for each piece.

Since this game uses polyomino of high sizes which are very unplayable, we will try to be complaisant to the player and allow as much kicking spots as possible, while trying not to make him feel like the piece is going through walls. To solve this problem, this game introduce a new Rotation System called **AutoRS**, which does not have a predetermined list of spots to fit the piece but instead adapt to its shape. Its algorithm goes as follow:

1. Before rotating, mark every position containing the piece or touching the piece, we will call the set of all theses positions the ``safePositions``
2. Rotate the piece, if it fit stop the algorithm
3. Try fitting the piece, going from the center to the sides, that means we try to move the piece 1 position right, then 1 position left, then 2 position right, etc. until it fit (and then stop the algorithm), if at one point none of the squares of the pieces are in one of the ``safePositions`` we stop trying in this direction
4. Move the piece one line down, and repeat step 3 again, until we hit a line were the first position (shifted by 0 positions horizontally) touched none of the ``safePositions``
5. Do the same as step 4 but now we move the piece one line up every time
6. Cancel the rotation

_Note: at step 3, the direction which is checked first is actually the last movement done by the player._  
Kicking is primarly designed for rotating, but there is also a 0° rotation applied when a piece spawns into a wall.  
0° rotations will first try to move the piece one position down, and if it can't, try kicking the piece, only registering a kick if the piece couldn't move down.

## Detecting spins

Another common mechanic of stacker games that goes alongside kicking is spinning. A spin is a special move (a move is calculated once a piece has been locked to the board) which usually happen when the last move a piece did was a kick or a rotation and the piece is locked in place or is locked in certain corners, but the rules varies a lot from game to game. 

Since we work with a great deal of different size and shapes, the rules for spin dectection have been simplified greatly:

- A move is a _spin_ if the piece is locked in place, that is it can't be moved one position up, down, left or right without hitting a wall
- A move is a _mini spin_ if the move isn't a spin and the last action of the piece was a kick (dropping down because of gravity counts as an action)

## Score calculation

- When locking a piece, add 1 to the score if it is due to lock delay, or 10 if it was hard dropped.
- When clearing one line, add 100 to the score, 200 for 2 lines, 400 for 3 lines, 800 for 4 lines, 1600 for 5 lines, etc.
- If the line clear is a spin, count the score like a normal clear of 2x more line (200 for 1-line spin, 800 for 2, 3200 for 3, etc.)
- When performing a spin, a mini spin, or clearing 4 or more lines, B2B is activated, every subsequent line clear that is a spin, a mini spin, or clear 4 or more lines, scores twice as much

## Grade calculation

Grade is an alternate system to line clears.

- Each time a piece is dropped, 1 point is added to the total.
- For each cleared line, 1 point is added to the total.

The only exception occurs when the total ends in '99', a line must be cleared to progress.
When this line is cleared, the point of the piece is also counted towards the total.

## Pieces distribution

A bag is an object which contains a set of pieces.
The principle of a bag generator is to put every available pieces into a bag and take them out one by one until the bag is empty, to then start with a new full bag.
It's a way to have equal distribution of pieces while still allowing for a random order of pieces.

The game has 3 modes of pieces distribution:

1. Default. The simplest of them, all selected pieces are put in a single bag.
2. Uniformous. The pieces are now separated by size and put in different bags. Each size will now appear as often as any other.
3. Custom. The pieces are once again separated by size, but now the player specifies how likely each size is to appear.

Both system 2 and 3 uses a system analogous to a bag to determine which size of piece to take next.
