Skip to content

Commit

Permalink
SRS wall kicks implemented, readme update
Browse files Browse the repository at this point in the history
  • Loading branch information
szymor committed Sep 21, 2020
1 parent 3666b92 commit be33e22
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 32 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ yet another tetris klone in action
- frame limiting, counting and upscaling code by Artur 'zear' Rojek
- in-game music by Vomitron
- some tetromino randomizers thanks to Simon Laroche ([link](https://simon.lc/the-history-of-tetris-randomizers))
- SRS wall kicks thanks to [Tetris Wiki](https://tetris.fandom.com/wiki/SRS)

Feel free to report errors.

Expand All @@ -30,8 +31,8 @@ For more, please refer to the source code.

### ideas / plans
- animated mascot (becchi?) evolving while playing or saying random things during gameplay
- animated background
- better score system (combos, T-spins)
- advanced wall kick
- rumble support for Bittboy
- line clear animation (TGM?)
- ports for other platforms
Expand Down
1 change: 1 addition & 0 deletions inc/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ struct Shape
{
enum BlockOrientation blockmap[FIG_DIM*FIG_DIM];
int cx, cy; // correction of position after CW rotation
int phase;
};

struct Figure
Expand Down
121 changes: 90 additions & 31 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@

#define START_DROP_RATE 2.00

#define TEST_NUM (5)
#define PHASE_NUM (4)

struct ShapeTemplate
{
int blockmap[FIG_DIM*FIG_DIM];
int cx, cy;
int phase;
};


Expand Down Expand Up @@ -100,58 +104,80 @@ static const struct ShapeTemplate templates[] = {
1, 1, 1, 1,
0, 0, 0, 0 },
.cx = 0,
.cy = 0
.cy = 0,
.phase = 2
},
{ // O
.blockmap = { 0, 0, 0, 0,
0, 1, 1, 0,
0, 1, 1, 0,
0, 0, 0, 0 },
.cx = 0,
.cy = 0
.cy = 0,
.phase = 0
},
{ // T
.blockmap = { 0, 0, 0, 0,
0, 1, 0, 0,
1, 1, 1, 0,
0, 0, 0, 0 },
.cx = 0,
.cy = 1
.cy = 1,
.phase = 0
},
{ // S
.blockmap = { 0, 0, 0, 0,
0, 1, 1, 0,
1, 1, 0, 0,
0, 0, 0, 0 },
.cx = 0,
.cy = 1
.cy = 1,
.phase = 0
},
{ // Z
.blockmap = { 0, 0, 0, 0,
1, 1, 0, 0,
0, 1, 1, 0,
0, 0, 0, 0 },
.cx = 0,
.cy = 1
.cy = 1,
.phase = 0
},
{ // J
.blockmap = { 0, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 0,
0, 0, 0, 0 },
.cx = 0,
.cy = 1
.cy = 1,
.phase = 0
},
{ // L
.blockmap = { 0, 0, 0, 0,
0, 0, 1, 0,
1, 1, 1, 0,
0, 0, 0, 0 },
.cx = 0,
.cy = 1
.cy = 1,
.phase = 0
}
};

// source: https://tetris.fandom.com/wiki/SRS
// phase, testid, x, y
static const int wallkick_data[PHASE_NUM][TEST_NUM][2] = {
{ { 0, 0}, {-1, 0}, {-1,-1}, { 0, 2}, {-1, 2} },
{ { 0, 0}, { 1, 0}, { 1, 1}, { 0,-2}, { 1,-2} },
{ { 0, 0}, { 1, 0}, { 1,-1}, { 0, 2}, { 1, 2} },
{ { 0, 0}, {-1, 0}, {-1, 1}, { 0,-2}, {-1,-2} }
};
static const int wallkick_data_figI[PHASE_NUM][TEST_NUM][2] = {
{ { 0, 0}, {-2, 0}, { 1, 0}, {-2, 1}, { 1,-2} },
{ { 0, 0}, {-1, 0}, { 2, 0}, {-1,-2}, { 2, 1} },
{ { 0, 0}, { 2, 0}, {-1, 0}, { 2,-1}, {-1, 2} },
{ { 0, 0}, { 1, 0}, {-2, 0}, { 1, 2}, {-2,-1} }
};

void initialize(void);
void finalize(void);
struct Shape *generateFromTemplate(const struct ShapeTemplate *template);
Expand Down Expand Up @@ -181,6 +207,7 @@ enum FigureId getNextColor(enum FigureId id);
enum FigureId getRandomColor(void);
void rotateFigureCW(void);
void rotateFigureCCW(void);
bool rotateTest(int x, int y);

static void softdrop_off(void);
static void softdrop_on(void);
Expand Down Expand Up @@ -415,6 +442,7 @@ struct Shape *generateFromTemplate(const struct ShapeTemplate *template)

sh->cx = template->cx;
sh->cy = template->cy;
sh->phase = template->phase;
for (int i = 0; i < FIG_DIM * FIG_DIM; ++i)
{
if (template->blockmap[i])
Expand Down Expand Up @@ -798,22 +826,31 @@ static void right_on(void)

static void rotate_cw(void)
{
bool success = true;
if (NULL == figures[0])
return;

bool success = false;

int phase = figures[0]->shape.phase;
const int (*tests)[2] = (FIGID_I == figures[0]->id) ?
wallkick_data_figI[phase] :
wallkick_data[phase];
rotateFigureCW();
if (isFigureColliding())
for (int i = 0; i < TEST_NUM; ++i)
{
++figures[0]->x;
if (isFigureColliding())
if (rotateTest(tests[i][0], tests[i][1]))
{
figures[0]->x -= 2;
if (isFigureColliding())
{
rotateFigureCCW();
++figures[0]->x;
success = false;
}
figures[0]->x += tests[i][0];
figures[0]->y += tests[i][1];
success = true;
break;
}
}
if (!success)
{
rotateFigureCCW();
}

if (success && figures[0] && figures[0]->id != FIGID_O)
{
updateEasySpin();
Expand All @@ -827,22 +864,32 @@ static void rotate_cw(void)

static void rotate_ccw(void)
{
bool success = true;
if (NULL == figures[0])
return;

bool success = false;

rotateFigureCCW();
if (isFigureColliding())
int phase = figures[0]->shape.phase;
const int (*tests)[2] = (FIGID_I == figures[0]->id) ?
wallkick_data_figI[phase] :
wallkick_data[phase];

for (int i = 0; i < TEST_NUM; ++i)
{
++figures[0]->x;
if (isFigureColliding())
if (rotateTest(-tests[i][0], -tests[i][1]))
{
figures[0]->x -= 2;
if (isFigureColliding())
{
rotateFigureCW();
++figures[0]->x;
success = false;
}
figures[0]->x -= tests[i][0];
figures[0]->y -= tests[i][1];
success = true;
break;
}
}
if (!success)
{
rotateFigureCW();
}

if (success && figures[0] && figures[0]->id != FIGID_O)
{
updateEasySpin();
Expand Down Expand Up @@ -1017,8 +1064,8 @@ void spawnFigure(void)

if (figures[0] != NULL)
{
figures[0]->y = -FIG_DIM + 2; // ...to gain a 'slide' effect from the top of screen
figures[0]->x = (BOARD_WIDTH - FIG_DIM) / 2; // ...to center a figure
figures[0]->y = -FIG_DIM + 2;
figures[0]->x = (BOARD_WIDTH - FIG_DIM) / 2; // center a figure
memcpy(&figures[0]->shape, getShape(figures[0]->id), sizeof(figures[0]->shape));
++statistics[figures[0]->id];
}
Expand Down Expand Up @@ -1183,6 +1230,8 @@ void rotateFigureCW(void)
int tcx = figures[0]->shape.cx;
figures[0]->shape.cx = -figures[0]->shape.cy;
figures[0]->shape.cy = tcx;

figures[0]->shape.phase = (figures[0]->shape.phase + 1) % PHASE_NUM;
}
}

Expand All @@ -1193,6 +1242,16 @@ void rotateFigureCCW(void)
rotateFigureCW();
}

bool rotateTest(int x, int y)
{
figures[0]->x += x;
figures[0]->y += y;
bool result = isFigureColliding();
figures[0]->x -= x;
figures[0]->y -= y;
return !result;
}

void incMod(int *var, int limit, bool sat)
{
if (sat && *var == limit - 1)
Expand Down

0 comments on commit be33e22

Please sign in to comment.