diff options
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | dat/texts.yaml | 16 | ||||
-rw-r--r-- | include/common.h | 2 | ||||
-rw-r--r-- | include/draw.h | 18 | ||||
-rw-r--r-- | include/engine.h | 15 | ||||
-rw-r--r-- | include/field.h | 8 | ||||
-rw-r--r-- | include/idlist.h | 5 | ||||
-rw-r--r-- | include/painter.h | 15 | ||||
-rw-r--r-- | include/tet_conf.h | 49 | ||||
-rw-r--r-- | include/text.h | 50 | ||||
-rw-r--r-- | include/vector.h | 7 | ||||
-rw-r--r-- | src/engine.c | 493 | ||||
-rw-r--r-- | src/field.c | 1 | ||||
-rw-r--r-- | src/idlist.c | 11 | ||||
-rw-r--r-- | src/main.c | 116 | ||||
-rw-r--r-- | src/painter.c (renamed from src/draw.c) | 185 | ||||
-rw-r--r-- | src/text.c | 287 |
17 files changed, 663 insertions, 630 deletions
@@ -6,23 +6,24 @@ TARGET:=tetris BUILD:=build SRC:=src SOURCES:=$(wildcard $(SRC)/*.c) -OBJECTS:=$(patsubst $(SRC)/%.c,$(BUILD)/%.c.o,$(SOURCES)) +OBJECTS:=$(SOURCES:$(SRC)/%.c=$(BUILD)/%.c.o) +DEPENDS:=$(OBJECTS:.o=.d) INCLUDE+=include -INCLUDE:=$(patsubst %,-I%,$(INCLUDE)) +INCLUDE:=$(INCLUDE:%=-I%) -#COMMON+=-fsanitize=address +COMMON+=-fsanitize=address CFLAGS+=$(COMMON) CFLAGS+=$(INCLUDE) CFLAGS+=-Wall CFLAGS+=-Wextra CFLAGS+=-Wpedantic -CFLAGS+=-Wduplicated-branches -CFLAGS+=-Wduplicated-cond CFLAGS+=-std=c11 +CFLAGS+=-fms-extensions CFLAGS+=-g3 CFLAGS+=-O0 +CFLAGS+=-MMD -MP LDFLAGS+=$(COMMON) LDFLAGS+=-lcsfml-graphics @@ -32,12 +33,14 @@ LDFLAGS+=-lyaml #====================================================================== +all: all: $(TARGET) $(TARGET): $(OBJECTS) $(QQ) echo " LD $@" $(Q) $(CC) -o $@ $^ $(LDFLAGS) +$(DEPENDS): | $(BUILD) $(OBJECTS): | $(BUILD) $(BUILD): @@ -47,6 +50,8 @@ $(BUILD)/%.c.o: $(SRC)/%.c $(QQ) echo " CC $@" $(Q) $(CC) -c $(CFLAGS) -o $@ $< +-include $(DEPENDS) + clean: $(Q) $(RM) -rfv $(TARGET) $(BUILD) diff --git a/dat/texts.yaml b/dat/texts.yaml index 5c35142..dec419c 100644 --- a/dat/texts.yaml +++ b/dat/texts.yaml @@ -1,5 +1,13 @@ --- - + type: "score.value" + scene: "game" + font: "Arial" + size: 20 + x: 350 + y: 10 + +- type: "score" scene: "game" text: "Score: " @@ -9,6 +17,14 @@ y: 10 - + type: "level.value" + scene: "game" + font: "Arial" + size: 20 + x: 350 + y: 44 + +- type: "level" scene: "game" text: "Level: " diff --git a/include/common.h b/include/common.h index 098ea9e..ca2e499 100644 --- a/include/common.h +++ b/include/common.h @@ -9,5 +9,5 @@ struct game { sfClock *mTick; sfClock *repPushDown; // repeat latency when hold Down arrow sfClock *repKeyLeft; // repeat latency when hold Left arrow - sfClock *repKeyRight; // repeat latency when hold Left arrow + sfClock *repKeyRight; // repeat latency when hold Right arrow }; diff --git a/include/draw.h b/include/draw.h deleted file mode 100644 index 17bf176..0000000 --- a/include/draw.h +++ /dev/null @@ -1,18 +0,0 @@ -struct window { - sfVideoMode mode; - sfRenderWindow *window; - sfEvent event; -}; - -void painter_init_window(); -void painter_destroy_window(); - -unsigned long painter_register_field(); -void painter_update_field(unsigned long id, struct field *fld); -void painter_destroy_field(unsigned long id); -void painter_destroy_fields(); - -void painter_draw(); - -void painter_destroy_drawables(); -void painter_destroy_all(); diff --git a/include/engine.h b/include/engine.h index bca16ed..4e0ee33 100644 --- a/include/engine.h +++ b/include/engine.h @@ -1,13 +1,2 @@ -#define RIGHT (1 << 0) -#define DOWN (1 << 1) -#define UP (1 << 2) -#define LEFT (1 << 3) -#define RIGHTHOLD (1 << 4) -#define LEFTHOLD (1 << 5) - -void tKeyCtrl(); -void tTick(); -void checkLevelUp(struct game *game); -int getMoveLatencyOfLevel(unsigned int level); -void valueAfterTextDisplay(int value, List *texts, char *type); -void gameover(struct game *game); +void transition_init(void); +void main_loop(void); diff --git a/include/field.h b/include/field.h index 93f80f0..30ed56b 100644 --- a/include/field.h +++ b/include/field.h @@ -6,14 +6,6 @@ struct cell { unsigned int color; }; -struct vector2i { - int x, y; -}; - -struct vector2ui { - unsigned int x, y; -}; - /* * field + shape coord system * y diff --git a/include/idlist.h b/include/idlist.h index d1badc7..3318be4 100644 --- a/include/idlist.h +++ b/include/idlist.h @@ -8,5 +8,6 @@ struct idlist { struct idlist *list_new(); struct idlist *list_append(struct idlist *list); struct idlist *list_get(const struct idlist *list, unsigned long id); -void list_rm_node(struct idlist *node); -void list_foreach(struct idlist *list, void (*job)(void *)); +void list_rm_node(struct idlist *node); +void list_foreach(struct idlist *list, void (*job)(void *)); +void list_destroy(struct idlist *list); diff --git a/include/painter.h b/include/painter.h new file mode 100644 index 0000000..7bcb47a --- /dev/null +++ b/include/painter.h @@ -0,0 +1,15 @@ +void painter_set_window(sfRenderWindow *window); + +void painter_load_font(char *filename); +void painter_destroy_font(); + +unsigned long painter_register_field(struct field *fld); +void painter_update_field(unsigned long id, struct field *fld); +unsigned long painter_register_text(struct text *txt); +void painter_update_text(unsigned long id, struct text *txt); + +void painter_draw(); + +void painter_destroy_drawable(unsigned long id); +void painter_destroy_drawables(); +void painter_destroy_all(); diff --git a/include/tet_conf.h b/include/tet_conf.h index 14a8c2a..c5a6153 100644 --- a/include/tet_conf.h +++ b/include/tet_conf.h @@ -16,23 +16,38 @@ // first repeat move when long push #define moveRepeatLatency2 30000 // microseconds, for Left, Right and Down // arrows, the rest repeat move when long push -#define basicLatency 500000 -#define L00LATENCY 800000 -#define L01LATENCY 716667 -#define L02LATENCY 633334 -#define L03LATENCY 550000 -#define L04LATENCY 466667 -#define L05LATENCY 383334 -#define L06LATENCY 300000 -#define L07LATENCY 216667 -#define L08LATENCY 133334 -#define L09LATENCY 100000 -#define L10LATENCY 83334 -#define L13LATENCY 66667 -#define L16LATENCY 50000 -#define L19LATENCY 33334 -#define L29LATENCY 16667 -#define PUT_LATENCY 300000 +#define basicLatency 500000 +#define L00LATENCY 800000 +#define L01LATENCY 716667 +#define L02LATENCY 633334 +#define L03LATENCY 550000 +#define L04LATENCY 466667 +#define L05LATENCY 383334 +#define L06LATENCY 300000 +#define L07LATENCY 216667 +#define L08LATENCY 133334 +#define L09LATENCY 100000 +#define L10LATENCY 83334 +#define L11LATENCY L10LATENCY +#define L12LATENCY L10LATENCY +#define L13LATENCY 66667 +#define L14LATENCY L13LATENCY +#define L15LATENCY L13LATENCY +#define L16LATENCY 50000 +#define L17LATENCY L16LATENCY +#define L18LATENCY L16LATENCY +#define L19LATENCY 33334 +#define L20LATENCY L19LATENCY +#define L21LATENCY L19LATENCY +#define L22LATENCY L19LATENCY +#define L23LATENCY L19LATENCY +#define L24LATENCY L19LATENCY +#define L25LATENCY L19LATENCY +#define L26LATENCY L19LATENCY +#define L27LATENCY L19LATENCY +#define L28LATENCY L19LATENCY +#define L29LATENCY 16667 +#define PUT_LATENCY 300000 #define RM_1LINES_SCORE 40 #define RM_2LINES_SCORE 100 #define RM_3LINES_SCORE 300 diff --git a/include/text.h b/include/text.h index 73285bf..c1de778 100644 --- a/include/text.h +++ b/include/text.h @@ -1,39 +1,15 @@ -typedef struct List { - void *obj; - void *next; - void *prev; -} List; - -typedef struct Pair { - void *k; - void *v; -} Pair; - -typedef struct KeyMap { - Pair *pair; - void *next; - void *prev; -} KeyMap; - -typedef struct Text { - char *font; - char *type; - char *scene; - char *text; - void *sfText; +#define TXT_ATTR_INVISIBLE (1 << 0) + +typedef struct text { + char *type; + char *scene; + char *font; + char *text; + unsigned int size; + struct vector2ui pos; + unsigned int attr; + unsigned long id; } Text; -FILE *openFile(char *filename); -void checkArgs(int argc, char **argv); -KeyMap *KeyMap_getLast(KeyMap **keyMap); -KeyMap *KeyMap_new(KeyMap **keyMap); -KeyMap *KeyMap_get(KeyMap **keyMap, const void *key); -KeyMap *KeyMap_put(KeyMap **keyMap, const void *key, const void *value); -List *List_getLast(List **list); -List *List_new(List **list); -List *ListOfKeyMapOfString_getFromYaml(char *filename); -void KeyMapOfString_free(KeyMap *keyMap); -void ListOfKeyMapOfString_free(List **list); -List *ListOfText_getFromListOfKeyMapOfString(List *list); -void Text_free(Text *obj); -void ListOfText_free(List **list); +struct idlist *load_texts(char *filename); +void text_destroy(void *text); diff --git a/include/vector.h b/include/vector.h new file mode 100644 index 0000000..fb00384 --- /dev/null +++ b/include/vector.h @@ -0,0 +1,7 @@ +struct vector2i { + int x, y; +}; + +struct vector2ui { + unsigned int x, y; +}; diff --git a/src/engine.c b/src/engine.c index 9840b34..c218105 100644 --- a/src/engine.c +++ b/src/engine.c @@ -7,41 +7,97 @@ #include <SFML/Graphics/Text.h> #include "common.h" +#include "idlist.h" #include "tet_conf.h" +#include "vector.h" #include "text.h" #include "field.h" -#include "draw.h" +#include "painter.h" #include "engine.h" +#define RIGHT (1 << 0) +#define UP (1 << 1) +#define DOWN (1 << 2) +#define LEFT (1 << 3) +#define RIGHTHOLD (1 << 4) +#define LEFTHOLD (1 << 7) + +int level_move_latency[] = { + L00LATENCY, + L01LATENCY, + L02LATENCY, + L03LATENCY, + L04LATENCY, + L05LATENCY, + L06LATENCY, + L07LATENCY, + L08LATENCY, + L09LATENCY, + L10LATENCY, + L11LATENCY, + L12LATENCY, + L13LATENCY, + L14LATENCY, + L15LATENCY, + L16LATENCY, + L17LATENCY, + L18LATENCY, + L19LATENCY, + L20LATENCY, + L21LATENCY, + L22LATENCY, + L23LATENCY, + L24LATENCY, + L25LATENCY, + L26LATENCY, + L27LATENCY, + L28LATENCY, + L29LATENCY +}; + +int rmlines_score[] = { + 0, + RM_1LINES_SCORE, + RM_2LINES_SCORE, + RM_3LINES_SCORE, + RM_4LINES_SCORE +}; + /* Externs from main.c */ -extern struct game game; -extern struct field fld, nxt; - -extern char arrKeys; // Arrow keys states byte container - -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; +extern struct game game; +extern struct field fld, nxt; +extern struct idlist *texts; +extern char arrKeys; + +static void render_score_value(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->type, "score.value")) { + if (!text->text) + text->text = malloc(sizeof(char) * BUFSIZ); + sprintf(text->text, "%d", game.scoreCurrent); } } -void checkLevelUp(struct game *game) +static void render_level_value(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->type, "level.value")) { + if (!text->text) + text->text = malloc(sizeof(char) * BUFSIZ); + sprintf(text->text, "%d", game.level); + } +} + +static int getMoveLatencyOfLevel(unsigned int level) +{ + if (level > 29) + return level_move_latency[29]; + else + return level_move_latency[level]; +} + +static void level_up(struct game *game) { while (game->lines >= LEVELUP_LINES) { game->level++; @@ -50,206 +106,259 @@ void checkLevelUp(struct game *game) } } -int getMoveLatencyOfLevel(unsigned 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(game.gameTick).microseconds >= game.moveLatency) { - sfClock_restart(game.gameTick); - fld.shape[0].y--; // try - if (field_shape_collision(&fld, &fld.shape[0])) - fld.shape[0].y++; // fallback +static void hide_menu_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "menu")) + text->attr |= TXT_ATTR_INVISIBLE; +} + +static void show_menu_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "menu")) + text->attr &= ~TXT_ATTR_INVISIBLE; +} + +static void hide_game_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "game")) + text->attr |= TXT_ATTR_INVISIBLE; +} + +static void show_game_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "game")) + text->attr &= ~TXT_ATTR_INVISIBLE; +} + +static void update_menu_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "menu")) + painter_update_text(text->id, text); +} + +static void update_game_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "game")) + painter_update_text(text->id, text); +} + +static void transition_game_over() +{ + game.isStarted = 0; + game.scoreCurrent = 0; + game.level = 0; + game.moveLatency = L00LATENCY; + game.lines = 0; + + nxt.attr |= FLD_ATTR_INVISIBLE; + painter_update_field(nxt.id, &nxt); + + fld.shape[0].y = fld.size.y; + field_fill_random(&fld); + painter_update_field(fld.id, &fld); + + list_foreach(texts, show_menu_text); + list_foreach(texts, hide_game_text); + list_foreach(texts, update_menu_text); + list_foreach(texts, update_game_text); +} + +static void transition_put_shape() +{ + field_put_shape(&fld, &fld.shape[0]); + int removedLines = field_rm_lines(&fld); + game.lines += removedLines; + game.scoreCurrent += rmlines_score[removedLines] * game.level; + fld.shape[0].t = nxt.shape[0].t; + field_reset_walking_shape(&fld, 0); + for (unsigned int s = 0; s < nxt.shape_cnt - 1; ++s) { + nxt.shape[s] = nxt.shape[s + 1]; + nxt.shape[s].y = 4 - s * 3; + } + shape_gen_random(&nxt.shape[nxt.shape_cnt - 1]); + level_up(&game); +} + +static void game_tick() +{ + sfClock_restart(game.gameTick); + fld.shape[0].y--; // try + if (field_shape_collision(&fld, &fld.shape[0])) + fld.shape[0].y++; // fallback + else + sfClock_restart(game.putTick); + if (sfClock_getElapsedTime(game.putTick).microseconds >= PUT_LATENCY) { + if (field_shape_out_of_bounds(&fld, &fld.shape[0])) + transition_game_over(); else - sfClock_restart(game.putTick); - if (sfClock_getElapsedTime(game.putTick).microseconds >= PUT_LATENCY) { - if (field_shape_out_of_bounds(&fld, &fld.shape[0])) { - gameover(&game); - fld.shape[0].y = fld.size.y; - field_fill_random(&fld); - nxt.attr |= FLD_ATTR_INVISIBLE; - painter_update_field(nxt.id, &nxt); - return; - } else { - field_put_shape(&fld, &fld.shape[0]); - int removedLines = field_rm_lines(&fld); - 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; - } - fld.shape[0].t = nxt.shape[0].t; - field_reset_walking_shape(&fld, 0); - for (unsigned int s = 0; s < nxt.shape_cnt - 1; ++s) { - nxt.shape[s] = nxt.shape[s + 1]; - nxt.shape[s].y = 4 - s * 3; - } - shape_gen_random(&nxt.shape[nxt.shape_cnt - 1]); - checkLevelUp(&game); - } - sfClock_restart(game.putTick); - } + transition_put_shape(); + sfClock_restart(game.putTick); } } -/* - * Keys hold handler - * - */ -void tKeyCtrl() +static void signal_up() +{ + field_rotate_shape(&fld, 0); +} + +static void signal_down() { - /* Up arrow key 'hold' handler */ + fld.shape[0].y--; + if (field_shape_collision(&fld, &fld.shape[0])) { + fld.shape[0].y++; + } else { + sfClock_restart(game.gameTick); + game.scoreCurrent++; + } + sfClock_restart(game.repPushDown); +} + +static void signal_left() +{ + fld.shape[0].x--; + if (field_shape_collision(&fld, &fld.shape[0])) + fld.shape[0].x++; + else + sfClock_restart(game.putTick); + sfClock_restart(game.repKeyLeft); +} + +static void signal_right() +{ + fld.shape[0].x++; + if (field_shape_collision(&fld, &fld.shape[0])) + fld.shape[0].x--; + else + sfClock_restart(game.putTick); + sfClock_restart(game.repKeyRight); +} + +static void game_keys() +{ + /* UP */ if (sfKeyboard_isKeyPressed(sfKeyUp)) { if (!(arrKeys & UP)) { arrKeys = arrKeys | UP; - field_rotate_shape(&fld, 0); + signal_up(); } } else { - if ((arrKeys & UP)) { - arrKeys = arrKeys & ~UP; - } + arrKeys = arrKeys & ~UP; } - /* Down Arrow Key 'hold' handler */ + /* DOWN */ if (sfKeyboard_isKeyPressed(sfKeyDown)) { if (!(arrKeys & DOWN)) { arrKeys = arrKeys | DOWN; - fld.shape[0].y--; - if (field_shape_collision(&fld, &fld.shape[0])) - fld.shape[0].y++; - else { - // Avoid excess move down by gameTick - sfClock_restart(game.putTick); - sfClock_restart(game.gameTick); - game.scoreCurrent++; - } - sfClock_restart(game.repPushDown); + signal_down(); } else { - if (sfClock_getElapsedTime(game.repPushDown).microseconds - >= moveRepeatLatency2) + if (sfClock_getElapsedTime(game.repPushDown).microseconds >= moveRepeatLatency2) arrKeys = arrKeys & ~DOWN; } } else { - if ((arrKeys & DOWN)) { - arrKeys = arrKeys & ~DOWN; - } + arrKeys = arrKeys & ~DOWN; } - /* Left Arrow Key 'hold' handler */ - if (sfKeyboard_isKeyPressed(sfKeyLeft) - && !sfKeyboard_isKeyPressed(sfKeyRight)) { + /* LEFT */ + if (sfKeyboard_isKeyPressed(sfKeyLeft) && !sfKeyboard_isKeyPressed(sfKeyRight)) { if (!(arrKeys & LEFT)) { arrKeys = arrKeys | LEFT; - fld.shape[0].x--; - if (field_shape_collision(&fld, &fld.shape[0])) - fld.shape[0].x++; - else - sfClock_restart(game.putTick); - sfClock_restart(game.repKeyLeft); - } else { - if (!(arrKeys & LEFTHOLD)) { - if (sfClock_getElapsedTime(game.repKeyLeft).microseconds - >= moveRepeatLatency1) { - arrKeys = arrKeys | LEFTHOLD; - arrKeys = arrKeys & ~LEFT; - } - } else { - if (sfClock_getElapsedTime(game.repKeyLeft).microseconds - >= moveRepeatLatency2) - arrKeys = arrKeys & ~LEFT; + signal_left(); + } else if (!(arrKeys & LEFTHOLD)) { + if (sfClock_getElapsedTime(game.repKeyLeft).microseconds >= moveRepeatLatency1) { + arrKeys = arrKeys | LEFTHOLD; + arrKeys = arrKeys & ~LEFT; } + } else { + if (sfClock_getElapsedTime(game.repKeyLeft).microseconds >= moveRepeatLatency2) + arrKeys = arrKeys & ~LEFT; } - } else if (!sfKeyboard_isKeyPressed(sfKeyLeft)) { - if ((arrKeys & LEFT)) { - arrKeys = arrKeys & ~LEFT; - arrKeys = arrKeys & ~LEFTHOLD; - } + } else { + arrKeys = arrKeys & ~LEFT; + arrKeys = arrKeys & ~LEFTHOLD; } - /* Right Arrow Key 'hold' handler */ - if (sfKeyboard_isKeyPressed(sfKeyRight) - && !sfKeyboard_isKeyPressed(sfKeyLeft)) { + /* RIGHT */ + if (sfKeyboard_isKeyPressed(sfKeyRight) && !sfKeyboard_isKeyPressed(sfKeyLeft)) { if (!(arrKeys & RIGHT)) { arrKeys = arrKeys | RIGHT; - fld.shape[0].x++; - if (field_shape_collision(&fld, &fld.shape[0])) - fld.shape[0].x--; - else - sfClock_restart(game.putTick); - sfClock_restart(game.repKeyRight); - } else { - if (!(arrKeys & RIGHTHOLD)) { - if (sfClock_getElapsedTime(game.repKeyRight).microseconds - >= moveRepeatLatency1) { - arrKeys = arrKeys | RIGHTHOLD; - arrKeys = arrKeys & ~RIGHT; - } - } else if (!sfKeyboard_isKeyPressed(sfKeyLeft)) { - if (sfClock_getElapsedTime(game.repKeyRight).microseconds - >= moveRepeatLatency2) // Wait short time - arrKeys = arrKeys & ~RIGHT; + signal_right(); + } else if (!(arrKeys & RIGHTHOLD)) { + if (sfClock_getElapsedTime(game.repKeyRight).microseconds >= moveRepeatLatency1) { + arrKeys = arrKeys | RIGHTHOLD; + arrKeys = arrKeys & ~RIGHT; } + } else { + if (sfClock_getElapsedTime(game.repKeyRight).microseconds >= moveRepeatLatency2) + arrKeys = arrKeys & ~RIGHT; } } else { - if ((arrKeys & RIGHT)) { - arrKeys = arrKeys & ~RIGHT; - arrKeys = arrKeys & ~RIGHTHOLD; - } + arrKeys = arrKeys & ~RIGHT; + arrKeys = arrKeys & ~RIGHTHOLD; } } -void gameover(struct game *game) +static void menuTick() { - game->isStarted = 0; - game->scoreCurrent = 0; - game->level = 0; - game->moveLatency = L00LATENCY; - game->lines = 0; + sfClock_restart(game.mTick); + field_fill_random(&fld); + painter_update_field(fld.id, &fld); } + +void transition_init(void) +{ + list_foreach(texts, show_menu_text); + list_foreach(texts, hide_game_text); + list_foreach(texts, update_menu_text); + list_foreach(texts, update_game_text); +} + +static void transition_game_start() +{ + game.isStarted = 1; + field_clear(&fld); + shape_gen_random(&fld.shape[0]); + field_reset_walking_shape(&fld, 0); + for (unsigned int i = 0; i < nxt.shape_cnt; ++i) + shape_gen_random(&nxt.shape[i]); + nxt.attr &= ~FLD_ATTR_INVISIBLE; + list_foreach(texts, hide_menu_text); + list_foreach(texts, show_game_text); + list_foreach(texts, update_menu_text); + list_foreach(texts, update_game_text); + sfClock_restart(game.gameTick); +} + +static void menu_loop() { + if (sfClock_getElapsedTime(game.mTick).microseconds >= basicLatency) + menuTick(); + if (sfKeyboard_isKeyPressed(sfKeyS) == 1) + transition_game_start(); + painter_draw(); +} + +static void game_loop() { + game_keys(); + if (sfClock_getElapsedTime(game.gameTick).microseconds >= game.moveLatency) + game_tick(); + list_foreach(texts, render_score_value); + list_foreach(texts, render_level_value); + painter_update_field(fld.id, &fld); + painter_update_field(nxt.id, &nxt); + list_foreach(texts, update_game_text); + painter_draw(); +} + +void main_loop() +{ + if (game.isStarted) + game_loop(); + else + menu_loop(); +} + diff --git a/src/field.c b/src/field.c index 37680ae..18b4fed 100644 --- a/src/field.c +++ b/src/field.c @@ -2,6 +2,7 @@ #include <string.h> #include <SFML/Graphics/RectangleShape.h> +#include "vector.h" #include "field.h" #include "tet_conf.h" diff --git a/src/idlist.c b/src/idlist.c index 5b4d99b..b9d551a 100644 --- a/src/idlist.c +++ b/src/idlist.c @@ -53,3 +53,14 @@ void list_foreach(struct idlist *list, void (*job)(void *)) job(list->obj); } } + +void list_destroy(struct idlist *list) +{ + if (list) { + while (list->next) { + list = list->next; + free(list->prev); + } + free(list); + } +} @@ -8,15 +8,17 @@ #include <SFML/Graphics/Font.h> #include "common.h" +#include "idlist.h" +#include "vector.h" #include "text.h" #include "field.h" -#include "draw.h" +#include "painter.h" #include "engine.h" #include "tet_conf.h" -extern struct window w; +sfRenderWindow *window; +struct idlist *texts; -List *texts; sfFont *fontScore; struct field fld, nxt; struct game game = { @@ -27,72 +29,19 @@ struct game game = { .lines = 0 }; -char arrKeys = 0; // Arrow keys states byte container +char arrKeys = 0; -void prepare() { +static void handleWindowEvents() { + sfEvent event; + while (sfRenderWindow_pollEvent(window, &event)) + if (event.type == sfEvtClosed) + sfRenderWindow_close(window); } -void handleWindowEvents() { - while (sfRenderWindow_pollEvent(w.window, &w.event)) - if (w.event.type == sfEvtClosed) - sfRenderWindow_close(w.window); -} - -void drawTextsAtScene(List *texts, char *scene, sfRenderWindow *window) { - List *t = texts; - while (t) { - if (!strcmp(((Text *)t->obj)->scene, scene)) - sfRenderWindow_drawText(window, ((Text *)t->obj)->sfText, NULL); - t = t->next; - } -} - -void gameLoop() { - tTick(); - tKeyCtrl(); - valueAfterTextDisplay(game.scoreCurrent, texts, "score"); - valueAfterTextDisplay(game.level, texts, "level"); - painter_update_field(fld.id, &fld); - painter_update_field(nxt.id, &nxt); - drawTextsAtScene(texts, "game", w.window); - painter_draw(); -} - -void menuTick() +static void register_text(void *obj) { - if (sfClock_getElapsedTime(game.mTick).microseconds >= basicLatency) { - sfClock_restart(game.mTick); - field_fill_random(&fld); - painter_update_field(fld.id, &fld); - } -} - -void menuLoop() { - menuTick(); - drawTextsAtScene(texts, "menu", w.window); - if (sfKeyboard_isKeyPressed(sfKeyS) == 1) { - game.isStarted = 1; - field_clear(&fld); - shape_gen_random(&fld.shape[0]); - field_reset_walking_shape(&fld, 0); - for (unsigned int i = 0; i < nxt.shape_cnt; ++i) - shape_gen_random(&nxt.shape[i]); - nxt.attr &= ~FLD_ATTR_INVISIBLE; - sfClock_restart(game.gameTick); - } - painter_draw(); -} - -void mainLoop() { - while (sfRenderWindow_isOpen(w.window)) { - handleWindowEvents(); - sfRenderWindow_clear(w.window, (sfColor)UIBGCOLOR); - if (game.isStarted) - gameLoop(); - else - menuLoop(); - sfRenderWindow_display(w.window); - } + struct text *text = obj; + text->id = painter_register_text(text); } int main() @@ -104,15 +53,19 @@ int main() game.repPushDown = sfClock_create(); game.repKeyLeft = sfClock_create(); game.repKeyRight = sfClock_create(); + painter_load_font("dat/arial.ttf"); fontScore = sfFont_createFromFile("dat/arial.ttf"); if (!fontScore) { - printf("dat/arial.ttf font load failed"); - exit(-1); + printf("%s font load failed", "dat/arial.ttf"); + exit(EXIT_FAILURE); } - painter_init_window(); - List *tmp = ListOfKeyMapOfString_getFromYaml("dat/texts.yaml"); - texts = ListOfText_getFromListOfKeyMapOfString(tmp); - ListOfKeyMapOfString_free(&tmp); + + sfVideoMode mode = (sfVideoMode){450, 570, 32}; + window = sfRenderWindow_create(mode, windowName_conf, sfResize | sfClose, NULL); + if (!window) + exit(EXIT_FAILURE); + sfRenderWindow_setFramerateLimit(window, 60); + painter_set_window(window); fld.pos = FLD_POS; fld.size = (struct vector2ui){.x = FLD_SIZE_X, .y = FLD_SIZE_Y}; @@ -136,19 +89,34 @@ int main() painter_update_field(fld.id, &fld); painter_update_field(nxt.id, &nxt); - mainLoop(); + texts = load_texts("dat/texts.yaml"); + + list_foreach(texts, register_text); + + transition_init(); + while (sfRenderWindow_isOpen(window)) { + handleWindowEvents(); + main_loop(); + } + + list_foreach(texts, text_destroy); + list_destroy(texts); + painter_destroy_drawables(); field_deinit(&fld); field_deinit(&nxt); - painter_destroy_window(); + if (window) { + sfRenderWindow_destroy(window); + window = 0; + } sfFont_destroy(fontScore); + painter_destroy_font(); sfClock_destroy(game.gameTick); sfClock_destroy(game.putTick); sfClock_destroy(game.mTick); sfClock_destroy(game.repPushDown); sfClock_destroy(game.repKeyLeft); sfClock_destroy(game.repKeyRight); - ListOfText_free(&texts); return EXIT_SUCCESS; } diff --git a/src/draw.c b/src/painter.c index dd888d0..9f6b911 100644 --- a/src/draw.c +++ b/src/painter.c @@ -1,10 +1,15 @@ #include <SFML/Graphics/RenderWindow.h> #include <SFML/Graphics/RectangleShape.h> +#include <SFML/Graphics/Font.h> +#include <SFML/Graphics/Text.h> #include <stdlib.h> +#include <stdio.h> #include "tet_conf.h" +#include "vector.h" +#include "text.h" #include "field.h" -#include "draw.h" +#include "painter.h" #include "idlist.h" @@ -19,48 +24,65 @@ static sfColor shape_color_map[] = { TCOLOR, }; +enum t { + TYPE_U, + TYPE_FIELD, + TYPE_TEXT +}; + +struct drawable { + enum t t; +}; struct field_drawable { + struct drawable; + sfRectangleShape ***p; - struct vector2ui size; - unsigned int attr; + struct vector2ui size; + unsigned int attr; }; -/* - * TODO: Must be static in future - * - * */ -struct window w; +struct text_drawable { + struct drawable; + + sfText *text; + unsigned long attr; +}; -static struct idlist *fields_list = NULL; +static sfRenderWindow *window; +static sfFont *font; -void painter_init_window() +static struct idlist *drawables = NULL; + +void painter_set_window(sfRenderWindow *w) { - w = (struct window){.mode = {450, 570, 32}}; - w.window = sfRenderWindow_create(w.mode, windowName_conf, - sfResize | sfClose, NULL); - if (!w.window) - exit(EXIT_FAILURE); - sfRenderWindow_setFramerateLimit(w.window, 60); + window = w; } -void painter_destroy_window() +void painter_load_font(char *filename) { - if (w.window) { - sfRenderWindow_destroy(w.window); - w.window = 0; + font = sfFont_createFromFile(filename); + if (!font) { + printf("%s font load failed", filename); + exit(EXIT_FAILURE); } } +void painter_destroy_font() +{ + sfFont_destroy(font); +} + unsigned long painter_register_field(struct field *fld) { struct idlist *last; - if (!fields_list) - last = fields_list = list_new(); + if (!drawables) + last = drawables = list_new(); else - last = list_append(fields_list); + last = list_append(drawables); struct field_drawable *f = calloc(1, sizeof(struct field_drawable)); + f->t = TYPE_FIELD; f->size = fld->size; f->p = calloc(f->size.y, sizeof(sfRectangleShape **)); for (unsigned int j = 0; j < f->size.y; j++) { @@ -84,7 +106,7 @@ unsigned long painter_register_field(struct field *fld) void painter_update_field(unsigned long id, struct field *fld) { - struct idlist *node = list_get(fields_list, id); + struct idlist *node = list_get(drawables, id); if (!node) return; struct field_drawable *f = node->obj; @@ -120,23 +142,18 @@ void painter_update_field(unsigned long id, struct field *fld) } } -static void draw_field(void *field) +static void draw_field_drawable(struct drawable *d) { - struct field_drawable *f = field; + struct field_drawable *f = (void *)d; if (!(f->attr & FLD_ATTR_INVISIBLE)) for (unsigned int j = 0; j < f->size.y; j++) for (unsigned int i = 0; i < f->size.x; i++) - sfRenderWindow_drawRectangleShape(w.window, f->p[j][i], NULL); -} - -static void draw_fields() -{ - list_foreach(fields_list, draw_field); + sfRenderWindow_drawRectangleShape(window, f->p[j][i], NULL); } -static void destroy_field(void *field) +static void destroy_field_drawable(struct drawable *d) { - struct field_drawable *f = field; + struct field_drawable *f = (void *)d; for (unsigned int j = 0; j < f->size.y; j++) { for (unsigned int i = 0; i < f->size.x; i++) sfRectangleShape_destroy(f->p[j][i]); @@ -146,30 +163,112 @@ static void destroy_field(void *field) free(f); } -void painter_destroy_field(unsigned long id) +unsigned long painter_register_text(struct text *txt) { - struct idlist *node = list_get(fields_list, id); - destroy_field(node->obj); - list_rm_node(node); + struct idlist *last; + if (!drawables) + last = drawables = list_new(); + else + last = list_append(drawables); + + struct text_drawable *t = calloc(1, sizeof(struct text_drawable)); + t->t = TYPE_TEXT; + t->text = sfText_create(); + sfText_setFont(t->text, font); + sfText_setCharacterSize(t->text, txt->size); + sfVector2f pos = (sfVector2f){.x = txt->pos.x, .y = txt->pos.y}; + sfText_setPosition(t->text, pos); + sfText_setString(t->text, txt->text); + + last->obj = t; + return last->id; } -void painter_destroy_fields() +void painter_update_text(unsigned long id, struct text *txt) { - list_foreach(fields_list, destroy_field); + struct idlist *node = list_get(drawables, id); + if (!node) + return; + struct text_drawable *t = node->obj; + t->attr = txt->attr; + sfText_setCharacterSize(t->text, txt->size); + sfVector2f pos = (sfVector2f){.x = txt->pos.x, .y = txt->pos.y}; + sfText_setPosition(t->text, pos); + sfText_setString(t->text, txt->text); +} + +static void draw_text_drawable(struct drawable *d) +{ + struct text_drawable *t = (struct text_drawable *)d; + if (!(t->attr & TXT_ATTR_INVISIBLE)) + sfRenderWindow_drawText(window, t->text, NULL); +} + +static void destroy_text_drawable(struct drawable *d) +{ + struct text_drawable *t = (struct text_drawable *)d; + sfText_destroy(t->text); + free(t); +} + +static void draw_drawable(void *obj) +{ + struct drawable *d = obj; + switch (d->t) { + case TYPE_FIELD: + draw_field_drawable(d); + break; + case TYPE_TEXT: + draw_text_drawable(d); + break; + case TYPE_U: + fprintf(stderr, "ERROR: Unknown type of drawable\n"); + exit(EXIT_FAILURE); + break; + } } void painter_draw() { - draw_fields(); + sfRenderWindow_clear(window, (sfColor)UIBGCOLOR); + list_foreach(drawables, draw_drawable); + sfRenderWindow_display(window); +} + +static void destroy_drawable(void *obj) +{ + struct drawable *d = obj; + switch (d->t) { + case TYPE_FIELD: + destroy_field_drawable(d); + break; + case TYPE_TEXT: + destroy_text_drawable(d); + break; + case TYPE_U: + fprintf(stderr, "ERROR: Unknown type of drawable\n"); + exit(EXIT_FAILURE); + break; + } +} + +void painter_destroy_drawable(unsigned long id) +{ + struct idlist *node = list_get(drawables, id); + destroy_drawable(node->obj); + list_rm_node(node); } void painter_destroy_drawables() { - painter_destroy_fields(); + list_foreach(drawables, destroy_drawable); + list_destroy(drawables); + drawables = 0; } void painter_destroy_all() { painter_destroy_drawables(); - painter_destroy_window(); + painter_destroy_font(); + window = 0; } @@ -7,255 +7,102 @@ #include <yaml.h> #include "common.h" +#include "idlist.h" +#include "vector.h" #include "text.h" -extern sfFont *fontScore; - -FILE *openFile(char *filename) +static FILE *openFile(char *filename) { FILE *file; if (!(file = fopen(filename, "rb"))){ - printf("ERROR\n"); + printf("ERROR: fild \"%s\"cannot be opened\n", filename); exit(EXIT_FAILURE); } return file; } -void checkArgs(int argc, char **argv) -{ - if (argc < 2) { - printf("Usage: %s file1.yaml ...\n", argv[0]); - exit(EXIT_FAILURE); - } -} - -KeyMap *KeyMap_getLast(KeyMap **keyMap) -{ - KeyMap *keyMapLocal = *keyMap; - if (keyMapLocal) - while (keyMapLocal->next) - keyMapLocal = keyMapLocal->next; - return keyMapLocal; -} - -KeyMap *KeyMap_new(KeyMap **keyMap) -{ - KeyMap *keyMapLocal = KeyMap_getLast(keyMap); - if (keyMapLocal) { - keyMapLocal->next = malloc(sizeof(KeyMap)); - ((KeyMap *)keyMapLocal->next)->prev = keyMapLocal; - keyMapLocal = keyMapLocal->next; - } else { - *keyMap = malloc(sizeof(KeyMap)); - keyMapLocal = *keyMap; - keyMapLocal->prev = 0; - } - keyMapLocal->pair = malloc(sizeof(Pair)); - keyMapLocal->next = 0; - return keyMapLocal; -} - -KeyMap *KeyMap_get(KeyMap **keyMap, const void *key) -{ - KeyMap *keyMapLocal = *keyMap; - while (keyMapLocal) - if (keyMapLocal->pair) - if (keyMapLocal->pair->k) - if (!strcmp(keyMapLocal->pair->k, key)) - return keyMapLocal; - else - keyMapLocal = keyMapLocal->next; - else - keyMapLocal = keyMapLocal->next; - else - keyMapLocal = keyMapLocal->next; - return 0; -} - -KeyMap *KeyMap_put(KeyMap **keyMap, const void *key, const void *value) +struct idlist *load_texts(char *filename) { - KeyMap *keyMapLocal = KeyMap_get(keyMap, key); - if (!keyMapLocal) { - keyMapLocal = KeyMap_new(keyMap); - keyMapLocal->pair->k = malloc(strlen(key)+1); - strcpy(keyMapLocal->pair->k, key); - } - keyMapLocal->pair->v = malloc(strlen(value)+1); - strcpy(keyMapLocal->pair->v, value); - return keyMapLocal; -} - -List *List_getLast(List **list) -{ - List *listLocal = *list; - if (listLocal) - while (listLocal->next) - listLocal = listLocal->next; - return listLocal; -} - -List *List_new(List **list) -{ - List *listLocal = List_getLast(list); - if (listLocal) { - (listLocal)->next = malloc(sizeof(List)); - ((List *)listLocal->next)->prev = listLocal; - listLocal = listLocal->next; - } else { - *list = malloc(sizeof(List)); - (*list)->prev = 0; - listLocal = *list; - } - listLocal->obj = 0; - listLocal->next = 0; - return listLocal; -} - -List *ListOfKeyMapOfString_getFromYaml(char *filename) -{ - List *list = 0; FILE *file = openFile(filename); yaml_parser_t parser; yaml_event_t event; yaml_parser_initialize(&parser); yaml_parser_set_input_file(&parser, file); + + struct idlist *texts = NULL; + struct idlist *texts_node = texts; do { if (!yaml_parser_parse(&parser, &event)) { - printf("Parser error %d\n", parser.error); + fprintf(stderr, "Parser error %d\n", parser.error); exit(EXIT_FAILURE); } - switch(event.type) + + switch (event.type) { - case YAML_MAPPING_START_EVENT: - List_new(&list); - break; - case YAML_SCALAR_EVENT: - ;yaml_event_t ev; - yaml_parser_parse(&parser, &ev); - while (ev.type != YAML_SCALAR_EVENT) { - yaml_event_delete(&ev); - if (!yaml_parser_parse(&parser, &ev)) { - printf("Parser error %d\n", parser.error); - exit(EXIT_FAILURE); - } - } - KeyMap **keyMap = (KeyMap **)&((List *)List_getLast(&list))->obj; - KeyMap_put(keyMap, event.data.scalar.value, ev.data.scalar.value); + case YAML_MAPPING_START_EVENT: + if (!texts) { + texts = list_new(); + texts_node = texts; + } else + texts_node = list_append(texts); + texts_node->obj = calloc(1, sizeof(struct text)); + break; + case YAML_SCALAR_EVENT: + ;yaml_event_t ev; + yaml_parser_parse(&parser, &ev); + while (ev.type != YAML_SCALAR_EVENT) { yaml_event_delete(&ev); - break; - default: break; + if (!yaml_parser_parse(&parser, &ev)) { + fprintf(stderr, "Parser error %d\n", parser.error); + exit(EXIT_FAILURE); + } + } + struct text *text = texts_node->obj; + if (!strcmp((char *)event.data.scalar.value, "type")) { + text->type = malloc(sizeof(char) * (strlen((char *)ev.data.scalar.value) + 1)); + strcpy(text->type, (char *)ev.data.scalar.value); + } else if (!strcmp((char *)event.data.scalar.value, "scene")) { + text->scene = malloc(sizeof(char) * (strlen((char *)ev.data.scalar.value) + 1)); + strcpy(text->scene, (char *)ev.data.scalar.value); + } else if (!strcmp((char *)event.data.scalar.value, "text")) { + text->text = malloc(sizeof(char) * (strlen((char *)ev.data.scalar.value) + 1)); + strcpy(text->text, (char *)ev.data.scalar.value); + } else if (!strcmp((char *)event.data.scalar.value, "font")) { + text->font = malloc(sizeof(char) * (strlen((char *)ev.data.scalar.value) + 1)); + strcpy(text->font, (char *)ev.data.scalar.value); + } else if (!strcmp((char *)event.data.scalar.value, "size")) { + text->size = atoi((char *)ev.data.scalar.value); + } else if (!strcmp((char *)event.data.scalar.value, "x")) { + text->pos.x = atoi((char *)ev.data.scalar.value); + } else if (!strcmp((char *)event.data.scalar.value, "y")) { + text->pos.y = atoi((char *)ev.data.scalar.value); + } + yaml_event_delete(&ev); + break; + default: + break; } - if(event.type != YAML_STREAM_END_EVENT) + + if (event.type != YAML_STREAM_END_EVENT) yaml_event_delete(&event); - } while(event.type != YAML_STREAM_END_EVENT); + } while (event.type != YAML_STREAM_END_EVENT); + yaml_event_delete(&event); yaml_parser_delete(&parser); fclose(file); - return list; -} - -void KeyMapOfString_free(KeyMap *keyMap) -{ - KeyMap *keyMapLocal = KeyMap_getLast(&keyMap); - while (keyMapLocal) { - free(keyMapLocal->pair->k); - free(keyMapLocal->pair->v); - free(keyMapLocal->pair); - KeyMap *prev = keyMapLocal->prev; - free(keyMapLocal); - keyMapLocal = prev; - } -} - -void ListOfKeyMapOfString_free(List **list) -{ - List *listLocal = List_getLast(list); - while (listLocal) { - KeyMapOfString_free(listLocal->obj); - List *prev = listLocal->prev; - free(listLocal); - listLocal = prev; - } - *list = 0; -} - -static int _loadText_getInt(void *obj, char *key) -{ - int v = 0; - KeyMap *keyMap = KeyMap_get((KeyMap **)&obj, key); - if (keyMap) - if (keyMap->pair) - if (keyMap->pair->v) - v = atoi(keyMap->pair->v); - return v; + return texts; } -static char *_loadText_getString(void *obj, char *key) +void text_destroy(void *obj) { - char *v = 0; - KeyMap *keyMap = KeyMap_get((KeyMap **)&obj, key); - if (keyMap) - if (keyMap->pair) - if (keyMap->pair->v) { - v = malloc(strlen(keyMap->pair->v)+1); - strcpy(v, keyMap->pair->v); - } - return v; -} - -static void _loadText_initSfText(Text *objo, void *obji) -{ - sfVector2f pos = { - .x = _loadText_getInt(obji, "x"), - .y = _loadText_getInt(obji, "y") - }; - int size = _loadText_getInt(obji, "size"); - char *text = _loadText_getString(obji, "text"); - objo->sfText = sfText_create(); - sfText_setFont(objo->sfText, fontScore); - sfText_setCharacterSize(objo->sfText, size); - sfText_setPosition(objo->sfText, pos); - sfText_setString(objo->sfText, text); + struct text *text = obj; + if (text->type) + free(text->type); + if (text->scene) + free(text->scene); + if (text->text) + free(text->text); + if (text->font) + free(text->font); free(text); } - -List *ListOfText_getFromListOfKeyMapOfString(List *list) -{ - List *li = list; - List *lo = 0; - List *l = 0; - while (li) { - List_new(&lo); - l = List_getLast(&lo); - l->obj = malloc(sizeof(Text)); - ((Text *)l->obj)->type = _loadText_getString(li->obj, "type"); - ((Text *)l->obj)->font = _loadText_getString(li->obj, "font"); - ((Text *)l->obj)->scene = _loadText_getString(li->obj, "scene"); - ((Text *)l->obj)->text = _loadText_getString(li->obj, "text"); - _loadText_initSfText(l->obj, li->obj); - li = li->next; - } - return lo; -} - -void Text_free(Text *obj) -{ - free(obj->type); - free(obj->scene); - free(obj->text); - free(obj->font); - sfText_destroy(obj->sfText); - free(obj); -} - -void ListOfText_free(List **list) -{ - List *listLocal = List_getLast(list); - while (listLocal) { - Text_free(listLocal->obj); - List *prev = listLocal->prev; - free(listLocal); - listLocal = prev; - } - *list = 0; -} |