diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/engine.c | 367 | ||||
-rw-r--r-- | src/field.c | 235 | ||||
-rw-r--r-- | src/functions.c | 678 | ||||
-rw-r--r-- | src/main.c | 61 | ||||
-rw-r--r-- | src/text.c | 9 |
5 files changed, 644 insertions, 706 deletions
diff --git a/src/engine.c b/src/engine.c new file mode 100644 index 0000000..6df3c79 --- /dev/null +++ b/src/engine.c @@ -0,0 +1,367 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <SFML/System/Clock.h> +#include <SFML/Graphics/RenderWindow.h> +#include <SFML/Graphics/Text.h> +#include <SFML/Graphics/RectangleShape.h> + +#include "common.h" +#include "tet_conf.h" +#include "text.h" +#include "field.h" +#include "engine.h" + +/* Externs from main.c */ +extern struct game game; +extern struct shape active, next; +extern struct field fld; + +extern sfFont *fontScore; + +extern char arrKeys; // Arrow keys states byte container + +extern sfClock *gameTick; +extern sfClock *putTick; +extern sfClock *mTick; +extern sfClock *repPushDown; // Clock for repeat latency when Down key held +extern sfClock *repKeyLeft; // Clock for repeat latency when Left key held +extern sfClock *repKeyRight; // Clock for repeat latency when Left key held + + + + + +void valueAfterTextDisplay(int value, List *texts, char *type) +{ + List *l = texts; + while (l) { + Text *text = (Text *)l->obj; + if (text->type) + if (!strcmp(text->type, type)) { + char a[64]; + if (text->text) { + if (strlen(text->text) > 52) { + memset(text->text+52, '\0', 1); + strcpy(a, text->text); + } + sprintf(a, "%s%d", text->text, value); + sfText_setString(text->sfText, (char *)&a); + break; + } + } + l = l->next; + } +} + +/* + * Removes line when cells all are in row in it + * + */ +int rmLines() +{ + int k = 0; // "Filled line" indicator + int s = 0; + for (int j = 0; j < 22; j++) { + for (int i = 0; i < 10; i++) + if (fld.c[j][i].a != 0) + k++; + if (k >= 10) { // If line is full + s++; // Give scores for line + for (int n = j; n < 22; n++) { // Drop all lines down + if (n == 21) { + for (int m = 0; m < 10; m++) { + fld.c[n][m].a = 0; + fld.c[n][m].fColor = UIBGCOLOR; + } + break; + } + for (int m = 0; m < 10; m++) { + fld.c[n][m].a = fld.c[n+1][m].a; + fld.c[n][m].fColor = fld.c[n+1][m].fColor; + } + } + j--; // Do not let loop to go to next line because + // next line go down by itself =) + } + k = 0; // Clear line fill indicator + } + return s; // Return number of deleted lines +} + +void checkLevelUp(struct game *game) +{ + while (game->lines >= LEVELUP_LINES) { + game->level++; + game->lines -= LEVELUP_LINES; + game->moveLatency = getMoveLatencyOfLevel(game->level); + } +} + +int getMoveLatencyOfLevel(int level) +{ + if (level >= 29) + return L29LATENCY; + else if (level >= 19) + return L19LATENCY; + else if (level >= 16) + return L16LATENCY; + else if (level >= 13) + return L13LATENCY; + else if (level >= 10) + return L10LATENCY; + else if (level == 9) + return L09LATENCY; + else if (level == 8) + return L08LATENCY; + else if (level == 7) + return L07LATENCY; + else if (level == 6) + return L06LATENCY; + else if (level == 5) + return L05LATENCY; + else if (level == 4) + return L04LATENCY; + else if (level == 3) + return L03LATENCY; + else if (level == 2) + return L02LATENCY; + else if (level == 1) + return L01LATENCY; + else if (level == 0) + return L00LATENCY; + return L00LATENCY; +} + + +/* + * Game tick + * + */ +void tTick() +{ // If tick exceeds current level tick latency + if (sfClock_getElapsedTime(gameTick).microseconds >= game.moveLatency) { + sfClock_restart(gameTick); + active.y--; // try + if (collide(&fld, &active)) + active.y++; // fallback + else + sfClock_restart(putTick); + if (sfClock_getElapsedTime(putTick).microseconds >= PUT_LATENCY) { + if (out_of_field(&fld, &active)) { + gameover(&game); + return; + } else { + putShape(&fld, &active); + int removedLines = rmLines(); + game.lines += removedLines; + switch (removedLines) { + case 1: + game.scoreCurrent += RM_1LINES_SCORE * game.level; + break; + case 2: + game.scoreCurrent += RM_2LINES_SCORE * game.level; + break; + case 3: + game.scoreCurrent += RM_3LINES_SCORE * game.level; + break; + case 4: + game.scoreCurrent += RM_4LINES_SCORE * game.level; + break; + } + active.t = next.t; + resetActiveShape(&fld, &active); + genNextShape(); + checkLevelUp(&game); + } + sfClock_restart(putTick); + } + } +} + + + + + + +/* + * Keys hold handler + * + */ +void tKeyCtrl() +{ + /* Up arrow key 'hold' handler */ + if (sfKeyboard_isKeyPressed(sfKeyUp)) { + if (!(arrKeys & UP)) { + arrKeys = arrKeys | UP; + rotate_shape(&fld, &active); + } + } else { + if ((arrKeys & UP)) { + arrKeys = arrKeys & ~UP; + } + } + + /* Down Arrow Key 'hold' handler */ + if (sfKeyboard_isKeyPressed(sfKeyDown)) { + if (!(arrKeys & DOWN)) { + arrKeys = arrKeys | DOWN; + active.y--; + if (collide(&fld, &active)) + active.y++; + else { + // Avoid excess move down by gameTick + sfClock_restart(putTick); + sfClock_restart(gameTick); + game.scoreCurrent++; + } + sfClock_restart(repPushDown); + } else { + if (sfClock_getElapsedTime(repPushDown).microseconds + >= moveRepeatLatency2) + arrKeys = arrKeys & ~DOWN; + } + } else { + if ((arrKeys & DOWN)) { + arrKeys = arrKeys & ~DOWN; + } + } + + /* Left Arrow Key 'hold' handler */ + if (sfKeyboard_isKeyPressed(sfKeyLeft) + && !sfKeyboard_isKeyPressed(sfKeyRight)) { + if (!(arrKeys & LEFT)) { + arrKeys = arrKeys | LEFT; + active.x--; + if (collide(&fld, &active)) + active.x++; + else + sfClock_restart(putTick); + sfClock_restart(repKeyLeft); + } else { + if (!(arrKeys & LEFTHOLD)) { + if (sfClock_getElapsedTime(repKeyLeft).microseconds + >= moveRepeatLatency1) { + arrKeys = arrKeys | LEFTHOLD; + arrKeys = arrKeys & ~LEFT; + } + } else { + if (sfClock_getElapsedTime(repKeyLeft).microseconds + >= moveRepeatLatency2) + arrKeys = arrKeys & ~LEFT; + } + } + } else if (!sfKeyboard_isKeyPressed(sfKeyLeft)) { + if ((arrKeys & LEFT)) { + arrKeys = arrKeys & ~LEFT; + arrKeys = arrKeys & ~LEFTHOLD; + } + } + + /* Right Arrow Key 'hold' handler */ + if (sfKeyboard_isKeyPressed(sfKeyRight) + && !sfKeyboard_isKeyPressed(sfKeyLeft)) { + if (!(arrKeys & RIGHT)) { + arrKeys = arrKeys | RIGHT; + active.x++; + if (collide(&fld, &active)) + active.x--; + else + sfClock_restart(putTick); + sfClock_restart(repKeyRight); + } else { + if (!(arrKeys & RIGHTHOLD)) { + if (sfClock_getElapsedTime(repKeyRight).microseconds + >= moveRepeatLatency1) { + arrKeys = arrKeys | RIGHTHOLD; + arrKeys = arrKeys & ~RIGHT; + } + } else if (!sfKeyboard_isKeyPressed(sfKeyLeft)) { + if (sfClock_getElapsedTime(repKeyRight).microseconds + >= moveRepeatLatency2) // Wait short time + arrKeys = arrKeys & ~RIGHT; + } + } + } else { + if ((arrKeys & RIGHT)) { + arrKeys = arrKeys & ~RIGHT; + arrKeys = arrKeys & ~RIGHTHOLD; + } + } +} + + +/* + * Colorize active cells of active shape (overlay only + * active cells above background of fld) + * + */ +void colorizeActive() +{ + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) + if (active.c[j][i] && j+active.y < 22) { + sfRectangleShape_setFillColor(fld.p[j + active.y][i + active.x], + active.fColor); + sfRectangleShape_setOutlineColor( + fld.p[j + active.y][i + active.x], UIFGACTIVECOLOR); + } +} + + +/* + * Draw all fld cells + * + */ +void drawFld(sfRenderWindow *window) +{ + for (int j = 0; j < fld.size.y; j++) + for (int i = 0; i < fld.size.x; i++) + sfRenderWindow_drawRectangleShape(window, fld.p[j][i], NULL); +} + + + + +void gameover(struct game *game) +{ + game->isStarted = 0; + game->scoreCurrent = 0; + game->level = 0; + game->moveLatency = L00LATENCY; + game->lines = 0; +} + + +void genNextShape() +{ + next.t = (rand() % 7) + 1; // Insert new random shape of 7 variants + load_shape(&next); + if (next.t == 5) + for (int j = 0; j < 3; j++) + for (int i = 0; i < 4; i++) + next.c[i][j] = next.c[i][j+1]; +} + + + + +void drawNextShape(sfRenderWindow *window) +{ + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) + if (next.c[j][i]) { + sfRectangleShape_setFillColor(next.p[j][i], next.fColor); + sfRectangleShape_setOutlineColor(next.p[j][i], UIFGACTIVECOLOR); + sfRenderWindow_drawRectangleShape(window, next.p[j][i], NULL); + } +} + +void freeFld() { + for (int j = 0; j < fld.size.y; j++) + for (int i = 0; i < fld.size.x; i++) + sfRectangleShape_destroy(fld.p[j][i]); + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) + sfRectangleShape_destroy(next.p[j][i]); +} diff --git a/src/field.c b/src/field.c new file mode 100644 index 0000000..dcb332d --- /dev/null +++ b/src/field.c @@ -0,0 +1,235 @@ +#include <stdlib.h> +#include <string.h> +#include <SFML/Graphics/RectangleShape.h> + +#include "field.h" +#include "tet_conf.h" + +/* Shapes maps */ +extern char arrShapeL[4][4]; +extern char arrShapeRL[4][4]; +extern char arrShapeZ[4][4]; +extern char arrShapeS[4][4]; +extern char arrShapeB[4][4]; +extern char arrShapeI[4][4]; +extern char arrShapeT[4][4]; + +static void rotate_shape_left(struct shape *shape); +static void rotate_shape_right(struct shape *shape); +static int out_of_bounds(struct field *fld, struct shape *active); + +void init_field(struct field *fld) +{ + sfVector2f fldCPos[22][10]; + for (int j = 0; j < fld->size.y; j++) { + for (int i = 0; i < fld->size.x; i++) { + fld->c[j][i].a = 0; // Inactive = empty + fldCPos[j][i].x + = fld->pos.x + (i * (fld->cSize.x + 2 * fld->cOutThick)); + fldCPos[j][i].y + = fld->pos.y - (j * (fld->cSize.y + 2 * fld->cOutThick)); + fld->p[j][i] = sfRectangleShape_create(); + sfRectangleShape_setFillColor(fld->p[j][i], UIBGCOLOR); + sfRectangleShape_setSize(fld->p[j][i], fld->cSize); + sfRectangleShape_setPosition(fld->p[j][i], fldCPos[j][i]); + sfRectangleShape_setOutlineColor(fld->p[j][i], UIFGACTIVECOLOR); + sfRectangleShape_setOutlineThickness(fld->p[j][i], fld->cOutThick); + } + } +} + +void colorize_field(struct field *fld) +{ + for (int j = 0; j < fld->size.y; j++) + for (int i = 0; i < fld->size.x; i++) + if (fld->c[j][i].a) { + sfRectangleShape_setFillColor(fld->p[j][i], fld->c[j][i].fColor); + sfRectangleShape_setOutlineColor(fld->p[j][i], UIFGACTIVECOLOR); + } else { + sfRectangleShape_setFillColor(fld->p[j][i], UIBGCOLOR); + sfRectangleShape_setOutlineColor(fld->p[j][i], UIFGINACTIVECOLOR); + } +} + +void colorize_field_random(struct field *fld) +{ + int a; + for (int j = 0; j < fld->size.y; j++) { + for (int i = 0; i < fld->size.x; i++) { + a = rand() % 7 + 1; + switch (a) { + case 1 : + sfRectangleShape_setFillColor(fld->p[j][i], LCOLOR); + break; + case 2 : + sfRectangleShape_setFillColor(fld->p[j][i], RLCOLOR); + break; + case 3 : + sfRectangleShape_setFillColor(fld->p[j][i], ZCOLOR); + break; + case 4 : + sfRectangleShape_setFillColor(fld->p[j][i], SCOLOR); + break; + case 5 : + sfRectangleShape_setFillColor(fld->p[j][i], BCOLOR); + break; + case 6 : + sfRectangleShape_setFillColor(fld->p[j][i], ICOLOR); + break; + case 7 : + sfRectangleShape_setFillColor(fld->p[j][i], TCOLOR); + break; + } + sfRectangleShape_setOutlineColor(fld->p[j][i], UIFGACTIVECOLOR); + } + } +} + +void init_next_shape_field(struct shape *next) +{ + sfVector2f nsPos; + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + nsPos.x = next->x + i *(next->cSize.x + 2 * next->cOutThick); + nsPos.y = next->y - j *(next->cSize.y + 2 * next->cOutThick); + next->p[j][i] = sfRectangleShape_create(); + sfRectangleShape_setSize(next->p[j][i], next->cSize); + sfRectangleShape_setPosition(next->p[j][i], nsPos); + sfRectangleShape_setOutlineThickness(next->p[j][i], next->cOutThick); + } + } +} + +/* + * Inserts shape into field, runs filled lines searching, puts new shape + * into the game at the top. + * + */ +void putShape(struct field *fld, struct shape *active) +{ + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) + if (active->c[j][i]) { + fld->c[j+active->y][i+active->x].a = active->c[j][i]; + fld->c[j+active->y][i+active->x].fColor = active->fColor; + } +} + +int out_of_field(struct field *fld, struct shape *active) +{ + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + if (active->c[i][j] && active->y + i >= fld->size.y) + return 1; + return 0; +} + +void load_shape(struct shape *shape) +{ + switch (shape->t) { // Copy cell active/inactive state + case 1 : + memcpy(&shape->c[0][0], &arrShapeL[0][0], sizeof(char)*4*4); + shape->fColor = LCOLOR; + break; + case 2 : + memcpy(&shape->c[0][0], &arrShapeRL[0][0], sizeof(char)*4*4); + shape->fColor = RLCOLOR; + break; + case 3 : + memcpy(&shape->c[0][0], &arrShapeZ[0][0], sizeof(char)*4*4); + shape->fColor = ZCOLOR; + break; + case 4 : + memcpy(&shape->c[0][0], &arrShapeS[0][0], sizeof(char)*4*4); + shape->fColor = SCOLOR; + break; + case 5 : + memcpy(&shape->c[0][0], &arrShapeB[0][0], sizeof(char)*4*4); + shape->fColor = BCOLOR; + break; + case 6 : + memcpy(&shape->c[0][0], &arrShapeI[0][0], sizeof(char)*4*4); + shape->fColor = ICOLOR; + break; + case 7 : + memcpy(&shape->c[0][0], &arrShapeT[0][0], sizeof(char)*4*4); + shape->fColor = TCOLOR; + break; + } +} + +void resetActiveShape(struct field *fld, struct shape *active) +{ + load_shape(active); + active->x = 3; + if (active->t == 6) + active->y = 19; + else + active->y = 18; + while (collide(fld, active)) { + active->y++; + } +} + +int collide(struct field *fld, struct shape *active) +{ + if (out_of_bounds(fld, active)) + return 1; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + if (active->c[i][j] && fld->c[i + active->y][j + active->x].a) + return 1; + return 0; +} + +static int out_of_bounds(struct field *fld, struct shape *active) +{ + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + if (active->c[i][j]) + if (active->x + j >= fld->bound.x || active->x + j < 0 + || active->y + i >= fld->bound.y || active->y + i < 0) + return 1; + return 0; +} + +static void rotate_shape_left(struct shape *shape) +{ + char arr[4][4]; + memcpy(&arr[0][0], &shape->c[0][0], sizeof(char)*4*4); + if (shape->t == 5) + return; + if (shape->t == 6) { + for (int j = 3; j >= 0; j--) + for (int i = 0; i < 4; i++) + shape->c[j][i] = arr[3-i][3-j]; + return; + } + for (int j = 3; j > 0; j--) + for (int i = 0; i < 3; i++) + shape->c[j][i] = arr[3-i][j-1]; +} + +static void rotate_shape_right(struct shape *shape) +{ + char arr[4][4]; + memcpy(&arr[0][0], &shape->c[0][0], sizeof(char)*4*4); + if (shape->t == 5) + return; + if (shape->t == 6) { + for (int j = 3; j >= 0; j--) + for (int i = 0; i < 4; i++) + shape->c[j][i] = arr[3-i][3-j]; + return; + } + for (int j = 3; j > 0; j--) + for (int i = 0; i < 3; i++) + shape->c[j][i] = arr[i+1][3-j]; +} + +void rotate_shape(struct field *fld, struct shape *shape) +{ + rotate_shape_right(shape); + if (collide(fld, shape)) + rotate_shape_left(shape); +} diff --git a/src/functions.c b/src/functions.c deleted file mode 100644 index eebbf67..0000000 --- a/src/functions.c +++ /dev/null @@ -1,678 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <SFML/System/Clock.h> -#include <SFML/Graphics/RenderWindow.h> -#include <SFML/Graphics/Text.h> -#include <SFML/Graphics/RectangleShape.h> - -#include "common.h" -#include "tet_conf.h" -#include "functions.h" - -/* Externs from main.c */ -extern Game game; -extern Shape active, next; -extern Field fld; - -extern sfFont *fontScore; - -extern char arrKeys; // Arrow keys states byte container - -extern sfClock *gameTick; -extern sfClock *putTick; -extern sfClock *mTick; -extern sfClock *repPushDown; // Clock for repeat latency when Down key held -extern sfClock *repKeyLeft; // Clock for repeat latency when Left key held -extern sfClock *repKeyRight; // Clock for repeat latency when Left key held - -/* Shapes maps */ -extern char arrShapeL[4][4]; -extern char arrShapeRL[4][4]; -extern char arrShapeZ[4][4]; -extern char arrShapeS[4][4]; -extern char arrShapeB[4][4]; -extern char arrShapeI[4][4]; -extern char arrShapeT[4][4]; - - -/* Field init routine */ -void initFld() -{ - sfVector2f fldCPos[22][10]; - /* Create field */ - for (int j = 0; j < fld.size.y; j++) { - for (int i = 0; i < fld.size.x; i++) { - fld.c[j][i].a = 0; // Inactive = empty - fldCPos[j][i].x - = fld.pos.x + (i * (fld.cSize.x + 2 * fld.cOutThick)); - fldCPos[j][i].y - = fld.pos.y - (j * (fld.cSize.y + 2 * fld.cOutThick)); - fld.p[j][i] = sfRectangleShape_create(); - sfRectangleShape_setFillColor(fld.p[j][i], UIBGCOLOR); - sfRectangleShape_setSize(fld.p[j][i], fld.cSize); - sfRectangleShape_setPosition(fld.p[j][i], fldCPos[j][i]); - sfRectangleShape_setOutlineColor(fld.p[j][i], UIFGACTIVECOLOR); - sfRectangleShape_setOutlineThickness(fld.p[j][i], fld.cOutThick); - } - } - /* Create next shape field */ - sfVector2f nsPos; - for (int j = 0; j < 4; j++) { - for (int i = 0; i < 4; i++) { - nsPos.x = next.x+i*(next.cSize.x+2*fld.cOutThick); - nsPos.y = next.y-j*(next.cSize.y+2*fld.cOutThick); - next.p[j][i] = sfRectangleShape_create(); - sfRectangleShape_setSize(next.p[j][i], next.cSize); - sfRectangleShape_setPosition(next.p[j][i], nsPos); - sfRectangleShape_setOutlineThickness(next.p[j][i], fld.cOutThick); - } - } - genNextShape(); - resetActiveShape(&active); -} - - -void valueAfterTextDisplay(int value, List *texts, char *type) -{ - List *l = texts; - while (l) { - Text *text = (Text *)l->obj; - if (text->type) - if (!strcmp(text->type, type)) { - char a[64]; - if (text->text) { - if (strlen(text->text) > 52) { - memset(text->text+52, '\0', 1); - strcpy(a, text->text); - } - sprintf(a, "%s%d", text->text, value); - sfText_setString(text->sfText, (char *)&a); - break; - } - } - l = l->next; - } -} - -/* - * Removes line when cells all are in row in it - * - */ -int rmLines() -{ - int k = 0; // "Filled line" indicator - int s = 0; - for (int j = 0; j < 22; j++) { - for (int i = 0; i < 10; i++) - if (fld.c[j][i].a != 0) - k++; - if (k >= 10) { // If line is full - s++; // Give scores for line - for (int n = j; n < 22; n++) { // Drop all lines down - if (n == 21) { - for (int m = 0; m < 10; m++) { - fld.c[n][m].a = 0; - fld.c[n][m].fColor = UIBGCOLOR; - } - break; - } - for (int m = 0; m < 10; m++) { - fld.c[n][m].a = fld.c[n+1][m].a; - fld.c[n][m].fColor = fld.c[n+1][m].fColor; - } - } - j--; // Do not let loop to go to next line because - // next line go down by itself =) - } - k = 0; // Clear line fill indicator - } - return s; // Return number of deleted lines -} - -/* - * Inserts shape into field, runs filled lines searching, puts new shape - * into the game at the top. - * - */ -void putShape() -{ - if (outOfFieldCheck(&fld, &active)) { - gameover(&game); - return; - } - for (int j = 0; j < 4; j++) - for (int i = 0; i < 4; i++) - if (active.c[j][i]) { - fld.c[j+active.y][i+active.x].a = active.c[j][i]; - if ((j+active.y >= 0) && (i+active.x >= 0)) - fld.c[j+active.y][i+active.x].fColor = active.fColor; - } - int removedLines = rmLines(); - game.lines += removedLines; - switch (removedLines) { - case 1: - game.scoreCurrent += RM_1LINES_SCORE * game.level; - break; - case 2: - game.scoreCurrent += RM_2LINES_SCORE * game.level; - break; - case 3: - game.scoreCurrent += RM_3LINES_SCORE * game.level; - break; - case 4: - game.scoreCurrent += RM_4LINES_SCORE * game.level; - break; - } - resetActiveShape(&active); - checkLevelUp(&game); -} - -int outOfFieldCheck(Field *fld, Shape *active) -{ - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - if (active->c[i][j] && active->y+i >= fld->size.y) { - gameover(&game); - return 1; - } - } - } - return 0; -} - -void checkLevelUp(Game *game) -{ - while (game->lines >= LEVELUP_LINES) { - game->level++; - game->lines -= LEVELUP_LINES; - game->moveLatency = getMoveLatencyOfLevel(game->level); - } -} - -int getMoveLatencyOfLevel(int level) -{ - if (level >= 29) - return L29LATENCY; - else if (level >= 19) - return L19LATENCY; - else if (level >= 16) - return L16LATENCY; - else if (level >= 13) - return L13LATENCY; - else if (level >= 10) - return L10LATENCY; - else if (level == 9) - return L09LATENCY; - else if (level == 8) - return L08LATENCY; - else if (level == 7) - return L07LATENCY; - else if (level == 6) - return L06LATENCY; - else if (level == 5) - return L05LATENCY; - else if (level == 4) - return L04LATENCY; - else if (level == 3) - return L03LATENCY; - else if (level == 2) - return L02LATENCY; - else if (level == 1) - return L01LATENCY; - else if (level == 0) - return L00LATENCY; - return L00LATENCY; -} - -void resetActiveShape(Shape *active) -{ - genNextShape(); - copyShape(active); - active->x = 3; - if (active->t == 6) - active->y = 19; - else - active->y = 18; - for (;;) { - if (cellCollisionCheckHere(&fld, active)) - active->y++; - else - break; - } -} - -/* - * Game tick - * - */ -void tTick() -{ // If tick exceeds current level tick latency - if (sfClock_getElapsedTime(gameTick).microseconds - >= game.moveLatency) { - sfClock_restart(gameTick); - /* if bottom not reached */ - if ((wallCollisionCheck(DOWN) == 0) - && (cellCollisionCheck(DOWN) == 0)) { - active.y--; // Move - sfClock_restart(putTick); - } else { - if (sfClock_getElapsedTime(putTick).microseconds >= PUT_LATENCY) { - putShape(); // Just put the shape - sfClock_restart(putTick); - } - } - } -} - - -/* - * Rotate matrix left routine - * - */ -void rotateLeft() -{ - char arr[4][4]; - memcpy(&arr[0][0], &active.c[0][0], sizeof(char)*4*4); - if (active.t == 5) - return; - if (active.t == 6) { - for (int j = 3; j >= 0; j--) - for (int i = 0; i < 4; i++) - active.c[j][i] = arr[3-i][3-j]; - return; - } - for (int j = 3; j > 0; j--) - for (int i = 0; i < 3; i++) - active.c[j][i] = arr[3-i][j-1]; -} - - -/* - * Rotate matrix right routine - * - */ -void rotateRight() -{ - char arr[4][4]; - memcpy(&arr[0][0], &active.c[0][0], sizeof(char)*4*4); - if (active.t == 5) - return; - if (active.t == 6) { - for (int j = 3; j >= 0; j--) - for (int i = 0; i < 4; i++) - active.c[j][i] = arr[3-i][3-j]; - return; - } - for (int j = 3; j > 0; j--) - for (int i = 0; i < 3; i++) - active.c[j][i] = arr[i+1][3-j]; -} - - -/* - * Rotates active shape with callling collision checkers - * - */ -void rotateShape() -{ - rotateRight(); // Try rotate - if ((wallRotCollisionCheck()) - || (cellRotCollisionCheck())) - rotateLeft(); -} - -int cellRotCollisionCheck() -{ - for (int j = 0; j < 4; j++) - for (int i = 0; i < 4; i++) - if (active.c[j][i] - && fld.c[j+active.y][i+active.x].a) - return 1; // Collision happens - return 0; // Else it do not -} - - -int wallRotCollisionCheck() -{ - if (active.y < 0) //If shape has crossed Bottom border - for (int i = 0; i < 4; i++) - if (active.c[-1-active.y][i]) - return 1; // Collision happens - if (active.x < 0) //If shape has crossed Left border - for (int i = 0; i < 4; i++) - if (active.c[i][-1-active.x]) - return 1; // Collision happens - if (active.x > 6) //If shape has crossed Right border - for (int i = 0; i < 4; i++) - if (active.c[i][3-(active.x-7)]) - return 1; // Collision happens - return 0; // If no conditions are met collision is absent -} - -int cellCollisionCheckHere(Field *fld, Shape *active) -{ - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) - if (active->y + i < fld->size.y) - if (active->c[i][j] && fld->c[i+active->y][j+active->x].a) - return 1; - return 0; -} - -int cellCollisionCheck(int dir) -{ - for (int j = 0; j < 4; j++) { - for (int i = 0; i < 4; i++) { - if ((dir & RIGHT) // Check Right - && (j+active.y >= 0) // Avoiding nonexisting fld cells - && (i+active.x+1 >= 0) // --- - && active.c[j][i] // Check activity - && fld.c[j+active.y][i+active.x+1].a) - return 1; // Collision happens - if ((dir & LEFT) // Check Left - && (j+active.y >= 0) // Avoiding nonexisting fld cells - && (i+active.x-1 >= 0) // --- - && active.c[j][i] // Check activity - && fld.c[j+active.y][i+active.x-1].a) - return 1; // Collision happens - if ((dir & DOWN) // Check Bottom - && (j+active.y-1 >= 0) // Avoiding nonexisting fld cells - && (i+active.x >= 0) // --- - && active.c[j][i] // Check activity - && fld.c[j+active.y-1][i+active.x].a) - return 1; // Collision happens - } - } - return 0; // Else it do not -} - -int wallCollisionCheck(int dir) -{ - if (dir & RIGHT) { // Right collision request - if (active.x >= 6) // If shape has reached Right boreder - for (int i = 0 ; i < 4; i++) - if (active.c[i][3-(active.x-6)]) - return 1; // Collision happens - } else if (dir & DOWN) { // Bottom collision request - if (active.y <= 0) //If shape has reached Bottom border - for (int i = 0; i < 4; i++) - if (active.c[-active.y][i]) - return 1; // Collision happens - } else if (dir & LEFT) // Left collision request - if (active.x <= 0) // If shape has reached Left border - for (int i = 0; i < 4; i++) - if (active.c[i][-active.x]) - return 1; // Collision happens - return 0; -} - - -/* - * Keys hold handler - * - */ -void tKeyCtrl() -{ - /* Up arrow key 'hold' handler */ - if (sfKeyboard_isKeyPressed(sfKeyUp)) { - if (!(arrKeys & UP)) { - arrKeys = arrKeys | UP; - rotateShape(); - } - } else { - if ((arrKeys & UP)) { - arrKeys = arrKeys & ~UP; - } - } - - /* Down Arrow Key 'hold' handler */ - if (sfKeyboard_isKeyPressed(sfKeyDown)) { - if (!(arrKeys & DOWN)) { - arrKeys = arrKeys | DOWN; - if (!wallCollisionCheck(DOWN) - && !cellCollisionCheck(DOWN)) { - active.y--; - // Avoid excess move down by gameTick - sfClock_restart(putTick); - sfClock_restart(gameTick); - game.scoreCurrent++; - } - repPushDown = sfClock_create(); - } else { - if (sfClock_getElapsedTime(repPushDown).microseconds - >= moveRepeatLatency2) - arrKeys = arrKeys & ~DOWN; - } - } else { - if ((arrKeys & DOWN)) { - arrKeys = arrKeys & ~DOWN; - } - } - - /* Left Arrow Key 'hold' handler */ - if (sfKeyboard_isKeyPressed(sfKeyLeft) - && !sfKeyboard_isKeyPressed(sfKeyRight)) { - if (!(arrKeys & LEFT)) { - arrKeys = arrKeys | LEFT; - if (!wallCollisionCheck(LEFT) - && !cellCollisionCheck(LEFT)) { - active.x--; - sfClock_restart(putTick); - } - repKeyLeft = sfClock_create(); - } else { - if (!(arrKeys & LEFTHOLD)) { - if (sfClock_getElapsedTime(repKeyLeft) - .microseconds - >= moveRepeatLatency1) { - arrKeys = arrKeys | LEFTHOLD; - arrKeys = arrKeys & ~LEFT; - } - } else { - if (sfClock_getElapsedTime(repKeyLeft) - .microseconds - >= moveRepeatLatency2) - arrKeys = arrKeys & ~LEFT; - } - } - } else if (!sfKeyboard_isKeyPressed(sfKeyLeft)) { - if ((arrKeys & LEFT)) { - arrKeys = arrKeys & ~LEFT; - arrKeys = arrKeys & ~LEFTHOLD; - } - } - - /* Right Arrow Key 'hold' handler */ - if (sfKeyboard_isKeyPressed(sfKeyRight) - && !sfKeyboard_isKeyPressed(sfKeyLeft)) { - if (!(arrKeys & RIGHT)) { - arrKeys = arrKeys | RIGHT; - if (!wallCollisionCheck(RIGHT) - && !cellCollisionCheck(RIGHT)) { - active.x++; - sfClock_restart(putTick); - } - repKeyRight = sfClock_create(); - } else { - if (!(arrKeys & RIGHTHOLD)) { - if (sfClock_getElapsedTime(repKeyRight).microseconds - >= moveRepeatLatency1) { - arrKeys = arrKeys | RIGHTHOLD; - arrKeys = arrKeys & ~RIGHT; - } - } else if (!sfKeyboard_isKeyPressed(sfKeyLeft)) { - if (sfClock_getElapsedTime(repKeyRight).microseconds - >= moveRepeatLatency2) // Wait short time - arrKeys = arrKeys & ~RIGHT; - } - } - } else { - if ((arrKeys & RIGHT)) { - arrKeys = arrKeys & ~RIGHT; - arrKeys = arrKeys & ~RIGHTHOLD; - } - } -} - - -/* - * Colorize active cells of field - * - */ -void colorizeFld() -{ - for (int j = 0; j < fld.size.y; j++) - for (int i = 0; i < fld.size.x; i++) - if (fld.c[j][i].a) { - sfRectangleShape_setFillColor(fld.p[j][i], fld.c[j][i].fColor); - sfRectangleShape_setOutlineColor(fld.p[j][i], UIFGACTIVECOLOR); - } else { - sfRectangleShape_setFillColor(fld.p[j][i], UIBGCOLOR); - sfRectangleShape_setOutlineColor(fld.p[j][i], UIFGINACTIVECOLOR); - } -} - -/* - * Colorize active cells of active shape (overlay only - * active cells above background of fld) - * - */ -void colorizeActive() -{ - for (int j = 0; j < 4; j++) - for (int i = 0; i < 4; i++) - if (active.c[j][i] && j+active.y < 22) { - sfRectangleShape_setFillColor( - fld.p[j+active.y][i+active.x], - active.fColor); - sfRectangleShape_setOutlineColor( - fld.p[j+active.y][i+active.x], - UIFGACTIVECOLOR); - } -} - - -/* - * Draw all fld cells - * - */ -void drawFld(sfRenderWindow *window) -{ - for (int j = 0; j < fld.size.y; j++) - for (int i = 0; i < fld.size.x; i++) - sfRenderWindow_drawRectangleShape(window, fld.p[j][i], NULL); -} - - -void colorizeRandom(Field *fld) -{ - int a; - for (int j = 0; j < fld->size.y; j++) { - for (int i = 0; i < fld->size.x; i++) { - a = rand()%7+1; - switch (a) { - case 1 : - sfRectangleShape_setFillColor(fld->p[j][i], LCOLOR); - break; - case 2 : - sfRectangleShape_setFillColor(fld->p[j][i], RLCOLOR); - break; - case 3 : - sfRectangleShape_setFillColor(fld->p[j][i], ZCOLOR); - break; - case 4 : - sfRectangleShape_setFillColor(fld->p[j][i], SCOLOR); - break; - case 5 : - sfRectangleShape_setFillColor(fld->p[j][i], BCOLOR); - break; - case 6 : - sfRectangleShape_setFillColor(fld->p[j][i], ICOLOR); - break; - case 7 : - sfRectangleShape_setFillColor(fld->p[j][i], TCOLOR); - break; - } - sfRectangleShape_setOutlineColor(fld->p[j][i], UIFGACTIVECOLOR); - } - } -} - - -void gameover(Game *game) -{ - game->isStarted = 0; - game->scoreCurrent = 0; - game->level = 0; - game->moveLatency = L00LATENCY; - game->lines = 0; -} - - -void genNextShape() -{ - active.t = next.t; - next.t = (rand()%7)+1; // Insert new random shape of 7 variants - copyShape(&next); - if (next.t == 5) - for (int j = 0; j < 3; j++) - for (int i = 0; i < 4; i++) - next.c[i][j] = next.c[i][j+1]; -} - - -void copyShape(Shape *localSh) -{ - switch (localSh->t) { // Copy cell active/inactive state - case 1 : - memcpy(&localSh->c[0][0], &arrShapeL[0][0], sizeof(char)*4*4); - localSh->fColor = LCOLOR; - break; - case 2 : - memcpy(&localSh->c[0][0], &arrShapeRL[0][0], sizeof(char)*4*4); - localSh->fColor = RLCOLOR; - break; - case 3 : - memcpy(&localSh->c[0][0], &arrShapeZ[0][0], sizeof(char)*4*4); - localSh->fColor = ZCOLOR; - break; - case 4 : - memcpy(&localSh->c[0][0], &arrShapeS[0][0], sizeof(char)*4*4); - localSh->fColor = SCOLOR; - break; - case 5 : - memcpy(&localSh->c[0][0], &arrShapeB[0][0], sizeof(char)*4*4); - localSh->fColor = BCOLOR; - break; - case 6 : - memcpy(&localSh->c[0][0], &arrShapeI[0][0], sizeof(char)*4*4); - localSh->fColor = ICOLOR; - break; - case 7 : - memcpy(&localSh->c[0][0], &arrShapeT[0][0], sizeof(char)*4*4); - localSh->fColor = TCOLOR; - break; - } -} - - -void drawNextShape(sfRenderWindow *window) -{ - for (int j = 0; j < 4; j++) - for (int i = 0; i < 4; i++) - if (next.c[j][i]) { - sfRectangleShape_setFillColor(next.p[j][i], next.fColor); - sfRectangleShape_setOutlineColor(next.p[j][i], UIFGACTIVECOLOR); - sfRenderWindow_drawRectangleShape(window, next.p[j][i], NULL); - } -} - -void freeFld() { - for (int j = 0; j < fld.size.y; j++) - for (int i = 0; i < fld.size.x; i++) - sfRectangleShape_destroy(fld.p[j][i]); - for (int j = 0; j < 4; j++) - for (int i = 0; i < 4; i++) - sfRectangleShape_destroy(next.p[j][i]); -} @@ -8,24 +8,25 @@ #include <SFML/Graphics/Font.h> #include "common.h" -#include "functions.h" #include "text.h" +#include "field.h" +#include "engine.h" #include "tet_conf.h" -Window w = {.mode = {450, 570, 32}}; -Game game = { +List *texts; +sfFont *fontScore; +struct shape active, next; +struct field fld; +struct window w = {.mode = {450, 570, 32}}; +struct game game = { .isStarted = 0, .scoreCurrent = 0, .level = 0, .moveLatency = L00LATENCY, .lines = 0 }; -List *texts; -sfFont *fontScore; -Shape active, next; -Field fld; -char arrKeys = 0b00000000; // Arrow keys states byte container +char arrKeys = 0; // Arrow keys states byte container sfClock *gameTick; sfClock *putTick; @@ -35,10 +36,13 @@ sfClock *repKeyLeft; // Clock for repeat latency when Left arrow long push sfClock *repKeyRight; // Clock for repeat latency when Left arrow long push void prepare() { - srand( time(NULL) ); + srand(time(NULL)); gameTick = sfClock_create(); putTick = sfClock_create(); mTick = sfClock_create(); + repPushDown = sfClock_create(); + repKeyLeft = sfClock_create(); + repKeyRight = sfClock_create(); fontScore = sfFont_createFromFile("dat/arial.ttf"); if (!fontScore) { printf("dat/arial.ttf font load failed"); @@ -52,17 +56,27 @@ void prepare() { fld.cSize = (sfVector2f){.x = 23, .y = 23}; //Fld's cell size in pixels fld.cOutThick = 1; fld.pos = (sfVector2i){.x = 10, .y = 10+550-24}; // Fld bot left corner - fld.size = (sfVector2i){.x = 10, .y = 22}; // Field's size in blocks + fld.size = (sfVector2i){.x = FLD_SIZE_X, .y = FLD_SIZE_Y}; // Field's size in blocks + fld.bound = (sfVector2i){.x = FLD_BOUND_X, .y = FLD_BOUND_Y}; // Field's bound in blocks - next = (Shape){.x = 250+10+20, .y = 200, - .cSize = {.x = 23, .y = 23}}; + next = (struct shape){ + .x = 250 + 10 + 20, + .y = 200, + .cOutThick = 1, + .cSize = {.x = 23, .y = 23} + }; - initFld(); - texts = ListOfText_getFromListOfKeyMapOfString(ListOfKeyMapOfString_getFromYaml("dat/texts.yaml")); - w.window = sfRenderWindow_create(w.mode, - windowName_conf, - sfResize | sfClose, - NULL); + init_field(&fld); + init_next_shape_field(&next); + genNextShape(); + active.t = next.t; + resetActiveShape(&fld, &active); + genNextShape(); + List *tmp = ListOfKeyMapOfString_getFromYaml("dat/texts.yaml"); + texts = ListOfText_getFromListOfKeyMapOfString(tmp); + ListOfKeyMapOfString_free(&tmp); + w.window = sfRenderWindow_create(w.mode, windowName_conf, + sfResize | sfClose, NULL); if (!w.window) exit(EXIT_FAILURE); sfRenderWindow_setFramerateLimit(w.window, 60); @@ -88,7 +102,7 @@ void gameLoop() { tKeyCtrl(); valueAfterTextDisplay(game.scoreCurrent, texts, "score"); valueAfterTextDisplay(game.level, texts, "level"); - colorizeFld(); + colorize_field(&fld); colorizeActive(); drawFld(w.window); drawNextShape(w.window); @@ -97,9 +111,9 @@ void gameLoop() { void menuTick() { - if(sfClock_getElapsedTime(mTick).microseconds >= basicLatency) { + if (sfClock_getElapsedTime(mTick).microseconds >= basicLatency) { sfClock_restart(mTick); - colorizeRandom(&fld); + colorize_field_random(&fld); } } @@ -110,7 +124,8 @@ void menuLoop() { if (sfKeyboard_isKeyPressed(sfKeyS) == 1) { game.isStarted = 1; freeFld(); - initFld(); + init_field(&fld); + init_next_shape_field(&next); sfClock_restart(gameTick); } } @@ -130,7 +145,7 @@ void mainLoop() { int main() { prepare(); - colorizeRandom(&fld); + colorize_field_random(&fld); mainLoop(); freeFld(); sfRenderWindow_destroy(w.window); @@ -77,7 +77,6 @@ KeyMap *KeyMap_put(KeyMap **keyMap, const void *key, const void *value) KeyMap *keyMapLocal = KeyMap_get(keyMap, key); if (!keyMapLocal) { keyMapLocal = KeyMap_new(keyMap); - keyMapLocal->pair = malloc(sizeof(Pair)); keyMapLocal->pair->k = malloc(strlen(key)+1); strcpy(keyMapLocal->pair->k, key); } @@ -180,7 +179,7 @@ void ListOfKeyMapOfString_free(List **list) *list = 0; } -int _loadText_getInt(void *obj, char *key) +static int _loadText_getInt(void *obj, char *key) { int v = 0; KeyMap *keyMap = KeyMap_get((KeyMap **)&obj, key); @@ -191,7 +190,7 @@ int _loadText_getInt(void *obj, char *key) return v; } -char *_loadText_getString(void *obj, char *key) +static char *_loadText_getString(void *obj, char *key) { char *v = 0; KeyMap *keyMap = KeyMap_get((KeyMap **)&obj, key); @@ -204,10 +203,10 @@ char *_loadText_getString(void *obj, char *key) return v; } -void _loadText_initSfText(Text *objo, void *obji) +static void _loadText_initSfText(Text *objo, void *obji) { sfVector2f pos = { - .x = _loadText_getInt(obji, "x"), + .x = _loadText_getInt(obji, "x"), .y = _loadText_getInt(obji, "y") }; int size = _loadText_getInt(obji, "size"); |