diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..41565cf --- /dev/null +++ b/.clang-format @@ -0,0 +1,10 @@ +# https://clang.llvm.org/docs/ClangFormat.html +BasedOnStyle: LLVM +IndentWidth: 8 +UseTab: AlignWithSpaces +BreakBeforeBraces: Linux +AllowShortIfStatementsOnASingleLine: false +IndentCaseLabels: false +ColumnLimit: 80 +AlignConsecutiveMacros: true +AlwaysBreakAfterReturnType: TopLevelDefinitions diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc88c68 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Build files +/build-fx +/build-cg +/*.g1a +/*.g3a + +# Python bytecode + __pycache__/ + +# Common IDE files +*.sublime-project +*.sublime-workspace +.vscode +*.swp + +# Krita backup files +*.png~ + +# cmake_sources.sh +CMakeLists.txt~ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..253c620 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,49 @@ +# Configure with [fxsdk build-fx] or [fxsdk build-cg], which provide the +# toolchain file and module path of the fxSDK + +cmake_minimum_required(VERSION 3.18) +project(ProtoDig C) + +include(GenerateG3A) +include(Fxconv) +find_package(Gint 2.5 REQUIRED) + +include_directories(include) + +set(SOURCES + src/main.c + src/player/update.c + src/player/init.c + src/player/draw.c + src/game/init.c + src/grid/get_set.c + src/grid/alloc.c + src/grid/random_walker.c + src/grid/draw.c +) + +set(ASSETS +) + +set(FLAGS + -std=c99 + -Wall -Wextra -pedantic + -Wshadow + -Wswitch-default -Wswitch-enum + -Wunreachable-code + -Wstrict-prototypes -Wmissing-prototypes + -Werror-implicit-function-declaration + -Os +) + +fxconv_declare_assets(${ASSETS} WITH_METADATA) + +add_executable(Main ${SOURCES} ${ASSETS}) +target_compile_options(Main PRIVATE ${FLAGS}) +target_link_libraries(Main Gint::Gint) + +generate_g3a( + TARGET Main + OUTPUT "${PROJECT_NAME}.g3a" + NAME "${PROJECT_NAME}" + ICONS assets/icon-uns.png assets/icon-sel.png) diff --git a/assets/icon-sel.png b/assets/icon-sel.png new file mode 100644 index 0000000..7137b50 Binary files /dev/null and b/assets/icon-sel.png differ diff --git a/assets/icon-uns.png b/assets/icon-uns.png new file mode 100644 index 0000000..3c99f62 Binary files /dev/null and b/assets/icon-uns.png differ diff --git a/include/game.h b/include/game.h new file mode 100644 index 0000000..98fe63a --- /dev/null +++ b/include/game.h @@ -0,0 +1,11 @@ +#pragma once +#include "grid.h" +#include "player.h" + +struct Game { + struct Grid floor; + struct Player player; +}; + +struct Game game_init(void); +void game_deinit(struct Game); diff --git a/include/grid.h b/include/grid.h new file mode 100644 index 0000000..3269530 --- /dev/null +++ b/include/grid.h @@ -0,0 +1,17 @@ +#pragma once +#include "tiles.h" +#include +#include + +struct Grid { + int width; + int height; + uint8_t *data; +}; + +struct Grid grid_new(int width, int height); +void grid_free(struct Grid); +void grid_set(struct Grid *restrict, int x, int y, enum Tile); +enum Tile grid_get(struct Grid, int x, int y); +void grid_draw(struct Grid, int scr_x, int scr_y); +void grid_random_walker(struct Grid *restrict grid); diff --git a/include/player.h b/include/player.h new file mode 100644 index 0000000..ff7b7b0 --- /dev/null +++ b/include/player.h @@ -0,0 +1,16 @@ +#pragma once +#include "grid.h" + +struct Player { + int x; + int y; + int cash; + int left_held; + int right_held; + int up_held; + int down_held; +}; + +struct Player player_init(int x, int y); +void player_draw(struct Player, int scr_x, int scr_y); +void player_update(struct Player *restrict, struct Grid *restrict); diff --git a/include/tiles.h b/include/tiles.h new file mode 100644 index 0000000..0b0bc17 --- /dev/null +++ b/include/tiles.h @@ -0,0 +1,13 @@ +#pragma once + +#define TILE_WIDTH 16 +#define TILE_HEIGHT 16 + +enum Tile { + TILE_VOID, + TILE_OBSTACLE_1, + TILE_OBSTACLE_2, + TILE_OBSTACLE_3, + TILE_SOLID, +}; +#define TILE_OOB TILE_SOLID diff --git a/src/game/init.c b/src/game/init.c new file mode 100644 index 0000000..09e19d7 --- /dev/null +++ b/src/game/init.c @@ -0,0 +1,18 @@ +#include "game.h" +#include "grid.h" + +struct Game +game_init(void) +{ + struct Game game; + game.floor = grid_new(1024, 14); + grid_random_walker(&game.floor); + game.player = player_init(0, game.floor.height / 2); + return game; +} + +void +game_deinit(struct Game game) +{ + grid_free(game.floor); +} diff --git a/src/grid/alloc.c b/src/grid/alloc.c new file mode 100644 index 0000000..b49265a --- /dev/null +++ b/src/grid/alloc.c @@ -0,0 +1,17 @@ +#include "grid.h" +#include +#include + +struct Grid +grid_new(int width, int height) +{ + struct Grid grid = {width, height, NULL}; + grid.data = calloc(width * height, sizeof(uint8_t)); + return grid; +} + +void +grid_free(struct Grid grid) +{ + free(grid.data); +} diff --git a/src/grid/draw.c b/src/grid/draw.c new file mode 100644 index 0000000..506cd67 --- /dev/null +++ b/src/grid/draw.c @@ -0,0 +1,74 @@ +#include "grid.h" +#include "tiles.h" +#include + +static void tile_draw(enum Tile, int x, int y); + +void +grid_draw(struct Grid grid, int scr_x, int scr_y) +{ + int x; + int y; + int ix; + int iy; + int ry; + int riy; + + x = scr_x; + y = scr_y; + ix = 0; + iy = 0; + + while (x <= -TILE_WIDTH) { + x += TILE_WIDTH; + ix += 1; + } + + while (y <= -TILE_HEIGHT) { + y += TILE_HEIGHT; + iy += 1; + } + + ry = y; + riy = iy; + while (x < DWIDTH) { + while (y < DHEIGHT) { + tile_draw(grid_get(grid, ix, iy), x, y); + y += TILE_HEIGHT; + iy += 1; + } + y = ry; + iy = riy; + x += TILE_WIDTH; + ix += 1; + } +} + +static void +tile_draw(enum Tile tile, int x, int y) +{ + color_t color; + + switch (tile) { + case TILE_VOID: + color = C_BLACK; + break; + case TILE_OBSTACLE_1: + color = C_DARK; + break; + case TILE_OBSTACLE_2: + color = C_LIGHT; + break; + case TILE_OBSTACLE_3: + color = C_WHITE; + break; + case TILE_SOLID: + color = C_BLUE; + break; + default: + color = C_RGB(31, 0, 31); + break; + } + + drect(x, y, x + TILE_WIDTH - 1, y + TILE_HEIGHT - 1, color); +} diff --git a/src/grid/get_set.c b/src/grid/get_set.c new file mode 100644 index 0000000..33d2af8 --- /dev/null +++ b/src/grid/get_set.c @@ -0,0 +1,20 @@ +#include "grid.h" +#include "tiles.h" + +enum Tile +grid_get(struct Grid grid, int x, int y) +{ + if (x >= grid.width || y >= grid.height || x < 0 || y < 0) + return TILE_OOB; + + return grid.data[x + y * grid.width]; +} + +void +grid_set(struct Grid *restrict grid, int x, int y, enum Tile new) +{ + if (x >= grid->width || y >= grid->height || x < 0 || y < 0) + return; + + grid->data[x + y * grid->width] = new; +} diff --git a/src/grid/random_walker.c b/src/grid/random_walker.c new file mode 100644 index 0000000..b4b8d38 --- /dev/null +++ b/src/grid/random_walker.c @@ -0,0 +1,57 @@ +#include "grid.h" +#include "tiles.h" +#include + +void +grid_random_walker(struct Grid *restrict grid) +{ + int x; + int y; + int i; + int roll; + + /* fill with walls */ + i = grid->width * grid->height; + while (i-- > 0) + grid->data[i] = TILE_SOLID; + + /* dig our way to the right */ + x = 0; + y = grid->height / 2; + while (x < grid->width) { + roll = rand() % 8; + grid_set(grid, x, y, roll ? TILE_VOID : TILE_OBSTACLE_3); + roll = rand() % 9; + switch (roll) { + case 0: + case 1: + case 2: + /* right */ + x += 1; + break; + case 3: + case 4: + /* up */ + y -= 1; + if (y < 0) + y = grid->height - 1; + break; + case 5: + case 6: + /* down */ + y += 1; + if (y >= grid->height) + y = 0; + break; + case 7: + case 8: + /* left */ + x -= 1; + if (x < 0) + x = 0; + break; + default: + break; + } + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..26bc65e --- /dev/null +++ b/src/main.c @@ -0,0 +1,68 @@ +#include "game.h" +#include "grid.h" +#include "player.h" +#include "tiles.h" +#include +#include +#include + +static void init_rand(void); +/* return 1 to break */ +static int main_loop(struct Game *restrict game); + +int +main(void) +{ + struct Game game; + + init_rand(); + + game = game_init(); + + while (!main_loop(&game)) { + } + + game_deinit(game); + + return 1; +} + +static void +init_rand(void) +{ + dclear(C_BLACK); + dprint(0, 0, C_WHITE, "PRESS SHIFT"); + dupdate(); + + unsigned int seed = 0; + do { + clearevents(); + seed += 1; + } while (keydown(KEY_SHIFT)); + do { + clearevents(); + seed += 1; + } while (!keydown(KEY_SHIFT)); + srand(seed); +} + +static int +main_loop(struct Game *restrict game) +{ + static int scroll_x = 1 << 13; + + if (scroll_x == 1 << 13) + scroll_x = 99; + + clearevents(); + player_update(&game->player, &game->floor); + + dclear(C_BLACK); + grid_draw(game->floor, (scroll_x < 0) ? (scroll_x) : (0), 0); + player_draw(game->player, (scroll_x < 0) ? (scroll_x) : (0), 0); + dupdate(); + + scroll_x -= 1; + + return keydown(KEY_EXIT); +} diff --git a/src/player/draw.c b/src/player/draw.c new file mode 100644 index 0000000..5894892 --- /dev/null +++ b/src/player/draw.c @@ -0,0 +1,12 @@ +#include "player.h" +#include "tiles.h" +#include + +void +player_draw(struct Player player, int scr_x, int scr_y) +{ + const int x = scr_x + player.x * TILE_WIDTH; + const int y = scr_y + player.y * TILE_HEIGHT; + drect(x + 2, y + 2, x + TILE_WIDTH - 3, y + TILE_HEIGHT - 3, C_GREEN); + dprint(0, 0, C_RGB(31, 31, 0), "$%d", player.cash); +} diff --git a/src/player/init.c b/src/player/init.c new file mode 100644 index 0000000..c0a86c6 --- /dev/null +++ b/src/player/init.c @@ -0,0 +1,11 @@ +#include "player.h" + +struct Player +player_init(int x, int y) +{ + struct Player player; + player.x = x; + player.y = y; + player.cash = 0; + return player; +} diff --git a/src/player/update.c b/src/player/update.c new file mode 100644 index 0000000..420b72e --- /dev/null +++ b/src/player/update.c @@ -0,0 +1,52 @@ +#include "grid.h" +#include "player.h" +#include + +void +player_update(struct Player *restrict player, struct Grid *restrict grid) +{ + int new_x; + int new_y; + const int k_left = keydown(KEY_LEFT); + const int k_right = keydown(KEY_RIGHT); + const int k_up = keydown(KEY_UP); + const int k_down = keydown(KEY_DOWN); + const int move_x = + (k_right && !player->right_held) - (k_left && !player->left_held); + const int move_y = + (k_down && !player->down_held) - (k_up && !player->up_held); + + player->left_held += (k_left) ? (1) : (-player->left_held); + if (player->left_held > 6) + player->left_held = 0; + player->right_held += (k_right) ? (1) : (-player->right_held); + if (player->right_held > 6) + player->right_held = 0; + player->up_held += (k_up) ? (1) : (-player->up_held); + if (player->up_held > 6) + player->up_held = 0; + player->down_held += (k_down) ? (1) : (-player->down_held); + if (player->down_held > 6) + player->down_held = 0; + + new_x = player->x + move_x; + new_y = player->y + move_y; + if (new_x < 0) + new_x = 0; + if (new_y < 0) + new_y = grid->height - 1; + if (new_x >= grid->width) + new_x = grid->width - 1; + if (new_y >= grid->height) + new_y = 0; + + if (!grid_get(*grid, new_x, new_y)) { + player->x = new_x; + player->y = new_y; + } else if (grid_get(*grid, new_x, new_y) != TILE_SOLID) { + grid_set(grid, new_x, new_y, grid_get(*grid, new_x, new_y) - 1); + /* get rich! */ + if (!grid_get(*grid, new_x, new_y)) + player->cash += 1; + } +}