summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMenase Teshale <osome3717@gmail.com>2026-08-24 10:53:14 +0300
committerMenase Teshale <osome3717@gmail.com>2026-08-24 10:53:14 +0300
commit790249cc59bdf646ee38a081ebe392c33ae5b732 (patch)
tree45ca1026b88e4d0dc7709d041cb15455ccea508d /src
parent15b194df64db5850757d195344e682bb8ec4c138 (diff)
Started working on fonts
Diffstat (limited to 'src')
-rw-r--r--src/app.h4
-rw-r--r--src/font.c178
-rw-r--r--src/font.h26
-rw-r--r--src/game.c68
-rw-r--r--src/main.c5
5 files changed, 268 insertions, 13 deletions
diff --git a/src/app.h b/src/app.h
index 75ff2e6..c75ece6 100644
--- a/src/app.h
+++ b/src/app.h
@@ -12,9 +12,9 @@ typedef enum {
void init_app(SDL_Renderer* renderer, MIX_Mixer* mixer);
void free_app();
-void init_game(SDL_Renderer* renderer, MIX_Mixer* mixer);
+void init_timed_game(SDL_Renderer* renderer, MIX_Mixer* mixer, float time_remaining);
void free_game();
-void update_game(float dt, MIX_Mixer* mixer);
+void update_game(float dt);
void draw_game(SDL_Renderer* renderer);
void game_event(SDL_Event* e);
diff --git a/src/font.c b/src/font.c
new file mode 100644
index 0000000..999c3da
--- /dev/null
+++ b/src/font.c
@@ -0,0 +1,178 @@
+#include "font.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#define FILE_NAME_SIZE 300
+
+void free_sprite_font(sprite_font* font) {
+ free(font->characters);
+ SDL_DestroyTexture(font->spritesheet);
+
+ memset(font, 0, sizeof(sprite_font));
+}
+
+int get_string_parameter(const char* line, const char* parameter, const char** start) {
+ *start = strstr(line, parameter);
+ if ((*start) == NULL)
+ return -1;
+
+ *start += strlen(parameter);
+ if ((*start)[0] != '\"') {
+ return -1;
+ }
+
+ int length = 0;
+ while ((*start)[length+1] != '\0' && (*start)[length+1] != '\"') length++;
+
+ (*start)++;
+ return length;
+}
+
+char parse_character_tag(const char* character_tag) {
+ if (strncmp(character_tag, "space", 5) == 0)
+ return ' ';
+
+ return character_tag[0];
+}
+
+bool get_int_parameter(const char* line, const char* parameter, int* value) {
+ const char* start = strstr(line, parameter);
+ if (start == NULL) {
+ return false;
+ }
+ start += strlen(parameter);
+
+ int c = 0;
+ bool negative = false;
+
+ if (start[0] == '-') {
+ negative = true;
+ start++;
+ }
+
+ for(int i = 0; start[i] >= '0' && start[i] <= '9'; i++) {
+ c *= 10; c += start[i] - '0';
+ }
+
+ *value = negative ? -c : c;
+ return true;
+}
+
+bool load_sprite_font(const char* filename, sprite_font* font) {
+ if (font->characters || font->spritesheet) {
+ SDL_Log("Trying to reallocate font causing memory leak, exitting!");
+ exit(EXIT_FAILURE);
+ }
+
+ FILE* f = fopen(filename, "r");
+ if (f == NULL) {
+ SDL_Log("Failed to open sprite font file %s, error: %s, exitting!",
+ filename,
+ strerror(errno)
+ );
+ exit(EXIT_FAILURE);
+ }
+
+ char line[PARSER_LINE_SIZE];
+ if (fgets(line, sizeof(line), f) == NULL ||
+ strncmp(line, "info", 4) != 0) {
+ SDL_Log("File %s is not a valid font file, exitting!",
+ filename);
+ fclose(f);
+ exit(EXIT_FAILURE);
+ }
+
+ char font_name[FONT_NAME_SIZE];
+ const char* font_name_start;
+ int font_name_length =
+ SDL_min(get_string_parameter(line, "face=", &font_name_start),
+ FONT_NAME_SIZE-1
+ );
+
+ strncpy(font_name, font_name_start, font_name_length);
+ font_name[font_name_length] = '\0';
+
+ int char_size = 0, char_count = 0;
+ font_char* characters_unarranged = NULL;
+
+ while (fgets(line, PARSER_LINE_SIZE, f) != NULL) {
+
+ if (strncmp(line, "chars", 5) == 0) {
+ int total_char_count;
+
+ if(!get_int_parameter(line, "count=", &total_char_count))
+ continue;
+
+ char_size = total_char_count;
+ characters_unarranged =
+ realloc(characters_unarranged, char_size * sizeof(font_char));
+
+ if (characters_unarranged == NULL) {
+ SDL_Log("Failed to allocate space while loading font %s, error %s, exitting!",
+ filename,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ else if (strncmp(line, "char", 4) == 0) {
+ font_char new_font_char;
+
+ int val;
+
+ if (!get_int_parameter(line, "x=", &val))
+ continue;
+ new_font_char.x = val;
+
+ if (!get_int_parameter(line, "y=", &val))
+ continue;
+ new_font_char.y = val;
+
+ if (!get_int_parameter(line, "width=", &val))
+ continue;
+ new_font_char.width = val;
+
+ if (!get_int_parameter(line, "height=", &val))
+ continue;
+ new_font_char.height = val;
+
+ if (!get_int_parameter(line, "xoffset=", &val))
+ continue;
+ new_font_char.x_offset = val;
+
+ if (!get_int_parameter(line, "yoffset=", &val))
+ continue;
+ new_font_char.y_offset = val;
+
+ if (!get_int_parameter(line, "xadvance=", &val))
+ continue;
+ new_font_char.x_advance = val;
+
+ const char* character_tag;
+ if (get_string_parameter(line, "letter=", &character_tag) <= 0)
+ continue;
+ new_font_char.character = parse_character_tag(character_tag);
+
+ if (char_count >= char_size) {
+ char_size = char_count+1;
+ characters_unarranged =
+ realloc(characters_unarranged, char_size * sizeof(font_char));
+ }
+
+ if (characters_unarranged == NULL) {
+ SDL_Log("Failed to allocate space while loading font %s, error %s, exitting!",
+ filename,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ characters_unarranged[char_count] = new_font_char;
+ char_count++;
+ }
+ }
+
+ fclose(f);
+ return true;
+}
diff --git a/src/font.h b/src/font.h
new file mode 100644
index 0000000..a26c332
--- /dev/null
+++ b/src/font.h
@@ -0,0 +1,26 @@
+#ifndef FONT_H_
+#define FONT_H_
+
+#include <SDL3/SDL.h>
+#define FONT_NAME_SIZE 40
+#define PARSER_LINE_SIZE 4096
+
+typedef struct {
+ float x, y;
+ float width, height;
+ float x_offset, y_offset;
+ float x_advance;
+ char character;
+} font_char;
+
+typedef struct {
+ char name[FONT_NAME_SIZE];
+ SDL_Texture* spritesheet;
+ char smallest_character, largest_character;
+ font_char* characters;
+} sprite_font;
+
+bool load_sprite_font(const char* filename, sprite_font* font);
+void free_sprite_font(sprite_font* font);
+
+#endif // FONT_H_
diff --git a/src/game.c b/src/game.c
index 61323a3..8e51dca 100644
--- a/src/game.c
+++ b/src/game.c
@@ -33,6 +33,7 @@
#define BOARD_PADDING 4
#define BACKGROUND_SCROLL_SPEED 40
+#define MAX_CLEARED_TILES_STORED 50
typedef enum {
linear_move_state,
@@ -79,10 +80,20 @@ typedef enum {
swap_animation_state
} game_scene_state;
+typedef enum {
+ timed_mode,
+ combo_mode
+} game_mode;
+
+typedef struct {
+ float time_remaining;
+} timed_mode_data;
+
typedef struct {
bool inited;
SDL_Texture* spritesheet;
game_scene_state state;
+ game_mode mode;
piece pieces[MAX_PIECES];
int num_pieces;
@@ -104,6 +115,8 @@ typedef struct {
MIX_Track* background_music_track;
MIX_Track* effect_track;
MIX_Audio* pop_audio;
+
+ timed_mode_data timed_mode_data;
} s_game;
extern SDL_Window* window;
@@ -265,6 +278,15 @@ void init_game(SDL_Renderer* renderer, MIX_Mixer* mixer) {
fill_board();
}
+void init_timed_game(SDL_Renderer* renderer, MIX_Mixer* mixer, float time_remaining) {
+ init_game(renderer, mixer);
+
+ game.mode = timed_mode;
+ game.timed_mode_data = (timed_mode_data) {
+ .time_remaining = time_remaining
+ };
+}
+
void free_game() {
SDL_DestroyTexture(game.spritesheet);
SDL_DestroyTexture(game.background_texture);
@@ -351,6 +373,9 @@ int mouse_on_piece() {
}
void update_intro_state() {
+ if (game.state != intro_state)
+ return;
+
for (int i = 0; i < game.num_pieces; i++) {
if (game.pieces[i].state != static_state && game.pieces[i].state != fall_state) {
return;
@@ -463,6 +488,9 @@ static inline void play_sound_effect(MIX_Audio* audio) {
}
void update_piece_swap_animation_state() {
+ if (game.state != swap_animation_state)
+ return;
+
for (int i = 0; i < game.num_pieces; i++) {
if (game.pieces[i].state != static_state && game.pieces[i].state != fall_state)
return;
@@ -521,27 +549,32 @@ void scroll_background(float dt) {
}
}
-void update_game(float dt, MIX_Mixer* mixer) {
+
+void delete_out_of_screen_pieces() {
int window_width, window_height;
SDL_GetWindowSizeInPixels(window, &window_width, &window_height);
for (int i = 0; i < game.num_pieces; i++) {
- update_piece(&game.pieces[i], dt);
-
if (game.pieces[i].position.y > window_height + DELETE_PIECE_OFFSET) {
delete_piece(game.pieces[i].piece_id);
}
}
+}
- handle_piece_rotation(dt);
+void update_timed_mode(float dt);
+void update_game(float dt) {
+ for (int i = 0; i < game.num_pieces; i++) {
+ update_piece(&game.pieces[i], dt);
+ }
+ delete_out_of_screen_pieces();
+ handle_piece_rotation(dt);
scroll_background(dt);
- if (game.state == intro_state) {
- update_intro_state();
- } else if (game.state == swap_animation_state) {
- update_piece_swap_animation_state();
- }
+ update_intro_state();
+ update_piece_swap_animation_state();
+
+ update_timed_mode(dt);
}
void draw_piece(SDL_Renderer* renderer, const piece* piece) {
@@ -659,6 +692,8 @@ void piece_held_event(SDL_Event* e) {
}
}
+ //If pieces are more that one tile apart or
+ //they are of the same color do nothing
if (SDL_abs(selected_x-swap_x) + SDL_abs(selected_y-swap_y) != 1 ||
retreive_piece(selected_piece_id)->piece_color == retreive_piece(swap_piece_id)->piece_color) {
game.state = neutral_state;
@@ -683,3 +718,18 @@ void game_event(SDL_Event* e) {
piece_held_event(e);
}
}
+
+
+//**********************************************
+//*****************TIMED MODE*******************
+//*********************************************/
+void update_timed_mode(float dt) {
+ timed_mode_data* timed_mode_data = &game.timed_mode_data;
+
+ timed_mode_data->time_remaining =
+ SDL_max(timed_mode_data->time_remaining - dt, 0);
+
+ if (timed_mode_data->time_remaining <= 0) {
+ SDL_Log("Time over");
+ }
+}
diff --git a/src/main.c b/src/main.c
index b126e92..e26e971 100644
--- a/src/main.c
+++ b/src/main.c
@@ -7,6 +7,7 @@
#include <SDL3_mixer/SDL_mixer.h>
#include "app.h"
+#include "font.h"
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
@@ -66,7 +67,7 @@ SDL_AppResult SDL_AppIterate(void* userdata) {
switch (app_state) {
case game_state:
- update_game(SDL_min(dt, MAX_DELTATIME), mixer);
+ update_game(SDL_min(dt, MAX_DELTATIME));
draw_game(renderer);
break;
@@ -88,7 +89,7 @@ void SDL_AppQuit(void* userdata, SDL_AppResult result) {
}
void init_app(SDL_Renderer* renderer, MIX_Mixer* mixer) {
- init_game(renderer, mixer);
+ init_timed_game(renderer, mixer, 5);
app_state = game_state;
}