From bcf91590391c3847c753d8eb9db344d23af3d3aa Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Wed, 12 Jul 2023 00:08:00 +0200 Subject: [PATCH 01/18] add bash script for raylib installation Signed-off-by: Lorenzo Gualniera --- .gitignore | 2 +- Makefile | 24 ++++++++++++++++++------ install_raylib.sh | 25 +++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 install_raylib.sh diff --git a/.gitignore b/.gitignore index 4ff8a14..76749f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .vscode bin -lib +raylib \ No newline at end of file diff --git a/Makefile b/Makefile index 80f929b..8ae9801 100644 --- a/Makefile +++ b/Makefile @@ -2,33 +2,45 @@ TARGET_EXEC := doom_pico CC := gcc RM := rm -rf +MKDIR := mkdir -p SRC_DIR := src INC_DIR := inc -LIB_DIR := lib BIN_DIR := bin +RAYLIB_DIR := raylib SRCS := $(shell find $(SRC_DIR) -name '*.c' -or -name '*.s') OBJS := $(SRCS:%=$(BIN_DIR)/%.o) DEPS := $(OBJS:.o=.d) -CFLAGS := -Iinc -Ilib -MMD -MP -g +CFLAGS := -Iinc -MMD -MP -g LDFLAGS := -lm ifeq ($(USE_RAYLIB), 1) - CFLAGS += -DUSE_RAYLIB - LDFLAGS += -lraylib +CFLAGS += -I$(RAYLIB_DIR)/include -DUSE_RAYLIB +LDFLAGS += -L$(RAYLIB_DIR)/lib -lraylib +endif + +ifeq ($(OS), Windows_NT) +LDFLAGS += -lopengl32 -lgdi32 -lwinmm +else ifeq ($(shell uname -s), Linux) +LDFLAGS += -lGL -lpthread -ldl -lrt -lX11 +else +$(error Platform $(OS) currently not supported for make 'run' target) endif $(BIN_DIR)/$(TARGET_EXEC): $(OBJS) $(CC) $(OBJS) -o $@ $(LDFLAGS) $(BIN_DIR)/%.c.o: %.c - mkdir -p $(dir $@) + $(MKDIR) $(dir $@) $(CC) $(CFLAGS) -c $< -o $@ +$(RAYLIB_DIR): + ./install_raylib.sh + .PHONY: run -run: +run: $(RAYLIB_DIR) $(MAKE) clean $(MAKE) USE_RAYLIB=1 ./$(BIN_DIR)/$(TARGET_EXEC) diff --git a/install_raylib.sh b/install_raylib.sh new file mode 100644 index 0000000..6531188 --- /dev/null +++ b/install_raylib.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +RAYLIB_DIR="raylib" +RAYLIB_VERSION="4.5.0" +BASE_URL="https://github.com/raysan5/raylib/releases/download/${RAYLIB_VERSION}" +RAYLIB_ARCHIVE="" + +rm -rf "${RAYLIB_DIR}" +if [[ "${MSYSTEM}" == "MINGW"* ]]; then + echo "Downloading Raylib Mingw release..." + RAYLIB_ARCHIVE="raylib-${RAYLIB_VERSION}_win64_mingw-w64.zip" + curl -LO "${BASE_URL}/${RAYLIB_ARCHIVE}" + unzip "${RAYLIB_ARCHIVE}" + mv "${RAYLIB_ARCHIVE%.zip}" "${RAYLIB_DIR}" +elif [ "$(uname -s)" == "Linux" ]; then + echo "Downloading Raylib Linux release..." + RAYLIB_ARCHIVE="raylib-${RAYLIB_VERSION}_linux_amd64.tar.gz" + curl -LO "${BASE_URL}/${RAYLIB_ARCHIVE}" + tar -xzf "${RAYLIB_ARCHIVE}" + mv "${RAYLIB_ARCHIVE%.tar.gz}" "${RAYLIB_DIR}" +else + echo "Platform currently not supported." + exit 1 +fi +rm -rf "${RAYLIB_ARCHIVE}" From 950dff4c15b2f8cd2d24555efacf25f0b7176fb9 Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Wed, 19 Jul 2023 22:35:51 +0200 Subject: [PATCH 02/18] fix raylib library linking issue on Linux Signed-off-by: Lorenzo Gualniera --- Makefile | 25 +++++++++++++------------ install_raylib.sh | 26 ++++++++++++++------------ 2 files changed, 27 insertions(+), 24 deletions(-) mode change 100644 => 100755 install_raylib.sh diff --git a/Makefile b/Makefile index 8ae9801..20dbe7f 100644 --- a/Makefile +++ b/Makefile @@ -9,24 +9,23 @@ INC_DIR := inc BIN_DIR := bin RAYLIB_DIR := raylib -SRCS := $(shell find $(SRC_DIR) -name '*.c' -or -name '*.s') +SRCS := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s") OBJS := $(SRCS:%=$(BIN_DIR)/%.o) DEPS := $(OBJS:.o=.d) -CFLAGS := -Iinc -MMD -MP -g +CFLAGS := -I$(INC_DIR) -MMD -MP -g LDFLAGS := -lm ifeq ($(USE_RAYLIB), 1) -CFLAGS += -I$(RAYLIB_DIR)/include -DUSE_RAYLIB -LDFLAGS += -L$(RAYLIB_DIR)/lib -lraylib -endif - -ifeq ($(OS), Windows_NT) -LDFLAGS += -lopengl32 -lgdi32 -lwinmm -else ifeq ($(shell uname -s), Linux) -LDFLAGS += -lGL -lpthread -ldl -lrt -lX11 -else -$(error Platform $(OS) currently not supported for make 'run' target) + CFLAGS += -I$(RAYLIB_DIR)/include -DUSE_RAYLIB + LDFLAGS += -L$(RAYLIB_DIR)/lib -lraylib + ifeq ($(OS), Windows_NT) + LDFLAGS += -lopengl32 -lgdi32 -lwinmm + else ifeq ($(shell uname -s), Linux) + LDFLAGS += -lGL -lpthread -ldl -lrt -lX11 + else + $(error Platform $(OS) currently not supported for make "run" target) + endif endif $(BIN_DIR)/$(TARGET_EXEC): $(OBJS) @@ -47,6 +46,8 @@ run: $(RAYLIB_DIR) .PHONY: clean clean: +ifneq (,$(wildcard $(BIN_DIR))) $(RM) $(BIN_DIR) +endif -include $(DEPS) diff --git a/install_raylib.sh b/install_raylib.sh old mode 100644 new mode 100755 index 6531188..2ef8996 --- a/install_raylib.sh +++ b/install_raylib.sh @@ -7,19 +7,21 @@ RAYLIB_ARCHIVE="" rm -rf "${RAYLIB_DIR}" if [[ "${MSYSTEM}" == "MINGW"* ]]; then - echo "Downloading Raylib Mingw release..." - RAYLIB_ARCHIVE="raylib-${RAYLIB_VERSION}_win64_mingw-w64.zip" - curl -LO "${BASE_URL}/${RAYLIB_ARCHIVE}" - unzip "${RAYLIB_ARCHIVE}" - mv "${RAYLIB_ARCHIVE%.zip}" "${RAYLIB_DIR}" + echo "Downloading Raylib Mingw release..." + RAYLIB_ARCHIVE="raylib-${RAYLIB_VERSION}_win64_mingw-w64.zip" + curl -LO "${BASE_URL}/${RAYLIB_ARCHIVE}" + unzip "${RAYLIB_ARCHIVE}" + mv "${RAYLIB_ARCHIVE%.zip}" "${RAYLIB_DIR}" + find "${RAYLIB_DIR}/lib/" -name "*dll" -delete elif [ "$(uname -s)" == "Linux" ]; then - echo "Downloading Raylib Linux release..." - RAYLIB_ARCHIVE="raylib-${RAYLIB_VERSION}_linux_amd64.tar.gz" - curl -LO "${BASE_URL}/${RAYLIB_ARCHIVE}" - tar -xzf "${RAYLIB_ARCHIVE}" - mv "${RAYLIB_ARCHIVE%.tar.gz}" "${RAYLIB_DIR}" + echo "Downloading Raylib Linux release..." + RAYLIB_ARCHIVE="raylib-${RAYLIB_VERSION}_linux_amd64.tar.gz" + curl -LO "${BASE_URL}/${RAYLIB_ARCHIVE}" + tar -xzf "${RAYLIB_ARCHIVE}" + mv "${RAYLIB_ARCHIVE%.tar.gz}" "${RAYLIB_DIR}" + find "${RAYLIB_DIR}/lib/" -name "*.so*" -delete else - echo "Platform currently not supported." - exit 1 + echo "Platform currently not supported." + exit 1 fi rm -rf "${RAYLIB_ARCHIVE}" From 600cadbd8c59ea52567dee8b46e06477b5760b61 Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Thu, 20 Jul 2023 00:22:17 +0200 Subject: [PATCH 03/18] begin integration of doom nano brutality Signed-off-by: Lorenzo Gualniera --- inc/constants.h | 73 +-- inc/entities.h | 68 ++- inc/level.h | 522 +++++++++------- inc/sound.h | 149 ++++- inc/sprites.h | 225 +++++-- src/game.c | 1561 ++++++++++++++++++++++++++++++++++++----------- src/game_old.c | 1157 +++++++++++++++++++++++++++++++++++ 7 files changed, 3053 insertions(+), 702 deletions(-) create mode 100644 src/game_old.c diff --git a/inc/constants.h b/inc/constants.h index 31449ba..b65f8f0 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -8,22 +8,6 @@ /* Frame rate */ #define FPS 15 #define FRAME_TIME (1000.0f / FPS) - -/* Higher values will result in lower horizontal resolution when rasterize and - * lower process and memory usage. Lower will require more process and memory, - * but looks nicer. */ -#define RES_DIVIDER 2 - -/* Zbuffer resolution divider. We sacrifice resolution to save memory. */ -#define Z_RES_DIVIDER 2 - -/* Distances are stored as uint8_t, multiplying the distance we can obtain more - * precision taking care of keep numbers inside the type range. - * Max is 256 / MAX_RENDER_DEPTH */ -#define DISTANCE_MULTIPLIER 20 -#define MAX_RENDER_DEPTH 12 -#define MAX_SPRITE_DEPTH 8 - /* Display */ #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 @@ -32,39 +16,56 @@ #define RENDER_HEIGHT 58 // Raycaster working height #define HUD_HEIGHT 6 // HUD working height -/* Level */ +#define RES_DIVIDER 2 // Higher values will result in lower horizontal resolution when rasterize and lower process and memory usage + // Lower will require more process and memory, but looks nicer +#define Z_RES_DIVIDER 2 // Zbuffer resolution divider. We sacrifice resolution to save memory +#define DISTANCE_MULTIPLIER 20 // Distances are stored as uint8_t, multiplying the distance we can obtain more precision taking care + // of keep numbers inside the type range. Max is 256 / MAX_RENDER_DEPTH +#define MAX_RENDER_DEPTH 12 +#define MAX_SPRITE_DEPTH 8 + +#define ZBUFFER_SIZE SCREEN_WIDTH / Z_RES_DIVIDER + 4 + +// Level #define LEVEL_WIDTH_BASE 6 #define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) #define LEVEL_HEIGHT 57 -#define LEVEL_SIZE (LEVEL_WIDTH / 2 * LEVEL_HEIGHT) - -/* Game */ +#define LEVEL_SIZE LEVEL_WIDTH / 2 * LEVEL_HEIGHT + +// scenes +#define INTRO 0 +#define GAME_PLAY 1 +#define DIFF 2 +#define MUS 3 +#define MID 4 +#define SCORE 5 +// Game #define GUN_TARGET_POS 18 -#define GUN_SHOT_POS (GUN_TARGET_POS + 4) +#define GUN_SHOT_POS GUN_TARGET_POS + 8 -#define ROT_SPEED 0.12f -#define MOV_SPEED 0.2f -#define MOV_SPEED_INV (1.0f / MOV_SPEED) +#define ROT_SPEED .12 +#define MOV_SPEED .1 +#define MOV_SPEED_INV 2.5 // 1 / MOV_SPEED -#define JOGGING_SPEED 0.005f -#define ENEMY_SPEED 0.02f -#define FIREBALL_SPEED 0.2f +#define JOGGING_SPEED .005 +#define ENEMY_SPEED .04 +#define FIREBALL_SPEED .2 #define FIREBALL_ANGLES 45 // Num of angles per PI -#define MAX_ENTITIES 10 // Max num of active entities -#define MAX_STATIC_ENTITIES 28 // Max num of entities in sleep mode +#define MAX_ENTITIES 12 // Max num of active entities +#define MAX_STATIC_ENTITIES 24 // Max num of entities in sleep mode #define MAX_ENTITY_DISTANCE 200 // * DISTANCE_MULTIPLIER -#define MAX_ENEMY_VIEW 80 // * DISTANCE_MULTIPLIER +#define MAX_ENEMY_VIEW 90 // * DISTANCE_MULTIPLIER #define ITEM_COLLIDER_DIST 6 // * DISTANCE_MULTIPLIER #define ENEMY_COLLIDER_DIST 4 // * DISTANCE_MULTIPLIER -#define FIREBALL_COLLIDER_DIST 2 // * DISTANCE_MULTIPLIER -#define ENEMY_MELEE_DIST 6 // * DISTANCE_MULTIPLIER -#define WALL_COLLIDER_DIST 0.2f +#define FIREBALL_COLLIDER_DIST 3 // * DISTANCE_MULTIPLIER +#define ENEMY_MELEE_DIST 9 // * DISTANCE_MULTIPLIER +#define WALL_COLLIDER_DIST .2 -#define ENEMY_MELEE_DAMAGE 8 -#define ENEMY_FIREBALL_DAMAGE 20 -#define GUN_MAX_DAMAGE 15 +#define ENEMY_MELEE_DAMAGE 18 +#define ENEMY_FIREBALL_DAMAGE 25 +#define GUN_MAX_DAMAGE 80 #endif /* CONSTANTS_H */ diff --git a/inc/entities.h b/inc/entities.h index 9426c88..593d586 100644 --- a/inc/entities.h +++ b/inc/entities.h @@ -20,16 +20,18 @@ typedef uint16_t EntityUID; typedef enum { - E_FLOOR = 0x0, // . (also null) - E_WALL = 0xF, // # - E_PLAYER = 0x1, // P - E_ENEMY = 0x2, // E - E_DOOR = 0x4, // D - E_LOCKEDDOOR = 0x5, // L - E_EXIT = 0x7, // X - E_MEDKIT = 0x8, // M - E_KEY = 0x9, // K - E_FIREBALL = 0xa, // not in map + E_FLOOR = 0x0, // . (also null) + E_WALL = 0xF, // # + E_DOOR = 0xD, + E_DOOR2 = 0xA, + E_DOOR3 = 0xB, + E_COLL = 0xC, + E_PLAYER = 0x1, // P + E_ENEMY = 0x2, // E + E_EXIT = 0x7, // X + E_MEDKIT = 0x8, // M + E_KEY = 0x9, // K + E_FIREBALL = 0xA // not in map } EntityType; typedef enum @@ -53,6 +55,11 @@ typedef struct float velocity; uint8_t health; uint8_t keys; + uint8_t secret; + uint8_t secret2; + uint8_t secret3; + int16_t score; + bool cheats; } Player; typedef struct @@ -60,9 +67,11 @@ typedef struct EntityUID uid; Coords pos; uint8_t state; - uint8_t health; // angle for fireballs + uint8_t health; uint8_t distance; uint8_t timer; + bool a; + bool b; } Entity; typedef struct @@ -77,7 +86,7 @@ typedef struct /** * @brief ENTITIES get UID from entity type and location. - * + * * @param type Entity type * @param x X coordinate * @param y Y coordinate @@ -87,7 +96,7 @@ EntityUID entities_get_uid(EntityType type, uint8_t x, uint8_t y); /** * @brief ENTITIES get entity type from UID. - * + * * @param uid Entity UID * @return EntityType Entity type */ @@ -97,7 +106,7 @@ EntityType entities_get_type(EntityUID uid); /** * @brief ENTITIES create player entity struct. - * + * * @param x X coordinate * @param y Y coordinate * @return Player Player entity instance @@ -110,12 +119,17 @@ static inline Player entities_create_player(uint8_t x, uint8_t y) .plane = {0.0f, -0.66f}, .velocity = 0.0f, .health = 100, - .keys = 0}; + .keys = 10, + .secret = 0, + .secret2 = 0, + .secret3 = 0, + .score = 0, + .cheats = false}; } /** * @brief ENTITIES create enemy entity struct. - * + * * @param x X coordinate * @param y Y coordinate * @return Entity Enemy entity instance @@ -128,12 +142,14 @@ static inline Entity entities_create_enemy(uint8_t x, uint8_t y) .state = S_STAND, .health = 100, .distance = 0, - .timer = 0}; + .timer = 0, + .a = false, + .b = false}; } /** * @brief ENTITIES create medkit entity struct. - * + * * @param x X coordinate * @param y Y coordinate * @return Entity Medkit entity instance @@ -146,12 +162,14 @@ static inline Entity entities_create_medkit(uint8_t x, uint8_t y) .state = S_STAND, .health = 100, .distance = 0, - .timer = 0}; + .timer = 0, + .a = false, + .b = false}; } /** * @brief ENTITIES create key entity struct. - * + * * @param x X coordinate * @param y Y coordinate * @return Entity Key entity instance @@ -164,12 +182,14 @@ static inline Entity entities_create_key(uint8_t x, uint8_t y) .state = S_STAND, .health = 100, .distance = 0, - .timer = 0}; + .timer = 0, + .a = false, + .b = false}; } /** * @brief ENTITIES create fireball entity struct. - * + * * @param x X coordinate * @param y Y coordinate * @param dir Angle @@ -183,7 +203,9 @@ static inline Entity entities_create_fireball(uint8_t x, uint8_t y, uint8_t dir) .state = S_STAND, .health = dir, .distance = 0, - .timer = 0}; + .timer = 0, + .a = false, + .b = false}; } #endif /* ENTITIES_H */ diff --git a/inc/level.h b/inc/level.h index 0d424e6..be76121 100644 --- a/inc/level.h +++ b/inc/level.h @@ -5,227 +5,315 @@ /* Includes ----------------------------------------------------------------- */ -#include - #include "constants.h" /* Definitions -------------------------------------------------------------- */ -/** - * @brief E1M1 level from Wolfenstein 3D - * @details The map is built with regexp replacements using the legend above. - * Each block uses 4 bit. - * - * ################################################################ - * #############################...........######################## - * ######....###################........E..######################## - * ######....########..........#...........#...#################### - * ######.....#######..........L.....E.......M.#################### - * ######.....#######..........#...........#...#################### - * ##################...########...........######################## - * ######.........###...########...........######################## - * ######.........###...#############D############################# - * ######.........#......E##########...############################ - * ######....E....D...E...##########...############################ - * ######.........#.......##########...############################ - * ######....E....##################...############################ - * #...##.........##################...############################ - * #.K.######D######################...############################ - * #...#####...###############...#E.....K########################## - * ##D######...###############..####...############################ - * #...#####...###############..####...############################ - * #...#...#...###############..####...############################ - * #...D...#...#####################...############################ - * #...#...#...#####################...############################ - * #...######D#######################L############################# - * #.E.##.........#################.....#################........## - * #...##.........############...............############........## - * #...##...E.....############...............############........## - * #....#.........############...E.......E....#.........#........## - * #....L....K....############................D....E....D....E...## - * #....#.........############................#.........#........## - * #...##.....E...############...............####....####........## - * #...##.........############...............#####..#####.....M..## - * #...##.........#################.....##########..#####........## - * #...######L#######################D############..############### - * #...#####...#####################...###########..############### - * #E.E#####...#####################...###########..############### - * #...#...#...#####################.E.###########..############### - * #...D.M.#...#####################...###########..############### - * #...#...#...#####################...###########..###.#.#.#.##### - * #...#####...#####################...###########...#.........#### - * #...#####...#####################...###########...D....E..K.#### - * #................##......########...###########...#.........#### - * #....E........E...L...E...X######...################.#.#.#.##### - * #................##......########...############################ - * #################################...############################ - * #############..#..#..#############L############################# - * ###########....#..#.########....#...#....####################### - * #############.....##########.P..D...D....####################### - * ############################....#...#....####################### - * ##############..#################...############################ - * ##############..############....#...#....####################### - * ############################....D...D....####################### - * ############################....#...#....####################### - * #################################...############################ - * ############################.............####################### - * ############################..........EK.####################### - * ############################.............####################### - * ################################################################ - */ -static const uint8_t level_1[LEVEL_SIZE] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, - 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x0f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x20, 0x00, 0x04, - 0x00, 0x02, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x20, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x90, 0xff, 0xff, 0xff, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xf2, - 0x00, 0x00, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x4f, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x0f, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xf0, 0x00, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x40, 0x00, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x20, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xf0, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0x00, 0xff, 0x00, - 0x02, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, - 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xf0, 0x00, 0x05, 0x00, 0x00, 0x90, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0xff, 0xf0, 0x00, 0x0f, 0x00, - 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, - 0x00, 0x00, 0x00, 0xff, 0xf0, 0x00, 0xff, 0x00, 0x00, 0x02, 0x00, 0x0f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xf0, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, - 0x0f, 0xff, 0xff, 0x00, 0x00, 0x08, 0x00, 0xff, 0xf0, 0x00, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0x5f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0x02, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x20, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0x40, 0x80, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xf0, 0x00, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0x0f, 0x0f, - 0x0f, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x00, 0x40, 0x00, 0x02, 0x00, 0x90, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xf0, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, - 0x00, 0x50, 0x00, 0x20, 0x00, 0x7f, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, - 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, - 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, - 0x00, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0x00, 0xf0, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x0f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, - 0x40, 0x00, 0x40, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, - 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xf0, 0x00, 0xf0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, - 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x0f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const uint8_t E1M1[LEVEL_SIZE] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0x0F, 0xF0, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, + 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x0C, 0x02, 0x20, 0xC0, 0x00, + 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x0F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x04, + 0x00, 0x02, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x20, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x90, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF2, + 0x00, 0x00, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x20, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0xFF, 0x00, + 0x02, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xF0, 0x00, 0x05, 0x00, 0x00, 0x90, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0xFF, 0xF0, 0x00, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x08, 0x00, 0xFF, 0xF0, 0x00, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2, 0x02, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x20, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0x40, 0x80, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0x0F, 0x0F, + 0x8F, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, + 0x00, 0x40, 0x00, 0x02, 0x00, 0x90, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x50, 0x00, 0x20, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, + 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, + 0x00, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x90, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, + 0x40, 0x00, 0x40, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x80, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x02, 0x02, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +static const uint8_t E1M2[LEVEL_SIZE] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, + 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x08, 0x90, 0xF0, 0xF0, 0xF0, 0x00, + 0x00, 0xF0, 0xF0, 0x00, 0xF0, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xFF, + 0xF0, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF8, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, + 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0xFF, + 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xFF, + 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF8, 0x00, 0xF0, 0xF0, 0xF0, + 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0xF0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0xF0, 0xF0, 0xFF, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0x00, + 0x00, 0xF0, 0xF0, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF2, + 0x09, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, + 0xF0, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, 0xF0, 0xF0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x0F, 0xF0, 0xF0, + 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x00, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0xF0, + 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xF0, + 0xFF, 0xF0, 0xF0, 0xFF, 0xF0, 0xF0, 0xF2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0xF0, 0xF2, 0xF0, 0xF0, 0x00, 0xF0, 0x00, + 0x00, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF9, 0x00, 0xF0, 0xF0, 0x00, + 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x09, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x80, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, + 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xF0, 0x00, + 0x00, 0xF0, 0xF0, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0x00, 0xF2, 0x00, 0x00, + 0x0F, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0xF2, 0xF0, 0xF0, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, + 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, + 0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF}; #endif /* LEVEL_H */ diff --git a/inc/sound.h b/inc/sound.h index 444e9a0..a2635a3 100644 --- a/inc/sound.h +++ b/inc/sound.h @@ -12,11 +12,139 @@ /* Definitions -------------------------------------------------------------- */ +static const uint8_t MUS_S1_SND_LEN = 38; +static const uint8_t mus_s1_snd[] = { + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P1_SND_LEN = 19; +static const uint8_t mus_p1_snd[] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P2_SND_LEN = 19; +static const uint8_t mus_p2_snd[] = {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P3_SND_LEN = 19; +static const uint8_t mus_p3_snd[] = {0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P4_SND_LEN = 19; +static const uint8_t mus_p4_snd[] = {0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P5_SND_LEN = 19; +static const uint8_t mus_p5_snd[] = {0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, + 0x53, 0x53, 0x53, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P6_SND_LEN = 19; +static const uint8_t mus_p6_snd[] = {0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P7_SND_LEN = 19; +static const uint8_t mus_p7_snd[] = {0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58}; + +static const uint8_t MUS_S21_SND_LEN = 38; +static const uint8_t mus_s21_snd[] = { + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P21_SND_LEN = 19; +static const uint8_t mus_p21_snd[] = {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P22_SND_LEN = 19; +static const uint8_t mus_p22_snd[] = {0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P24_SND_LEN = 19; +static const uint8_t mus_p24_snd[] = {0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P26_SND_LEN = 19; +static const uint8_t mus_p26_snd[] = {0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_P27_SND_LEN = 38; +static const uint8_t mus_p27_snd[] = { + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24}; + +static const uint8_t MUS_P28_SND_LEN = 38; +static const uint8_t mus_p28_snd[] = { + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}; + +static const uint8_t MUS_P29_SND_LEN = 38; +static const uint8_t mus_p29_snd[] = { + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45}; + +static const uint8_t MUS_EP_SND_LEN = 38; +static const uint8_t mus_ep_snd[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t MUS_EP2_SND_LEN = 19; +static const uint8_t mus_ep2_snd[] = {0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45}; + +static const uint8_t JUMP_SND_LEN = 19; +static const uint8_t jump_snd[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x25, 0x25, 0x25, 0x25, 0x25}; + +static const uint8_t S_SND_LEN = 38; +static const uint8_t s_snd[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}; + +static const uint8_t R1_SND_LEN = 9; +static const uint8_t r1_snd[] = {0x95, 0x95, 0x95}; + +static const uint8_t R2_SND_LEN = 9; +static const uint8_t r2_snd[] = {0x50, 0x50, 0x50}; + +static const uint8_t SHOT_SND_LEN = 44; +static const uint8_t shot_snd[] = { + 0x10, 0x10, 0x10, 0x6e, 0x2a, 0x20, 0x28, 0x28, 0x9b, 0x28, 0x20, + 0x20, 0x21, 0x57, 0x20, 0x20, 0x20, 0x67, 0x20, 0x20, 0x29, 0x20, + 0x73, 0x20, 0x20, 0x20, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static const uint8_t SHOOT_SND_LEN = 27; -static const uint8_t shoot_snd[] = { - 0x10, 0x10, 0x10, 0x6e, 0x2a, 0x20, 0x28, 0x28, 0x9b, 0x28, 0x20, 0x20, - 0x21, 0x57, 0x20, 0x20, 0x20, 0x67, 0x20, 0x20, 0x29, 0x20, 0x73, 0x20, - 0x20, 0x20, 0x89}; +static const uint8_t shoot_snd[] = {0x10, 0x10, 0x10, 0x6e, 0x2a, 0x20, 0x28, + 0x28, 0x9b, 0x28, 0x20, 0x20, 0x21, 0x57, + 0x20, 0x20, 0x20, 0x67, 0x20, 0x20, 0x29, + 0x20, 0x73, 0x20, 0x20, 0x20, 0x89}; static const uint8_t GET_KEY_SND_LEN = 90; static const uint8_t get_key_snd[] = { @@ -30,8 +158,8 @@ static const uint8_t get_key_snd[] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19}; static const uint8_t HIT_WALL_SND_LEN = 8; -static const uint8_t hit_wall_snd[] = { - 0x83, 0x83, 0x82, 0x8e, 0x8a, 0x89, 0x86, 0x84}; +static const uint8_t hit_wall_snd[] = {0x83, 0x83, 0x82, 0x8e, + 0x8a, 0x89, 0x86, 0x84}; static const uint8_t WALK1_SND_LEN = 3; static const uint8_t walk1_snd[] = {0x8f, 0x8e, 0x8e}; @@ -48,6 +176,15 @@ static const uint8_t medkit_snd[] = { 0x20, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15}; +static const uint8_t MELEE_SND_LEN = 9; +static const uint8_t melee_snd[] = {0x8f, 0x8e, 0x8e}; + +uint8_t idx = 0; +bool sound = false; +uint16_t snd_ptr = 0; +uint8_t snd_len = 0; +uint8_t music = 0; + /* Function prototypes ------------------------------------------------------ */ /** diff --git a/inc/sprites.h b/inc/sprites.h index b609298..419c586 100644 --- a/inc/sprites.h +++ b/inc/sprites.h @@ -9,24 +9,24 @@ /* Definitions -------------------------------------------------------------- */ -#define bmp_font_width 24 +#define bmp_font_width 24 // in bytes #define bmp_font_height 6 #define CHAR_MAP " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.,-_(){}[]#" #define CHAR_WIDTH 4 #define CHAR_HEIGHT 6 static const uint8_t bmp_font[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0x80, 0x06, 0x26, 0x69, 0xf6, 0xf6, 0x66, 0xe6, 0xef, 0xf6, 0x92, 0x19, 0x89, - 0x96, 0xe6, 0xe6, 0xe9, 0x99, 0x99, 0xf0, 0x00, 0x02, 0x41, 0x83, 0xcf, + 0x96, 0xe6, 0xe6, 0xe9, 0x99, 0x99, 0xf0, 0x00, 0x02, 0x41, 0x83, 0x8f, 0x09, 0x29, 0x99, 0x88, 0x19, 0x99, 0x99, 0x98, 0x88, 0x92, 0x1a, 0x8f, - 0xd9, 0x99, 0x98, 0x49, 0x99, 0x99, 0x10, 0x00, 0x04, 0x27, 0xe5, 0x6f, - 0x09, 0x22, 0x2f, 0xee, 0x16, 0x7f, 0xe8, 0x9e, 0xe8, 0xf2, 0x1c, 0x89, - 0xb9, 0xe9, 0xe6, 0x49, 0x99, 0x66, 0x60, 0x06, 0x04, 0x27, 0xe7, 0xef, + 0xd9, 0x99, 0x98, 0x49, 0x99, 0x99, 0x10, 0x00, 0x04, 0x27, 0xe3, 0x8f, + 0x09, 0x22, 0x2f, 0xee, 0x16, 0x7f, 0xe8, 0x9e, 0xea, 0xf2, 0x1c, 0x89, + 0xb9, 0xe9, 0xe6, 0x49, 0x99, 0x66, 0x60, 0x06, 0x04, 0x27, 0xe2, 0x8f, 0x09, 0x24, 0x91, 0x19, 0x19, 0x19, 0x99, 0x98, 0x89, 0x92, 0x9a, 0x89, - 0x99, 0x8b, 0x91, 0x49, 0x6f, 0x96, 0x80, 0x20, 0x04, 0x21, 0x87, 0xef, + 0x99, 0x8b, 0x91, 0x49, 0x6f, 0x96, 0x80, 0x20, 0x04, 0x21, 0x82, 0x8f, 0x06, 0x7f, 0x61, 0xe6, 0x16, 0x69, 0xe6, 0xef, 0x86, 0x92, 0x69, 0xf9, - 0x96, 0x87, 0x9e, 0x46, 0x69, 0x96, 0xf4, 0x40, 0xf2, 0x41, 0x80, 0xe0}; + 0x96, 0x87, 0x9e, 0x46, 0x69, 0x96, 0xf4, 0x40, 0xf2, 0x41, 0x87, 0xc0}; #define BMP_LOGO_WIDTH 72 #define BMP_LOGO_HEIGHT 47 @@ -68,32 +68,162 @@ static const uint8_t bmp_logo_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c}; -#define BMP_GUN_WIDTH 32 +#define BMP_GUN_WIDTH 51 #define BMP_GUN_HEIGHT 32 static const uint8_t bmp_gun_bits[] = { - 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x01, 0xc4, 0x00, - 0x00, 0x02, 0x04, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0xea, 0x00, - 0x00, 0x04, 0xd1, 0x00, 0x00, 0x09, 0x88, 0x80, 0x00, 0x19, 0x00, 0x00, - 0x00, 0x0d, 0xc2, 0x80, 0x00, 0x29, 0x81, 0xc0, 0x00, 0x0b, 0xa2, 0x20, - 0x00, 0x31, 0x40, 0x40, 0x00, 0x23, 0x00, 0xc0, 0x00, 0x13, 0x00, 0x40, - 0x00, 0x72, 0x02, 0x00, 0x00, 0x49, 0x00, 0x40, 0x01, 0xe0, 0xa8, 0x20, - 0x07, 0xf1, 0x00, 0x30, 0x0b, 0xb9, 0xe0, 0xe8, 0x07, 0x5c, 0x03, 0xfc, - 0x07, 0xef, 0xff, 0xee, 0x07, 0x75, 0x7f, 0xd2, 0x1b, 0xbb, 0xff, 0xb2, - 0x11, 0x57, 0x7d, 0x64, 0x32, 0xaf, 0xff, 0xe8, 0x13, 0x5f, 0x75, 0xd0, - 0x33, 0xff, 0xfb, 0x98, 0x17, 0xd7, 0xe5, 0x00, 0x1b, 0x8f, 0xb2, 0x30, - 0x03, 0x7d, 0x58, 0x10, 0x6f, 0xbf, 0xec, 0x20}; + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x21, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, + 0xc0, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x78, 0x00, 0x00, 0x00, 0x0f, + 0xe0, 0x70, 0x3c, 0x00, 0x00, 0x00, 0x78, 0x20, 0x20, 0x16, 0x00, 0x00, + 0x01, 0xf0, 0x60, 0x00, 0x1f, 0x00, 0x00, 0x03, 0x48, 0xc0, 0x00, 0x09, + 0x80, 0x00, 0x06, 0x24, 0xb8, 0x00, 0xec, 0x80, 0x00, 0x06, 0x11, 0xb8, + 0x00, 0xe4, 0x80, 0x00, 0x06, 0x0b, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x0c, + 0x06, 0xff, 0x8f, 0xfb, 0x60, 0x00, 0x0c, 0x0c, 0x3e, 0x03, 0xf1, 0xb8, + 0x00, 0x0c, 0x08, 0x08, 0x00, 0xc0, 0x98, 0x00, 0x0c, 0x18, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x18, 0x13, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x10, 0x3c, + 0x00, 0x00, 0x01, 0xec, 0x00, 0x30, 0x28, 0x00, 0x20, 0x00, 0xac, 0x00, + 0x70, 0x30, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x7f, 0xe0, 0x00, 0x20, 0x00, + 0x28, 0x00, 0x7f, 0xe0, 0x00, 0x20, 0x00, 0x38, 0x00, 0xf0, 0x40, 0x00, + 0x20, 0x00, 0x10, 0x00, 0xa4, 0xc0, 0x00, 0x20, 0x00, 0x18, 0x00, 0x00, + 0x40, 0x00, 0x20, 0x00, 0x18, 0x00, 0x92, 0x40, 0x00, 0x20, 0x00, 0x1e, + 0x00, 0x00, 0xc0, 0x00, 0x20, 0x00, 0x1b, 0x00}; static const uint8_t bmp_gun_mask[] = { - 0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x03, 0xfe, 0x00, - 0x00, 0x07, 0xfe, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x07, 0xff, 0x00, - 0x00, 0x0f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0x80, - 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xf0, - 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xe0, - 0x00, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xf0, - 0x0f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xfe, - 0x1f, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, - 0x3f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8, - 0x7f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xf8, - 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf0}; + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xde, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xef, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x8f, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xdf, 0xdf, 0xe8, 0x00, 0x00, + 0x00, 0x0f, 0x9f, 0xff, 0xe0, 0x00, 0x00, 0x00, 0xb7, 0x3f, 0xff, 0xf6, + 0x00, 0x00, 0x01, 0xdb, 0x47, 0xff, 0x13, 0x00, 0x00, 0x01, 0xee, 0x47, + 0xff, 0x1b, 0x00, 0x00, 0x01, 0xf4, 0xff, 0xff, 0xf9, 0x00, 0x00, 0x03, + 0xf9, 0x00, 0x70, 0x04, 0x80, 0x00, 0x03, 0xf3, 0xc1, 0xfc, 0x0e, 0x40, + 0x00, 0x03, 0xf7, 0xf7, 0xff, 0x3f, 0x60, 0x00, 0x03, 0xe7, 0xff, 0xff, + 0xff, 0xb0, 0x00, 0x07, 0xec, 0xff, 0xff, 0xfc, 0xb0, 0x00, 0x0f, 0xc3, + 0xff, 0xff, 0xfe, 0x10, 0x00, 0x0f, 0xd7, 0xff, 0xdf, 0xff, 0x50, 0x00, + 0x0f, 0xcf, 0xff, 0xdf, 0xff, 0x90, 0x00, 0x00, 0x1f, 0xff, 0xdf, 0xff, + 0xd0, 0x00, 0x00, 0x1f, 0xff, 0xdf, 0xff, 0xc0, 0x00, 0x0f, 0xbf, 0xff, + 0xdf, 0xff, 0xe0, 0x00, 0x5b, 0x3f, 0xff, 0xdf, 0xff, 0xe0, 0x00, 0xff, + 0xbf, 0xff, 0xdf, 0xff, 0xe0, 0x00, 0x6d, 0xbf, 0xff, 0xdf, 0xff, 0xe0, + 0x00, 0xff, 0x3f, 0xff, 0xdf, 0xff, 0xe4, 0x00}; + +#define BMP_RE1_WIDTH 47 +#define BMP_RE1_HEIGHT 51 +static const uint8_t bmp_re1_bits[] = { + 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x20, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x20, 0x84, 0x00, 0x00, + 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0x80, 0x00, + 0x00, 0x00, 0x20, 0xa3, 0xc0, 0x00, 0x00, 0x00, 0x20, 0x8a, 0x78, 0x00, + 0x00, 0x00, 0x22, 0xa2, 0x07, 0x80, 0x00, 0x00, 0x22, 0x8f, 0xe0, 0xf0, + 0x00, 0x00, 0x22, 0x98, 0x7c, 0x18, 0x00, 0x00, 0x22, 0x88, 0x07, 0xf8, + 0x00, 0x00, 0x22, 0xa4, 0x00, 0x6c, 0x00, 0x00, 0x22, 0x8a, 0x00, 0x3c, + 0x00, 0x00, 0xe2, 0x87, 0xfc, 0x0c, 0x00, 0x03, 0x22, 0xd4, 0x03, 0xc4, + 0x00, 0x06, 0x22, 0xc4, 0x00, 0x34, 0x00, 0x04, 0x22, 0xe6, 0x00, 0x3e, + 0x00, 0x0c, 0x22, 0x43, 0xf8, 0x02, 0x00, 0x08, 0x22, 0x4a, 0x0f, 0x02, + 0x00, 0x08, 0x22, 0x42, 0x01, 0xe2, 0x00, 0x08, 0x23, 0x53, 0x00, 0x1a, + 0x00, 0x18, 0x21, 0x45, 0x80, 0x06, 0x00, 0x34, 0x21, 0x40, 0xfc, 0x06, + 0x00, 0x20, 0x21, 0x68, 0x3f, 0x06, 0x00, 0x20, 0x21, 0x7f, 0xf0, 0x82, + 0x00, 0x20, 0x21, 0x7c, 0x38, 0x82, 0x00, 0x30, 0x20, 0x66, 0x3c, 0x42, + 0x00, 0x60, 0x60, 0x32, 0x0c, 0x36, 0x00, 0x48, 0x40, 0x0a, 0x0c, 0x1c, + 0x00, 0x43, 0x49, 0x06, 0x0c, 0x08, 0x00, 0x40, 0x49, 0x23, 0x0c, 0x08, + 0x01, 0xe0, 0x49, 0x3d, 0xd8, 0x18, 0x02, 0x3c, 0x49, 0x34, 0xf8, 0x70, + 0x06, 0x17, 0x49, 0x34, 0xb0, 0xc0, 0x05, 0xcd, 0xc9, 0x14, 0x89, 0x80, + 0x0e, 0xb2, 0x49, 0x94, 0x8d, 0x00, 0x09, 0x19, 0x48, 0x9a, 0xcf, 0x00, + 0x08, 0x04, 0xc8, 0x86, 0x4e, 0x00, 0x18, 0x97, 0x88, 0xc6, 0x46, 0x00, + 0x31, 0x4a, 0x98, 0x40, 0x47, 0x00, 0x3a, 0x94, 0x90, 0x00, 0x65, 0x80, + 0x61, 0x0a, 0x90, 0x08, 0x24, 0x80, 0xc0, 0x00, 0x80, 0x00, 0x3c, 0x80, + 0xaa, 0x94, 0x80, 0x01, 0x00, 0x80}; +static const uint8_t bmp_re1_mask[] = { + 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x07, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x1f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x01, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x3f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80}; + +#define BMP_RE2_WIDTH 44 +#define BMP_RE2_HEIGHT 51 +static const uint8_t bmp_re2_bits[] = { + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x61, 0x80, 0x00, 0x00, 0x00, 0x00, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, + 0xde, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xc4, 0x00, 0x00, 0x00, 0x00, + 0x2e, 0x42, 0x00, 0x00, 0x00, 0x00, 0x30, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x42, 0x00, 0x00, 0x00, 0x00, 0x20, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x31, 0x63, 0x00, 0x00, 0x00, 0x00, 0x11, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x21, 0x00, 0x00, 0x00, 0x00, 0x11, 0x2f, 0xbe, 0x00, 0x00, 0x00, + 0x11, 0x32, 0x41, 0xf8, 0x00, 0x00, 0x11, 0xb2, 0x40, 0x0c, 0x00, 0x00, + 0x10, 0xb1, 0x5f, 0xfe, 0x00, 0x00, 0x18, 0x91, 0xf0, 0x0f, 0x00, 0x00, + 0x08, 0x88, 0x80, 0x31, 0xc0, 0x00, 0x08, 0xc8, 0x87, 0xc0, 0x70, 0x00, + 0x08, 0x48, 0x88, 0x00, 0x1c, 0x00, 0x08, 0x48, 0xf0, 0x0f, 0xfe, 0x00, + 0x08, 0x4c, 0x70, 0x1c, 0x03, 0x80, 0x08, 0x44, 0x53, 0xe0, 0x00, 0xc0, + 0x08, 0x66, 0x7e, 0x00, 0x00, 0x60, 0x08, 0x22, 0x2c, 0x03, 0xff, 0xe0, + 0x0c, 0x32, 0x26, 0x3e, 0x00, 0x30, 0x04, 0x12, 0x33, 0x40, 0x00, 0x10, + 0x04, 0x12, 0x19, 0xc0, 0x00, 0x10, 0x04, 0x11, 0x10, 0xff, 0xe0, 0x10, + 0x04, 0x11, 0x19, 0x24, 0x3f, 0xf0, 0x04, 0x19, 0x98, 0x06, 0x00, 0x10, + 0x06, 0x09, 0x8d, 0x2a, 0x00, 0x30, 0x02, 0x08, 0xa8, 0x42, 0x00, 0x30, + 0x02, 0x09, 0x8a, 0x03, 0x00, 0x70, 0x02, 0x01, 0x0c, 0x85, 0x00, 0xd0, + 0x02, 0x01, 0x86, 0x21, 0x81, 0x90, 0x02, 0x00, 0xff, 0xc0, 0x87, 0x10, + 0x02, 0x07, 0xd0, 0x72, 0xdc, 0x30, 0x02, 0x3c, 0x5f, 0x1c, 0x70, 0x20, + 0x02, 0xe0, 0x59, 0xc7, 0x44, 0x20, 0x03, 0x80, 0x70, 0x71, 0xc0, 0x60, + 0x02, 0x38, 0x20, 0x1e, 0x40, 0x40, 0x02, 0xe8, 0x20, 0x03, 0xc0, 0x40, + 0x03, 0x8c, 0x20, 0x00, 0x78, 0xc0, 0x03, 0x04, 0x20, 0x30, 0x0e, 0x80, + 0x06, 0x74, 0x20, 0x3c, 0x03, 0x80, 0x06, 0xd6, 0x30, 0x24, 0x01, 0x00, + 0x03, 0x92, 0x10, 0x26, 0x00, 0x80, 0x01, 0x1a, 0x10, 0x32, 0x00, 0xc0, + 0x01, 0x0a, 0x10, 0x12, 0x00, 0x60}; +static const uint8_t bmp_re2_mask[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x11, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xbc, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xbc, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xde, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0xde, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd0, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0xcd, 0xbe, 0x00, 0x00, 0x00, 0x0e, 0x4d, 0xbf, 0xf0, 0x00, 0x00, + 0x0f, 0x4e, 0xa0, 0x00, 0x00, 0x00, 0x07, 0x6e, 0x0f, 0xf0, 0x00, 0x00, + 0x07, 0x77, 0x7f, 0xce, 0x00, 0x00, 0x07, 0x37, 0x78, 0x3f, 0x80, 0x00, + 0x07, 0xb7, 0x77, 0xff, 0xe0, 0x00, 0x07, 0xb7, 0x0f, 0xf0, 0x00, 0x00, + 0x07, 0xb3, 0x8f, 0xe3, 0xfc, 0x00, 0x07, 0xbb, 0xac, 0x1f, 0xff, 0x00, + 0x07, 0x99, 0x81, 0xff, 0xff, 0x80, 0x07, 0xdd, 0xd3, 0xfc, 0x00, 0x00, + 0x03, 0xcd, 0xd9, 0xc1, 0xff, 0xc0, 0x03, 0xed, 0xcc, 0xbf, 0xff, 0xe0, + 0x03, 0xed, 0xe6, 0x3f, 0xff, 0xe0, 0x03, 0xee, 0xef, 0x00, 0x1f, 0xe0, + 0x03, 0xee, 0xe6, 0xdb, 0xc0, 0x00, 0x03, 0xe6, 0x67, 0xf9, 0xff, 0xe0, + 0x01, 0xf6, 0x72, 0xd5, 0xff, 0xc0, 0x01, 0xf7, 0x57, 0xbd, 0xff, 0xc0, + 0x01, 0xf6, 0x75, 0xfc, 0xff, 0x80, 0x01, 0xfe, 0xf3, 0x7a, 0xff, 0x20, + 0x01, 0xfe, 0x79, 0xde, 0x7e, 0x60, 0x01, 0xff, 0x00, 0x3f, 0x78, 0xe0, + 0x01, 0xf8, 0x2f, 0x8d, 0x23, 0xc0, 0x01, 0xc3, 0xa0, 0xe3, 0x8f, 0xc0, + 0x01, 0x1f, 0xa6, 0x38, 0xbb, 0xc0, 0x00, 0x7f, 0x8f, 0x8e, 0x3f, 0x80, + 0x01, 0xc7, 0xdf, 0xe1, 0xbf, 0x80, 0x01, 0x17, 0xdf, 0xfc, 0x3f, 0x80, + 0x00, 0x73, 0xdf, 0xff, 0x87, 0x00, 0x00, 0xfb, 0xdf, 0xcf, 0xf1, 0x00, + 0x01, 0x8b, 0xdf, 0xc3, 0xfc, 0x00, 0x01, 0x29, 0xcf, 0xdb, 0xfe, 0x00, + 0x00, 0x6d, 0xef, 0xd9, 0xff, 0x00, 0x00, 0xe5, 0xef, 0xcd, 0xff, 0x00, + 0x00, 0xf5, 0xef, 0xed, 0xff, 0x80}; #define BMP_FIRE_WIDTH 24 #define BMP_FIRE_HEIGHT 20 @@ -229,39 +359,26 @@ static const uint8_t bmp_fireball_mask[] = { 0xfc, 0x7f, 0xfd, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0x3f, 0xfe, 0x17, 0xf8, 0x07, 0xf4, 0x01, 0xe0}; -#define BMP_DOOR_WIDTH 32 -#define BMP_DOOR_HEIGHT 32 -static const uint8_t bmp_door_bits[] = { - 0xff, 0xff, 0xff, 0xff, 0xb2, 0xbd, 0xcd, 0x5b, 0x9a, 0xf4, 0x6d, 0x71, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xfd, - 0x3f, 0x00, 0xfe, 0xfc, 0x3e, 0x00, 0xc6, 0xfc, 0xbc, 0xaa, 0xfe, 0xbd, - 0x39, 0x54, 0xc6, 0xbc, 0x32, 0x8e, 0xfe, 0xac, 0xb5, 0xfe, 0xc6, 0xad, - 0x3f, 0xe0, 0xfe, 0xac, 0x31, 0xe0, 0xc6, 0xac, 0xb3, 0xf4, 0xfe, 0xad, - 0x3f, 0xe8, 0xc6, 0xac, 0x3c, 0xf4, 0xd6, 0xac, 0xb8, 0xff, 0xfe, 0xad, - 0x34, 0xc7, 0xfe, 0xfc, 0x38, 0xd6, 0x0e, 0x0c, 0xb0, 0xd6, 0x4e, 0x0d, - 0x3f, 0xd6, 0xaf, 0x5c, 0x30, 0x47, 0xff, 0xac, 0xb7, 0x57, 0xff, 0xfd, - 0x3f, 0xc6, 0x0e, 0x0c, 0x35, 0x56, 0x40, 0x4c, 0xb5, 0x46, 0xaa, 0xad, - 0x35, 0x56, 0x55, 0x4c, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x1f, 0xf8, 0x0d, - 0xd9, 0x30, 0x0c, 0x9b, 0xff, 0xe0, 0x07, 0xff}; - #define BMP_ITEMS_WIDTH 16 #define BMP_ITEMS_HEIGHT 16 #define BMP_ITEMS_COUNT 2 static const uint8_t bmp_items_bits[] = { 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0x77, 0xee, 0x3f, 0xfc, 0x5f, 0xfa, 0x2f, 0xf6, 0x53, 0xcc, 0x3e, 0x7e, 0x5e, 0x7c, - 0x38, 0x1e, 0x58, 0x1c, 0x3e, 0x7e, 0x5e, 0x7e, 0x2e, 0xfc, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, - 0x17, 0xfc, 0x22, 0x6c, 0x36, 0x44, 0x3f, 0xfc, 0x1f, 0xfc, 0x2b, - 0xfc, 0x05, 0x54, 0x02, 0xa8, 0x00, 0x00, 0x00, 0x00}; + 0x38, 0x1e, 0x58, 0x1c, 0x3e, 0x7e, 0x5e, 0x7e, 0x2f, 0xfc, 0x00, + 0x00, 0x1e, 0xf0, 0x00, 0x00, 0x0c, 0x60, 0x2d, 0x6c, 0x00, 0x00, + 0xff, 0xff, 0x7f, 0xf6, 0xf0, 0x86, 0x70, 0xb7, 0xf0, 0x86, 0x7f, + 0xf7, 0xff, 0xfe, 0x10, 0x30, 0x00, 0x00, 0x00, 0x00}; static const uint8_t bmp_items_mask[] = { 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, - 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, - 0x1f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, - 0xfc, 0x07, 0xfc, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00}; + 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc, 0x3f, + 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}; +// Gradient for lighting. +// Note: Width and height are in bytes #define GRADIENT_WIDTH 2 #define GRADIENT_HEIGHT 8 #define GRADIENT_COUNT 8 diff --git a/src/game.c b/src/game.c index 548d4a3..e130578 100644 --- a/src/game.c +++ b/src/game.c @@ -26,8 +26,11 @@ typedef enum { SCENE_INTRO, - SCENE_LEVEL1, - /* Add more levels here */ + SCENE_SCORE, + SCENE_MUSIC, + SCENE_DIFFICULTY, + SCENE_LEVEL, + SCENE_STORY } GameScene; /* Function prototypes ------------------------------------------------------ */ @@ -60,7 +63,7 @@ static void game_fire_shootgun(void); static Coords game_translate_into_view(Coords *pos); static void game_render_map(const uint8_t level[], float view_height); static void game_render_entities(float view_height); -static void game_render_gun(uint8_t gun_pos, float jogging); +void game_render_gun(uint8_t gun_pos, float amount_jogging, bool gun_fired, uint8_t r1); static void game_render_hud(void); /* Scenes */ @@ -68,32 +71,60 @@ static void game_jump_to_scene(GameScene scene); static void game_run_intro_scene(void); static void game_run_level_scene(void); +void updateHud(void); // temporary + /* Global variables --------------------------------------------------------- */ -/* Entities */ +static bool exit_scene = false; +static bool invert_screen = false; +static uint8_t flash_screen = 0; +static uint8_t z = 6; +static bool coll = 0; +static uint8_t jump = 0; +static uint8_t jump_height = 0; +static uint8_t vel = 1; +static uint8_t difficulty = 1; +static uint8_t noclip = 0; +static bool m = true; +static uint8_t rc1 = 0; +static int16_t a = 0; +static uint8_t enemyCount2 = 0; +static uint8_t enemyGoal2 = 8; +// game +// player and entities static Player player; static Entity entity[MAX_ENTITIES]; -static uint8_t num_entities; static StaticEntity static_entity[MAX_STATIC_ENTITIES]; -static uint8_t num_static_entities; - -/* Graphics */ -static bool flash_screen; -static uint8_t fade_screen; +static uint8_t num_entities = 0; +static uint8_t num_static_entities = 0; +static uint8_t x = 0; +static uint8_t enemyCount = 0; +static uint8_t del = 0; +static bool levelID = false; +static uint8_t enemyGoal = 20; +static bool fade_e = true; +static bool debug = false; +static uint8_t r = 0; +static bool reload1 = false; +static int16_t score; +static uint8_t k; +static int8_t mid = 1; +static bool bss = false; +static bool mc = false; +// init +static bool gun_fired = false; +static bool walkSoundToggle = false; +static uint8_t gun_pos = 0; +static float rot_speed; +static float old_dir_x; +static float old_plane_x; +static float view_height; +static float jogging; +static uint8_t fade = GRADIENT_COUNT - 1; -/* Sound effects */ -static bool walk_sound_toggle; - -/* Scene */ static void (*game_run_scene)(void); -/* Function definitions ----------------------------------------------------- */ - -/** - * @brief GAME jump to another scene at the end of the current frame. - * - * @param scene Game scene - */ +// Jump to another scene void game_jump_to_scene(GameScene scene) { switch (scene) @@ -102,8 +133,8 @@ void game_jump_to_scene(GameScene scene) game_run_scene = game_run_intro_scene; break; - case SCENE_LEVEL1: - game_init_level_scene(level_1); + case SCENE_LEVEL: + game_init_level_scene(E1M1); game_run_scene = game_run_level_scene; break; @@ -113,25 +144,28 @@ void game_jump_to_scene(GameScene scene) } } -/** - * @brief GAME initialize level state. - * - * @param level Level byte map - */ +// Finds the player in the map void game_init_level_scene(const uint8_t level[]) { - // Initialize game entities - memset(entity, 0x00, sizeof(Entity) * MAX_ENTITIES); - memset(static_entity, 0x00, sizeof(StaticEntity) * MAX_STATIC_ENTITIES); - num_entities = 0; - num_static_entities = 0; - - // Initialize screen effects - flash_screen = false; - fade_screen = GRADIENT_COUNT - 1; - - // Initialize audio effects - walk_sound_toggle = false; + gun_fired = false; + walkSoundToggle = false; + gun_pos = 0; + rot_speed; + old_dir_x; + old_plane_x; + view_height; + jogging; + fade = GRADIENT_COUNT - 1; + + mc = false; + if (levelID == false) + { + game_init_level_scene(E1M1); + } + if (levelID == true) + { + game_init_level_scene(E1M2); + } // Initialize game scene callback game_run_scene = game_run_intro_scene; @@ -154,14 +188,6 @@ void game_init_level_scene(const uint8_t level[]) } } -/** - * @brief GAME get entity type from level byte map. - * - * @param level Level byte map - * @param x X coordinate - * @param y Y coordinate - * @return EntityType Entity type - */ EntityType game_get_level_entity(const uint8_t level[], uint8_t x, uint8_t y) { if ((x < 0) || (x >= LEVEL_WIDTH) || (y < 0) || (y >= LEVEL_HEIGHT)) @@ -174,12 +200,6 @@ EntityType game_get_level_entity(const uint8_t level[], uint8_t x, uint8_t y) return byte & 0x0f; } -/** - * @brief GAME check if an entity with given UID is already spawned. - * - * @param uid Entity UID number - * @return bool Entity is spawned - */ bool game_is_entity_spawned(EntityUID uid) { for (uint8_t i = 0; i < num_entities; i++) @@ -191,12 +211,6 @@ bool game_is_entity_spawned(EntityUID uid) return false; } -/** - * @brief GAME check if a static entity with given UID is already spawned. - * - * @param uid Entity UID number - * @return bool Static entity is spawned - */ bool game_is_static_entity_spawned(EntityUID uid) { for (uint8_t i = 0; i < num_static_entities; i++) @@ -208,13 +222,6 @@ bool game_is_static_entity_spawned(EntityUID uid) return false; } -/** - * @brief GAME spawn a new entity at a given location. - * - * @param type Entity type - * @param x X coordinate - * @param y Y coordinate - */ void game_spawn_entity(EntityType type, uint8_t x, uint8_t y) { // Limit the number of spawned entities @@ -242,12 +249,6 @@ void game_spawn_entity(EntityType type, uint8_t x, uint8_t y) } } -/** - * @brief GAME spawn a fireball at a given location. - * - * @param x X coordinate - * @param y Y coordinate - */ void game_spawn_fireball(float x, float y) { // Limit the number of spawned entities @@ -271,11 +272,6 @@ void game_spawn_fireball(float x, float y) num_entities++; } -/** - * @brief GAME remove an entity. - * - * @param uid Entity UID number - */ void game_remove_entity(EntityUID uid) { uint8_t i = 0; @@ -296,11 +292,33 @@ void game_remove_entity(EntityUID uid) } } -/** - * @brief GAME remove a static entity. - * - * @param uid Entity UID number - */ +void clearEntities() +{ + uint8_t i = num_entities; + bool found; + while (found == false) + { + i--; + if (entity[i].state != S_DEAD && entities_get_type(entity[i].uid) != E_ENEMY) + { + found = true; + } + } + i--; + while (entity[i].state != S_DEAD && entities_get_type(entity[i].uid) != E_ENEMY && found == true) + { + i--; + if (i == 0) + { + break; + } + } + if (i > 0 && entity[i].state == S_DEAD) + { + game_remove_entity(entity[i].uid); + } +} + void game_remove_static_entity(EntityUID uid) { uint8_t i = 0; @@ -321,16 +339,6 @@ void game_remove_static_entity(EntityUID uid) } } -/** - * @brief GAME detect collision between entities and level blocks. - * - * @param level Level byte map - * @param pos Position to be checked - * @param rel_x X relative direction - * @param rel_y Y relative direction - * @param only_walls Check only walls collisions - * @return EntityUID Entity UID number - */ EntityUID game_detect_collision(const uint8_t level[], Coords *pos, float rel_x, float rel_y, bool only_walls) { @@ -339,11 +347,32 @@ EntityUID game_detect_collision(const uint8_t level[], Coords *pos, float rel_x, uint8_t round_y = pos->y + rel_y; uint8_t block = game_get_level_entity(level, round_x, round_y); - if (block == E_WALL) + if (block == E_WALL & debug == false) { sound_play(hit_wall_snd, HIT_WALL_SND_LEN); return entities_get_uid(block, round_x, round_y); } + else if (block == E_DOOR && player.secret == false) + { + z = 8; + player.secret = true; + updateHud(); + sound_play(s_snd, S_SND_LEN); + } + else if (block == E_DOOR2 && player.secret2 == false) + { + z = 8; + player.secret2 = true; + updateHud(); + sound_play(s_snd, S_SND_LEN); + } + else if (block == E_DOOR3 && player.secret3 == false) + { + z = 8; + player.secret3 = true; + sound_play(s_snd, S_SND_LEN); + updateHud(); + } if (only_walls) return UID_NULL; @@ -375,16 +404,97 @@ EntityUID game_detect_collision(const uint8_t level[], Coords *pos, float rel_x, return UID_NULL; } -/** - * @brief GAME update position if possible, otherwise return collided uid. - * - * @param level Level byte map - * @param pos Position to be checked - * @param rel_x X relative direction - * @param rel_y Y relative direction - * @param only_walls Check only walls collisions - * @return EntityUID Entity UID number - */ +// Shoot +void game_fire_shootgun(void) +{ + if (player.keys != 0) + { + z = 3; + sound_play(shoot_snd, SHOOT_SND_LEN); + for (uint8_t i = 0; i < num_entities; i++) + { + // Shoot only ALIVE enemies + if (entities_get_type(entity[i].uid) != E_ENEMY || entity[i].state == S_DEAD || entity[i].state == S_HIDDEN) + { + continue; + } + Coords transform = game_translate_into_view(&(entity[i].pos)); + if (fabsf(transform.x) < 20 && transform.y > 0) + { + uint8_t damage = MIN(GUN_MAX_DAMAGE, GUN_MAX_DAMAGE / (fabsf(transform.x) * entity[i].distance) / 5); + if (jump == 1 || jump == 2) + { + damage = damage / 3; + } + if (difficulty == 1) + { + damage = damage * 1.5; + } + else if (difficulty == 2) + { + damage = damage; + } + else + { + damage = damage * 0.70; + } + if (damage > 0) + { + entity[i].health = MAX(0, entity[i].health - damage / difficulty); + entity[i].state = S_HIT; + entity[i].timer = 2; + } + } + } + } + else + { + z = 3; + sound_play(melee_snd, MELEE_SND_LEN); + for (uint8_t i = 0; i < num_entities; i++) + { + if (entity[i].distance <= ENEMY_MELEE_DIST) + { + // Shoot only ALIVE enemies + if (entities_get_type(entity[i].uid) != E_ENEMY || entity[i].state == S_DEAD || entity[i].state == S_HIDDEN) + { + continue; + } + Coords transform = game_translate_into_view(&(entity[i].pos)); + if (fabsf(transform.x) < 20 && transform.y > 0) + { + uint8_t damage = MIN(GUN_MAX_DAMAGE, GUN_MAX_DAMAGE / (fabsf(transform.x) * entity[i].distance) / 5); + if (jump == 1 || jump == 2) + { + damage = damage / 3; + } + if (difficulty == 1) + { + damage = damage + damage / 4.0; + } + else if (difficulty == 2) + { + damage = damage - damage * 0.1; + } + else + { + damage = damage * 0.60; + } + if (damage > 0) + { + entity[i].health = MAX(0, entity[i].health - damage / difficulty); + entity[i].state = S_HIT; + entity[i].timer = 2; + } + } + } + } + } + + updateHud(); +} + +// Update coords if possible. Return the collided uid, if any EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, float rel_y, bool only_walls) { @@ -401,82 +511,82 @@ EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, return (collide_x || collide_y || UID_NULL); } -/** - * @brief GAME player fire shootgun and compute damage. - * - */ -void game_fire_shootgun(void) -{ - sound_play(shoot_snd, SHOOT_SND_LEN); - - for (uint8_t i = 0; i < num_entities; i++) - { - // Shoot only ALIVE enemies - if ((entities_get_type(entity[i].uid) != E_ENEMY) || - (entity[i].state == S_DEAD) || - (entity[i].state == S_HIDDEN)) - continue; - - Coords transform = game_translate_into_view(&(entity[i].pos)); - if ((fabsf(transform.x) < 20.0f) && (transform.y > 0.0f)) - { - uint8_t damage = MIN( - GUN_MAX_DAMAGE, - GUN_MAX_DAMAGE / - (fabsf(transform.x) * entity[i].distance) / 5.0f); - if (damage > 0) - { - entity[i].health = MAX(0, entity[i].health - damage); - entity[i].state = S_HIT; - entity[i].timer = 4; - } - } - } -} - -/** - * @brief GAME execute entities AI logic. - * - * @param level Level byte map - */ void game_update_entities(const uint8_t level[]) { + x = rand() % 4 + 1; uint8_t i = 0; while (i < num_entities) { - // Update distance - entity[i].distance = coords_get_distance( - &(player.pos), &(entity[i].pos)); + // update distance + entity[i].distance = coords_get_distance(&(player.pos), &(entity[i].pos)); // Run the timer. Works with actual frames. + // Todo: use delta_time here. But needs float type and more memory if (entity[i].timer > 0) entity[i].timer--; - // Too far away. put it in doze mode + // too far away. put it in doze mode if (entity[i].distance > MAX_ENTITY_DISTANCE) { game_remove_entity(entity[i].uid); + // don't increase 'i', since current one has been removed continue; } - - // Bypass render if hidden + // bypass render if hidden if (entity[i].state == S_HIDDEN) { i++; continue; } - EntityType type = entities_get_type(entity[i].uid); + uint8_t type = entities_get_type(entity[i].uid); + switch (type) { case E_ENEMY: { + // Enemy "IA" if (entity[i].health == 0) { + if (entity[i].a == false) + { + if (x == 1) + { + game_spawn_entity(E_KEY, entity[i].pos.x, entity[i].pos.y); + entity[i].a = true; + enemyCount++; + z = 7; + } + else if (x == 2) + { + game_spawn_entity(E_KEY, entity[i].pos.x, entity[i].pos.y); + entity[i].a = true; + enemyCount++; + z = 7; + } + else if (x == 3) + { + game_spawn_entity(E_MEDKIT, entity[i].pos.x, entity[i].pos.y); + entity[i].a = true; + enemyCount++; + z = 7; + } + else + { + entity[i].a = true; + enemyCount++; + z = 7; + } + if (bss == true) + enemyCount2++; + } + if (bss == true && enemyCount > 2) + { + } if (entity[i].state != S_DEAD) { - entity[i].state = S_DEAD; // Entity is dead + entity[i].state = S_DEAD; entity[i].timer = 6; } } @@ -484,48 +594,48 @@ void game_update_entities(const uint8_t level[]) { if (entity[i].timer == 0) { - entity[i].state = S_ALERT; // Back to alert state - entity[i].timer = 40; // Delay next fireball thrown + // Back to alert state + entity[i].state = S_ALERT; + entity[i].timer = 40; // delay next fireball thrown } } else if (entity[i].state == S_FIRING) { if (entity[i].timer == 0) { - entity[i].state = S_ALERT; // Back to alert state - entity[i].timer = 40; // Delay next fireball thrown + // Back to alert state + entity[i].state = S_ALERT; + entity[i].timer = 40; + // delay next fireball throwm } } else { - if ((entity[i].distance > ENEMY_MELEE_DIST) && - (entity[i].distance < MAX_ENEMY_VIEW)) + // ALERT STATE + if (entity[i].distance > ENEMY_MELEE_DIST && entity[i].distance < MAX_ENEMY_VIEW) { if (entity[i].state != S_ALERT) { - entity[i].state = S_ALERT; // Back to alert state - entity[i].timer = 20; // used to throw fireballs + entity[i].state = S_ALERT; + entity[i].timer = 20; // used to throw fireballs } else { if (entity[i].timer == 0) { // Throw a fireball - game_spawn_fireball( - entity[i].pos.x, entity[i].pos.y); + game_spawn_fireball(entity[i].pos.x, entity[i].pos.y); entity[i].state = S_FIRING; entity[i].timer = 6; } else { - // Move towards to the player + // move towards to the player. game_update_position( level, &(entity[i].pos), - SIGN(player.pos.x, entity[i].pos.x) * - ENEMY_SPEED * delta_time, - SIGN(player.pos.y, entity[i].pos.y) * - ENEMY_SPEED * delta_time, + SIGN(player.pos.x, entity[i].pos.x) * ENEMY_SPEED * delta_time, + SIGN(player.pos.y, entity[i].pos.y) * ENEMY_SPEED * delta_time, true); } } @@ -540,15 +650,19 @@ void game_update_entities(const uint8_t level[]) } else if (entity[i].timer == 0) { - // Melee attack - player.health = - MAX(0, player.health - ENEMY_MELEE_DAMAGE); + // Melee attack; + if (debug == false) + { + player.health = MAX(0, player.health - ENEMY_MELEE_DAMAGE * difficulty); + } entity[i].timer = 14; - flash_screen = true; + flash_screen = 1; + updateHud(); } } else { + // stand entity[i].state = S_STAND; } } @@ -560,29 +674,30 @@ void game_update_entities(const uint8_t level[]) if (entity[i].distance < FIREBALL_COLLIDER_DIST) { // Hit the player and disappear - player.health = - MAX(0, player.health - ENEMY_FIREBALL_DAMAGE); - flash_screen = true; + if (debug == false) + { + player.health = MAX(0, player.health - ENEMY_FIREBALL_DAMAGE * difficulty); + } + flash_screen = 1; + updateHud(); game_remove_entity(entity[i].uid); - continue; + continue; // continue in the loop } else { - // Move, only collide with walls. + // Move. Only collide with walls. // Note: using health to store the angle of the movement EntityUID collided = game_update_position( level, &(entity[i].pos), - cosf((float)entity[i].health / FIREBALL_ANGLES * PI) * - FIREBALL_SPEED, - sinf((float)entity[i].health / FIREBALL_ANGLES * PI) * - FIREBALL_SPEED, + cosf((float)entity[i].health / FIREBALL_ANGLES * PI) * FIREBALL_SPEED, + sinf((float)entity[i].health / FIREBALL_ANGLES * PI) * FIREBALL_SPEED, true); if (collided) { game_remove_entity(entity[i].uid); - continue; + continue; // continue in the entity check loop } } break; @@ -590,26 +705,61 @@ void game_update_entities(const uint8_t level[]) case E_MEDKIT: { - if (entity[i].distance < ITEM_COLLIDER_DIST) + if (entity[i].distance < ITEM_COLLIDER_DIST && player.health != 100 && jump_height < 14) { - // Pickup + // pickup sound_play(medkit_snd, MEDKIT_SND_LEN); entity[i].state = S_HIDDEN; - player.health = MIN(100, player.health + 50); - flash_screen = true; + if (difficulty == 1) + { + player.health = MIN(100, player.health + 65); + } + else if (difficulty == 2) + { + player.health = MIN(100, player.health + 50); + } + else + { + player.health = MIN(100, player.health + 25); + } + updateHud(); + flash_screen = 1; + z = 3; + updateHud(); + z = 2; + updateHud(); } break; } case E_KEY: { - if (entity[i].distance < ITEM_COLLIDER_DIST) + if (entity[i].distance < ITEM_COLLIDER_DIST && player.keys < 240 && jump_height < 14) { - // Pickup + // pickup sound_play(get_key_snd, GET_KEY_SND_LEN); entity[i].state = S_HIDDEN; - player.keys++; - flash_screen = true; + if (difficulty == 1) + { + player.keys = player.keys + 13; + } + else if (difficulty == 2) + { + player.keys = player.keys + 10; + } + else + { + player.keys = player.keys + 9; + } + if (player.keys > 240) + { + player.keys = 240; + } + updateHud(); + z = 3; + updateHud(); + z = 1; + updateHud(); } break; } @@ -619,14 +769,8 @@ void game_update_entities(const uint8_t level[]) } } -/** - * @brief GAME render map with raycasting technique. - * NOTE: Based on https://lodev.org/cgtutor/raycasting.html - * - * @param level Level byte map - * @param view_height View height of the camera - */ -void game_render_map(const uint8_t level[], float view_height) +// The map raycaster. Based on https://lodev.org/cgtutor/raycasting.html +void renderMap(const uint8_t level[], float view_height) { EntityUID last_uid; @@ -670,37 +814,41 @@ void game_render_map(const uint8_t level[], float view_height) // Wall detection uint8_t depth = 0; - bool hit = false; + bool hit = 0; bool side; - while (!hit && (depth < MAX_RENDER_DEPTH)) + bool coll = 0; + while (!hit && depth < MAX_RENDER_DEPTH) { if (side_x < side_y) { side_x += delta_x; map_x += step_x; - side = false; + side = 0; } else { side_y += delta_y; map_y += step_y; - side = true; + side = 1; } uint8_t block = game_get_level_entity(level, map_x, map_y); - if (block == E_WALL) - hit = true; + if (block == E_WALL || block == E_DOOR || block == E_DOOR2 || block == E_DOOR3 || block == E_COLL) + { + hit = 1; + if (block == E_COLL) + coll = 1; + } else { // Spawning entities here, as soon they are visible for the // player. Not the best place, but would be a very performance // cost scan for them in another loop - if ((block == E_ENEMY) || (block & 0b00001000)) + if (block == E_ENEMY || (block & 0b00001000) /* all collectable items */) { // Check that it's close to the player - if (coords_get_distance(&(player.pos), &map_coords) < - MAX_ENTITY_DISTANCE) + if (coords_get_distance(&(player.pos), &map_coords) < MAX_ENTITY_DISTANCE) { EntityUID uid = entities_get_uid(block, map_x, map_y); if (last_uid != uid && !game_is_entity_spawned(uid)) @@ -718,34 +866,43 @@ void game_render_map(const uint8_t level[], float view_height) if (hit) { float distance; - if (!side) - distance = - MAX(1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); + + if (side == 0) + { + distance = MAX(1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); + } else - distance = - MAX(1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); + { + distance = MAX(1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); + } // store zbuffer value for the column - zbuffer[x / Z_RES_DIVIDER] = - MIN(distance * DISTANCE_MULTIPLIER, 0xff); + zbuffer[x / Z_RES_DIVIDER] = MIN(distance * DISTANCE_MULTIPLIER, 255); // rendered line height - uint8_t line_height = RENDER_HEIGHT / distance; + uint8_t line_height = RENDER_HEIGHT / distance - 1; - display_draw_vline( - x, - view_height / distance - line_height / 2 + RENDER_HEIGHT / 2, - view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, - GRADIENT_COUNT - (side * 2) - - (distance / MAX_RENDER_DEPTH * GRADIENT_COUNT)); + if (coll == true) + { + display_draw_vline( + x, + view_height / distance - line_height / 2 + RENDER_HEIGHT / 2 - 17, + view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, + GRADIENT_COUNT - (int)(distance / MAX_RENDER_DEPTH * GRADIENT_COUNT) - side * 2); + } + else + { + display_draw_vline( + x, + view_height / distance - line_height / 2 + RENDER_HEIGHT / 2, + view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, + GRADIENT_COUNT - (int)(distance / MAX_RENDER_DEPTH * GRADIENT_COUNT) - side * 2); + } } } } -/** - * @brief GAME sort entities from far to close. - * - */ +// Sort entities from far to close void game_sort_entities(void) { uint8_t gap = num_entities; @@ -772,12 +929,6 @@ void game_sort_entities(void) } } -/** - * @brief GAME translate 2D map coordinates into camera coordinates. - * - * @param pos 2D map coordinates - * @return Coords Camera coordinates - */ Coords game_translate_into_view(Coords *pos) { // Translate sprite position to relative to camera @@ -795,11 +946,6 @@ Coords game_translate_into_view(Coords *pos) return (Coords){transform_x, transform_y}; } -/** - * @brief GAME render entities sprites. - * - * @param view_height View height of the camera - */ void game_render_entities(float view_height) { game_sort_entities(); @@ -901,234 +1047,919 @@ void game_render_entities(float view_height) } } -/** - * @brief GAME render player gun sprite. - * - * @param gun_pos Gun cyclic position - * @param jogging Player jogging speed - */ -void game_render_gun(uint8_t gun_pos, float jogging) +void game_render_gun(uint8_t gun_pos, float amount_jogging, bool gun_fired, uint8_t r1) { // jogging - uint8_t x = 48 + sinf(platform_millis() * JOGGING_SPEED) * 10 * jogging; - uint8_t y = RENDER_HEIGHT - gun_pos + - fabsf(cosf(platform_millis() * JOGGING_SPEED)) * 8 * jogging; - - // Gun fire + char x = 48 + sinf((float)platform_millis() * JOGGING_SPEED) * 10 * amount_jogging - 9; + char y = RENDER_HEIGHT - gun_pos + fabsf(cosf((float)platform_millis() * JOGGING_SPEED)) * 8 * amount_jogging - 3; + uint8_t clip_height = MAX(0, MIN(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); if (gun_pos > GUN_SHOT_POS - 2) - display_draw_bitmap(x + 6, y - 11, bmp_fire_bits, BMP_FIRE_WIDTH, - BMP_FIRE_HEIGHT, true); + { + // Gun fire + if (player.keys > 0 && gun_fired == true) + { + display_draw_bitmap(x + 14, y - 11, bmp_fire_bits, BMP_FIRE_WIDTH, BMP_FIRE_HEIGHT, 1); + } + } + if (r1 == 1) + { + clip_height = MAX(0, MIN(y + BMP_RE1_HEIGHT, RENDER_HEIGHT) - y + 22); + display_draw_bitmap(x - 10, y - 22, bmp_re1_mask, BMP_RE1_WIDTH, clip_height, 0); + display_draw_bitmap(x - 10, y - 22, bmp_re1_bits, BMP_RE1_WIDTH, clip_height, 1); + } + else if (r1 == 2) + { + clip_height = MAX(0, MIN(y + BMP_RE2_HEIGHT, RENDER_HEIGHT) - y + 22); + display_draw_bitmap(x - 10, y - 22, bmp_re2_mask, BMP_RE2_WIDTH, clip_height, 0); + display_draw_bitmap(x - 10, y - 22, bmp_re2_bits, BMP_RE2_WIDTH, clip_height, 1); + } + else if (r1 == 0) + { + display_draw_bitmap(x, y, bmp_gun_mask, BMP_GUN_WIDTH, clip_height, 0); + display_draw_bitmap(x, y, bmp_gun_bits, BMP_GUN_WIDTH, clip_height, 1); + } + else + { + } - // Don't draw over the hud - uint8_t clip_height = MAX(0, MIN(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); + // Don't draw over the hud! + + // Draw the gun (black mask + actual sprite). +} + +// Only needed first time +void game_render_hud() +{ + if (debug == false) + { + display_draw_text(2, 58, "{}", false); // Health symbol + display_draw_text(105, 58, "[]", false); // Keys symbol + updateHud(); + } + else + { + display_draw_text(2, 58, "X", false); // Health symbol + display_draw_text(105, 58, "Y", false); // Keys symbol + updateHud(); + } +} + +// Render values for the HUD +void updateHud() +{ + display_draw_rect(12, 58, 100, 6, false); + display_draw_rect(50, 58, 15, 6, false); + display_draw_rect(58, 58, 70, 6, false); + + if (z == 1) + { + display_draw_text(31, 58, "FOUND ", false); + display_draw_text(65, 58, " SHELLS", false); + if (difficulty == 1) + { + display_draw_text(57, 58, "13", false); + } + else if (difficulty == 2) + { + display_draw_text(57, 58, "10", false); + } + else + { + display_draw_text(60, 58, "9", false); + } + } + + else if (z == 2) + { + display_draw_text(31, 58, "FOUND A MEDKIT", false); + } + else if (z == 3) + { + display_draw_rect(12, 58, 100, 6, false); + display_draw_rect(1, 58, 100, 6, false); + display_draw_rect(50, 58, 15, 6, false); + display_draw_rect(58, 58, 70, 6, false); + } + else if (z == 4) + { + display_draw_text(38, 58, "GAME OVER", false); + } + else if (z == 5) + { + display_draw_text(44, 58, "YOU WIN", false); + } + else if (z == 6) + { + display_draw_text(33, 58, "GOAL-20 KILLS", false); + } + else if (z == 7) + { + if (levelID == true && bss == true) + { + display_draw_text(37, 58, enemyCount2, false); + display_draw_text(52, 58, "OUT OF ", false); + display_draw_text(87, 58, enemyGoal2, false); + } + else if (levelID == false) + { + display_draw_text(37, 58, enemyCount, false); + display_draw_text(52, 58, "OUT OF ", false); + display_draw_text(87, 58, enemyGoal, false); + } + } + else if (z == 8) + { + display_draw_text(35, 58, "SECRET FOUND", false); + } + else if (z == 9) + { + display_draw_text(31, 58, "GOAL-FIND EXIT", false); + } + else if (z == 10) + { + display_draw_text(31, 58, "DEBUG MODE OFF", false); + } + else + { + display_draw_text(32, 58, "DEBUG MODE ON", false); + } + + if (debug == false) + { + display_draw_rect(1, 58, 8, 6, false); + display_draw_text(2, 58, "{}", false); + display_draw_text(103, 58, "[]", false); + display_draw_text(12, 58, player.health, false); + display_draw_text(113, 58, player.keys, false); + } + else + { + display_draw_rect(1, 58, 8, 6, false); + display_draw_text(2, 58, "X", false); + display_draw_text(105, 58, "Y", false); + char posx[10]; + char posy[10]; + sprintf(posx, "%f", player.pos.x); + sprintf(posy, "%f", player.pos.y); + display_draw_text(12, 58, posx, false); + display_draw_text(113, 58, posy, false); + } +} - // Draw the gun (black mask + actual sprite) - display_draw_bitmap(x, y, bmp_gun_mask, BMP_GUN_WIDTH, clip_height, false); - display_draw_bitmap(x, y, bmp_gun_bits, BMP_GUN_WIDTH, clip_height, true); +// Debug stats +void renderStats() +{ } -/** - * @brief GAME render heads-up display (HUD). - * - */ -void game_render_hud(void) +void softReset() { - // Clear HUD - display_draw_rect(0, RENDER_HEIGHT, SCREEN_WIDTH, HUD_HEIGHT, false); - - // Draw HUD symbols - display_draw_text(2, RENDER_HEIGHT, "{}", false); - display_draw_text(40, RENDER_HEIGHT, "[]", false); - - // Update stats - display_draw_int(12, RENDER_HEIGHT, player.health); - display_draw_int(50, RENDER_HEIGHT, player.keys); - display_draw_int(114, RENDER_HEIGHT, (uint8_t)(display_get_fps())); - display_draw_int(82, RENDER_HEIGHT, num_entities); + asm volatile("jmp 0"); +} + +void game_run_story_scene() +{ + display_draw_rect(1, 1, 127, 63, false); + + if (mid == 1) + { + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, "YEAR 2027. HUMANS REACHED", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, "OTHER PLANETS, BUT WE ARE", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, "NOT ALONE, THERE IS ALSO", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, "HOSTILE ALIENS HERE. YOU", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, "ARE AN UNKNOWN MARINE,", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, "WHO FIGHT IN OLD LAB FOR", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, "REMNANTS OF EARTH. RESIST", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, "ALIENS TO ESCAPE.", false); + } + else if (mid == 2) + { + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, "AFTER KILLING BUNCH OF ", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, "ALIENS, LIGHTS TURNED OFF", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, "AND THE FLOOR COLLAPSED", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, "UNDER YOUR FEET AND YOU ", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, "FELL INTO THE UTILITY", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, "ROOMS. YOU HAVE NO CHOICE", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, "BUT TO START LOOKING FOR ", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, "EXIT, WHILE FIGHT ALIENS.", false); + + levelID = true; + } + else + { + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, "AFTER HARD FIGHT YOU WENT", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, "TO EXIT. AND AS SOON AS", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, "YOU STEP OUT, AN ALIEN", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, "ATTACKS YOU FROM BEHIND", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, "AND KILLS YOU. YOU DIDNT", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, "EXPECT THIS. YOUR FIGHT", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, "CAN NOT END LIKE THIS...", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, "THE END (MAYBE...)", false); + } + display_draw_text(SCREEN_WIDTH / 2.1 - 24, SCREEN_HEIGHT * .01, "THE STORY", false); + display_draw_text(SCREEN_WIDTH / 2 - 27, SCREEN_HEIGHT * .91, "PRESS FIRE", false); + + display_update(); + + if (input_fire()) + { + fade_e = true; + if (mid < 3) + { + game_jump_to_scene(SCENE_LEVEL); + } + else + { + game_jump_to_scene(SCENE_SCORE); + } + } +} + +void game_run_score_scene() +{ + + score = player.keys / 2; + score += player.health; + score *= 43; + score *= difficulty; + if (player.secret != 0) + { + score += 69; + } + if (player.secret2 += 0) + { + score += 69; + } + if (player.secret3 += 0) + { + score += 69; + } + score += k; + + display_draw_rect(1, 1, 127, 63, false); + + display_draw_bitmap( + (SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2 - 27, + (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 6, + bmp_logo_bits, + BMP_LOGO_WIDTH, + BMP_LOGO_HEIGHT, + 1); + display_draw_text(SCREEN_WIDTH / 2.36 - 52, SCREEN_HEIGHT * .79, "NANO BRUTALITY", false); + display_draw_text(SCREEN_WIDTH / 0.99 - 45, SCREEN_HEIGHT * .2, "YOU WIN", false); + if (player.cheats == false) + { + display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .4, "SCENE_SCORE", false); + if (a < score) + { + a += 155; + display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a, false); + sound_play(walk1_snd, WALK1_SND_LEN); + } + else if (a > score) + { + a = score; + display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a, false); + m = false; + music = 1; + sound_play(shot_snd, SHOT_SND_LEN); + } + else + { + display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a, false); + display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, "PRESS FIRE", false); + if (input_fire()) + { + display_draw_rect(1, 1, 127, 63, false); + display_update(); + music = 99; + platform_delay(1000); + fade_e = true; + softReset(); + } + } + } + else if (player.cheats == true) + { + display_draw_text(SCREEN_WIDTH / 0.99 - 49, SCREEN_HEIGHT * .4, "NO SCENE_SCORE", false); + display_draw_text(SCREEN_WIDTH / 0.99 - 37, SCREEN_HEIGHT * .5, "FOR", false); + display_draw_text(SCREEN_WIDTH / 0.99 - 49, SCREEN_HEIGHT * .6, "CHEATERS", false); + display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, "PRESS FIRE", false); + if (input_fire()) + { + display_draw_rect(1, 1, 127, 63, false); + display_update(); + music = 99; + platform_delay(1000); + fade_e = true; + softReset(); + } + if (mc == false) + { + m = false; + music = 1; + sound_play(mus_s1_snd, MUS_S1_SND_LEN); + platform_delay(100); + mc = true; + } + } + display_update(); + + fade_e = false; + game_jump_to_scene(SCENE_SCORE); } -/** - * @brief GAME run intro scene. - * - */ -void game_run_intro_scene(void) +// Intro screen +void game_run_intro_scene() { + music = 1; + display_draw_bitmap( (SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, - (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, + (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 6, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, - true); + 1); - display_draw_text( - SCREEN_WIDTH / 2 - 25, - SCREEN_HEIGHT * 0.8f, - "PRESS FIRE", - true); + platform_delay(100); + display_draw_text(SCREEN_WIDTH / 2.36 - 25, SCREEN_HEIGHT * .79, "NANO BRUTALITY", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 25, SCREEN_HEIGHT * .3, "PRESS", false); + display_draw_text(SCREEN_WIDTH / 0.99 - 25, SCREEN_HEIGHT * .3, "FIRE", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 25, SCREEN_HEIGHT * .91, "V 1.5", false); + display_update(); + sound_play(mus_s1_snd, MUS_S1_SND_LEN); if (input_fire()) - game_jump_to_scene(SCENE_LEVEL1); + game_jump_to_scene(SCENE_DIFFICULTY); + + // wait for fire +} + +void game_run_difficulty_scene() +{ + platform_delay(200); + + display_draw_rect(1, 1, 127, 63, false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .05, "CHOOSE SKILL LEVEL", false); + display_draw_text(SCREEN_WIDTH / 2.75 - 25, SCREEN_HEIGHT * .3, "I", false); + display_draw_text(SCREEN_WIDTH / 2.4 - 25, SCREEN_HEIGHT * .3, "M TOO YOUNG TO DIE.", false); + display_draw_text(SCREEN_WIDTH / 2.6 - 25, SCREEN_HEIGHT * .26, ",", false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .43, "HURT ME PLENTY.", false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .56, "NIGHTMARE.", false); + display_draw_text(SCREEN_WIDTH / 3.32 - 25, SCREEN_HEIGHT * .77, "NOTE - BUTTONS OUTSIDE", false); + display_draw_text(SCREEN_WIDTH / 4.1 - 25, SCREEN_HEIGHT * .9, "GAMEPLAY WORK AS U THINK", false); + + if (difficulty == 2) + { + display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .43, "#", false); + } + else if (difficulty == 1) + { + display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .3, "#", false); + } + else + { + display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .56, "#", false); + } + + if (input_down()) + { + difficulty++; + if (difficulty == 4) + { + difficulty = 1; + } + fade_e = false; + game_jump_to_scene(SCENE_DIFFICULTY); + } + else if (input_up()) + { + difficulty--; + if (difficulty == 0) + { + difficulty = 3; + } + fade_e = false; + game_jump_to_scene(SCENE_DIFFICULTY); + } + else if (input_fire()) + { + fade_e = true; + game_jump_to_scene(SCENE_MUSIC); + } + + display_update(); +} + +void game_run_music_scene(void) +{ + fade_e = false; + platform_delay(200); + + display_draw_rect(1, 1, 127, 63, false); + display_draw_text(SCREEN_WIDTH / 2.75 - 25, SCREEN_HEIGHT * .25, "MUSIC", false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .39, "OFF", false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .50, "ON (NOT RECOMENDED)", false); + + if (m == false) + { + display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .50, "#", false); + } + else if (m == true) + { + display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .39, "#", false); + } + + if (input_down() || input_up()) + { + m = !m; + game_jump_to_scene(SCENE_MUSIC); + } + else if (input_fire()) + { + fade_e = true; + game_jump_to_scene(SCENE_STORY); + } + + display_update(); } -/** - * @brief GAME run level scene. - * - */ void game_run_level_scene(void) { - static bool gun_fired; - static uint8_t gun_pos; - static float rot_speed; - static float old_dir_x; - static float old_plane_x; - static float view_height; - static float jogging; + display_get_fps(); + + if (player.keys == 0) + { + coll = false; + } + else if (player.keys != 0) + { + coll = true; + } + + if (levelID == false) + { + k = player.keys; + } + + display_draw_rect(1, 58, 100, 2, false); + + updateHud(); + + // Clear only the 3d view + memset(display_buf, 0, SCREEN_WIDTH * (RENDER_HEIGHT / 8)); + + if (player.pos.x >= 2 && player.pos.x <= 3 && player.pos.y >= 54 && player.pos.y <= 55 && z == 1 && player.secret < 2) + { + game_spawn_entity(E_ENEMY, 1, 51); + game_spawn_entity(E_ENEMY, 3, 51); + player.secret++; + } + + if (player.pos.x >= 46 && player.pos.x <= 47 && player.pos.y >= 35 && player.pos.y <= 36 && levelID == true) + { + player.pos.x = 12.5; + player.pos.y = 33.5; + enemyCount = 0; + game_spawn_entity(E_ENEMY, 10, 38); + game_spawn_entity(E_ENEMY, 13, 38); + bss = true; + } + if (player.pos.y >= 55 && player.pos.y <= 56 && player.pos.x >= 12 && player.pos.x <= 23 && levelID == true) + { + mid = 3; + m = false; + sound_play(mus_s1_snd, MUS_S1_SND_LEN); + game_jump_to_scene(SCENE_STORY); + } + if (levelID == true && bss == true) + { + if (enemyCount == 1 || enemyCount == 5 || enemyCount == 9) + { + clearEntities(); + enemyCount++; + game_spawn_entity(E_ENEMY, 13, 38); + } + else if (enemyCount == 3 || enemyCount == 7 || enemyCount == 11) + { + clearEntities(); + enemyCount++; + game_spawn_entity(E_ENEMY, 10, 38); + } + else if (enemyCount == 13) + { + player.pos.y = player.pos.y + 12; + enemyCount = 0; + enemyCount2 = 8; + updateHud(); + } + } + + if (m == true) + { + music = 99; + } // If the player is alive if (player.health > 0) { + + if (jump == 1 || jump == 2) + { + if (jump_height > 0 && jump == 2) + { + view_height -= 4; + jump_height -= 4; + } + else if (jump_height < 20 && jump == 1) + { + view_height += 4; + jump_height += 4; + } + else if (jump_height == 20) + jump = 2; + else if (jump_height == 0) + jump = 0; + + vel = 2; + } + if (jump == 0) + { + view_height = fabsf(sinf(platform_millis() * JOGGING_SPEED)) * 6 * jogging; + vel = 1; + } + // Player speed if (input_up()) { - player.velocity += (MOV_SPEED - player.velocity) * 0.4f; - jogging = fabsf(player.velocity) * MOV_SPEED_INV; + + player.velocity += (MOV_SPEED - player.velocity) * .4; + if (jump == 1 || jump == 2) + { + jogging = 0; + gun_pos = 22; + } + else + { + jogging = fabsf(player.velocity) * MOV_SPEED_INV * 2; + } } else if (input_down()) { - player.velocity -= (MOV_SPEED + player.velocity) * 0.4f; - jogging = fabsf(player.velocity) * MOV_SPEED_INV; + + jogging = fabsf(player.velocity) * MOV_SPEED_INV * 2; + player.velocity += (-MOV_SPEED - player.velocity) * .4; + if (jump == 1 || jump == 2) + { + jogging = 0; + gun_pos = 22; + } + else + { + jogging = fabsf(player.velocity) * MOV_SPEED_INV * 2; + } } else { - player.velocity *= 0.5f; - jogging = fabsf(player.velocity) * MOV_SPEED_INV; + if (jump == 1 || jump == 2) + { + jogging = 0; + gun_pos = 22; + } + else + { + jogging = fabsf(player.velocity) * MOV_SPEED_INV * 2; + } + player.velocity *= .5; } // Player rotation if (input_right()) { + rot_speed = ROT_SPEED * delta_time; old_dir_x = player.dir.x; - player.dir.x = player.dir.x * cosf(-rot_speed) - - player.dir.y * sinf(-rot_speed); - player.dir.y = old_dir_x * sinf(-rot_speed) + - player.dir.y * cosf(-rot_speed); + player.dir.x = player.dir.x * cosf(-rot_speed) - player.dir.y * sinf(-rot_speed); + player.dir.y = old_dir_x * sinf(-rot_speed) + player.dir.y * cosf(-rot_speed); old_plane_x = player.plane.x; - player.plane.x = player.plane.x * cosf(-rot_speed) - - player.plane.y * sinf(-rot_speed); - player.plane.y = old_plane_x * sinf(-rot_speed) + - player.plane.y * cosf(-rot_speed); + player.plane.x = player.plane.x * cosf(-rot_speed) - player.plane.y * sinf(-rot_speed); + player.plane.y = old_plane_x * sinf(-rot_speed) + player.plane.y * cosf(-rot_speed); } else if (input_left()) { + rot_speed = ROT_SPEED * delta_time; old_dir_x = player.dir.x; - player.dir.x = player.dir.x * cosf(rot_speed) - - player.dir.y * sinf(rot_speed); - player.dir.y = old_dir_x * sinf(rot_speed) + - player.dir.y * cosf(rot_speed); + player.dir.x = player.dir.x * cosf(rot_speed) - player.dir.y * sinf(rot_speed); + player.dir.y = old_dir_x * sinf(rot_speed) + player.dir.y * cosf(rot_speed); old_plane_x = player.plane.x; - player.plane.x = player.plane.x * cosf(rot_speed) - - player.plane.y * sinf(rot_speed); - player.plane.y = old_plane_x * sinf(rot_speed) + - player.plane.y * cosf(rot_speed); + player.plane.x = player.plane.x * cosf(rot_speed) - player.plane.y * sinf(rot_speed); + player.plane.y = old_plane_x * sinf(rot_speed) + player.plane.y * cosf(rot_speed); } - view_height = - fabsf(sinf(platform_millis() * JOGGING_SPEED)) * 6.0f * jogging; + if (input_left() && input_right() && jump == 0) + { + jump = 1; + sound_play(jump_snd, JUMP_SND_LEN); + } - if (view_height > 5.9f) + if (view_height > 2.95 && jump == 0) { - if (walk_sound_toggle) - { - sound_play(walk1_snd, WALK1_SND_LEN); - walk_sound_toggle = false; - } - else + if (sound == false) { - sound_play(walk2_snd, WALK2_SND_LEN); - walk_sound_toggle = true; + if (walkSoundToggle) + { + sound_play(walk1_snd, WALK1_SND_LEN); + walkSoundToggle = false; + } + else + { + sound_play(walk2_snd, WALK2_SND_LEN); + walkSoundToggle = true; + } } } - // Update gun if (gun_pos > GUN_TARGET_POS) { // Right after fire - gun_pos -= 1; + gun_pos -= 2; } else if (gun_pos < GUN_TARGET_POS) { // Showing up gun_pos += 2; } - else if (!gun_fired && input_fire()) + else if (!gun_fired && input_fire() && player.keys > 0 && reload1 == false) { - // Ready to fire and fire pressed + // ready to fire and fire pressed gun_pos = GUN_SHOT_POS; gun_fired = true; game_fire_shootgun(); + if (debug == false) + { + player.keys--; + } } else if (gun_fired && !input_fire()) { - // Just fired and restored position + // just fired and restored position gun_fired = false; + reload1 = true; + } + else if (!gun_fired && input_fire() && player.keys == 0 && reload1 == false) + { + gun_pos = GUN_SHOT_POS; + gun_fired = true; + game_fire_shootgun(); } - - // Update player - game_update_position( - level_1, - &(player.pos), - player.dir.x * player.velocity * delta_time, - player.dir.y * player.velocity * delta_time, - false); - - // Update entities - game_update_entities(level_1); } else { // The player is dead - if (view_height > -10.0f) + z = 3; + updateHud(); + z = 4; + updateHud(); + + if (view_height > -5) view_height--; - else if (input_fire()) - game_jump_to_scene(SCENE_INTRO); - if (gun_pos > 1) + else if (input_fire()) + { + game_jump_to_scene(INTRO); + } + if (gun_pos > 0) gun_pos -= 2; + else + { + rc1 = 3; + } } + if (fabsf(player.velocity) > 0.003) + { + + if (levelID == false) + { + game_update_position( + E1M1, + &(player.pos), + player.dir.x * player.velocity * delta_time * vel, + player.dir.y * player.velocity * delta_time * vel, false); + } + if (levelID == true) + { + game_update_position( + E1M2, + &(player.pos), + player.dir.x * player.velocity * delta_time * vel, + player.dir.y * player.velocity * delta_time * vel, false); + } + } + else + { + player.velocity = 0; + } + + if (enemyCount == enemyGoal && levelID == false) + { + z = 3; + updateHud(); + z = 5; + updateHud(); + if (del == 0) + { + platform_delay(200); + del++; + } + if (input_fire()) + { + player.pos.x = 230; + player.pos.y = 50; + mid = 2; + enemyCount = 0; + z = 3; + updateHud(); + game_jump_to_scene(SCENE_STORY); + } + } + + // Update things + if (levelID == false) + { + game_update_entities(E1M1); + } + if (levelID == true) + { + game_update_entities(E1M2); + } + + updateHud(); + // Render stuff - game_render_map(level_1, view_height); + + if (levelID == false) + { + renderMap(E1M1, view_height); + } + else if (levelID == true) + { + renderMap(E1M2, view_height); + } + game_render_entities(view_height); - game_render_gun(gun_pos, jogging); + + if (reload1 == true) + { + r++; + } + + if (coll == false) + { + r = 7; + } + + if (r == 1) + { + rc1 = 1; + } + else if (r == 3) + { + rc1 = 2; + sound_play(r1_snd, R1_SND_LEN); + } + + else if (r == 5) + { + rc1 = 1; + sound_play(r2_snd, R2_SND_LEN); + } + else if (r == 7) + { + r = 0; + reload1 = false; + rc1 = 0; + } + + game_render_gun(gun_pos, jogging, gun_fired, rc1); // Fade in effect - if (fade_screen > 0) + if (fade > 0) { - display_fade(fade_screen, false); - fade_screen--; - return; + display_fade(fade, false); + fade--; + + if (fade == 0) + { + // Only draw the hud after fade in effect + game_render_hud(); + } + } + else + { + renderStats(); } - game_render_hud(); - // Flash screen - if (flash_screen) + // flash screen + if (flash_screen > 0) { - display_invert(); - flash_screen = false; + invert_screen = !invert_screen; + flash_screen--; } + else if (invert_screen) + { + invert_screen = 0; + } + updateHud(); + + // Draw the frame + if (invert_screen) + display_invert(); + display_update(); // Exit routine - if (input_exit()) - game_jump_to_scene(SCENE_INTRO); + if (input_left() && input_right() && input_up() && input_down() && input_fire()) + { + z = 3; + updateHud(); + if (debug == true) + { + z = 3; + updateHud(); + z = 10; + debug = false; + updateHud(); + } + else + { + z = 3; + updateHud(); + z = 11; + debug = true; + updateHud(); + player.cheats = true; + } + updateHud(); + platform_delay(500); + } +} + +void loop(void) +{ + switch (scene) + { + case INTRO: + { + + game_run_intro_scene(); + break; + } + case SCENE_SCORE: + { + game_run_score_scene(); + break; + } + case SCENE_MUSIC: + { + + game_run_music_scene(); + break; + } + case SCENE_DIFFICULTY: + { + game_run_difficulty_scene(); + break; + } + case SCENE_LEVEL: + { + + game_run_level_scene(); + + break; + } + case SCENE_STORY: + { + game_run_story_scene(); + + break; + } + } + + if (fade_e == true) + { // fade out effect + for (uint8_t i = 0; i < GRADIENT_COUNT; i++) + { + display_fade(i, 0); + display_update(); + platform_delay(40); + } + } + exit_scene = false; + + // Stop (so it doesn't repeat forever driving you crazy--you're welcome). } -/** - * @brief GAME main function. - * - */ void main(void) { /* Initialize game */ @@ -1152,6 +1983,4 @@ void main(void) /* Stop drawing */ display_draw_stop(); } -} - -/* -------------------------------------------------------------------------- */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/game_old.c b/src/game_old.c new file mode 100644 index 0000000..548d4a3 --- /dev/null +++ b/src/game_old.c @@ -0,0 +1,1157 @@ +/* Includes ----------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include + +#include "constants.h" +#include "coords.h" +#include "display.h" +#include "entities.h" +#include "input.h" +#include "level.h" +#include "platform.h" +#include "sound.h" +#include "sprites.h" +#include "utils.h" + +/** TODO: verify if using pointers instead of returning struct is faster */ +/** TODO: integrate doom brutality expansion */ + +/* Data types --------------------------------------------------------------- */ + +typedef enum +{ + SCENE_INTRO, + SCENE_LEVEL1, + /* Add more levels here */ +} GameScene; + +/* Function prototypes ------------------------------------------------------ */ + +/* Level */ +static void game_init_level_scene(const uint8_t level[]); + +/* Entities */ +static EntityType game_get_level_entity(const uint8_t level[], uint8_t x, + uint8_t y); +static bool game_is_entity_spawned(EntityUID uid); +static bool game_is_static_entity_spawned(EntityUID uid); +static void game_spawn_entity(EntityType type, uint8_t x, uint8_t y); +static void game_spawn_fireball(float x, float y); +static void game_remove_entity(EntityUID uid); +static void game_remove_static_entity(EntityUID uid); +static void game_update_entities(const uint8_t level[]); +static void game_sort_entities(void); + +/* Game mechanics */ +static EntityUID game_detect_collision(const uint8_t level[], Coords *pos, + float rel_x, float rel_y, + bool only_walls); +static EntityUID game_update_position(const uint8_t level[], Coords *pos, + float rel_x, float rel_y, + bool only_walls); +static void game_fire_shootgun(void); + +/* Graphics */ +static Coords game_translate_into_view(Coords *pos); +static void game_render_map(const uint8_t level[], float view_height); +static void game_render_entities(float view_height); +static void game_render_gun(uint8_t gun_pos, float jogging); +static void game_render_hud(void); + +/* Scenes */ +static void game_jump_to_scene(GameScene scene); +static void game_run_intro_scene(void); +static void game_run_level_scene(void); + +/* Global variables --------------------------------------------------------- */ + +/* Entities */ +static Player player; +static Entity entity[MAX_ENTITIES]; +static uint8_t num_entities; +static StaticEntity static_entity[MAX_STATIC_ENTITIES]; +static uint8_t num_static_entities; + +/* Graphics */ +static bool flash_screen; +static uint8_t fade_screen; + +/* Sound effects */ +static bool walk_sound_toggle; + +/* Scene */ +static void (*game_run_scene)(void); + +/* Function definitions ----------------------------------------------------- */ + +/** + * @brief GAME jump to another scene at the end of the current frame. + * + * @param scene Game scene + */ +void game_jump_to_scene(GameScene scene) +{ + switch (scene) + { + case SCENE_INTRO: + game_run_scene = game_run_intro_scene; + break; + + case SCENE_LEVEL1: + game_init_level_scene(level_1); + game_run_scene = game_run_level_scene; + break; + + default: + game_run_scene = game_run_intro_scene; + break; + } +} + +/** + * @brief GAME initialize level state. + * + * @param level Level byte map + */ +void game_init_level_scene(const uint8_t level[]) +{ + // Initialize game entities + memset(entity, 0x00, sizeof(Entity) * MAX_ENTITIES); + memset(static_entity, 0x00, sizeof(StaticEntity) * MAX_STATIC_ENTITIES); + num_entities = 0; + num_static_entities = 0; + + // Initialize screen effects + flash_screen = false; + fade_screen = GRADIENT_COUNT - 1; + + // Initialize audio effects + walk_sound_toggle = false; + + // Initialize game scene callback + game_run_scene = game_run_intro_scene; + + // Find player in the map and create instance + for (uint8_t y = LEVEL_HEIGHT - 1; y >= 0; y--) + { + for (uint8_t x = 0; x < LEVEL_WIDTH; x++) + { + uint8_t block = game_get_level_entity(level, x, y); + + if (block == E_PLAYER) + { + player = entities_create_player(x, y); + return; + } + + /** TODO: Create other static entities */ + } + } +} + +/** + * @brief GAME get entity type from level byte map. + * + * @param level Level byte map + * @param x X coordinate + * @param y Y coordinate + * @return EntityType Entity type + */ +EntityType game_get_level_entity(const uint8_t level[], uint8_t x, uint8_t y) +{ + if ((x < 0) || (x >= LEVEL_WIDTH) || (y < 0) || (y >= LEVEL_HEIGHT)) + return E_FLOOR; + + // Y is read in inverse order + uint8_t byte = level[((LEVEL_HEIGHT - 1 - y) * LEVEL_WIDTH + x) / 2]; + byte >>= (x % 2) ? 0 : 4; + + return byte & 0x0f; +} + +/** + * @brief GAME check if an entity with given UID is already spawned. + * + * @param uid Entity UID number + * @return bool Entity is spawned + */ +bool game_is_entity_spawned(EntityUID uid) +{ + for (uint8_t i = 0; i < num_entities; i++) + { + if (entity[i].uid == uid) + return true; + } + + return false; +} + +/** + * @brief GAME check if a static entity with given UID is already spawned. + * + * @param uid Entity UID number + * @return bool Static entity is spawned + */ +bool game_is_static_entity_spawned(EntityUID uid) +{ + for (uint8_t i = 0; i < num_static_entities; i++) + { + if (static_entity[i].uid == uid) + return true; + } + + return false; +} + +/** + * @brief GAME spawn a new entity at a given location. + * + * @param type Entity type + * @param x X coordinate + * @param y Y coordinate + */ +void game_spawn_entity(EntityType type, uint8_t x, uint8_t y) +{ + // Limit the number of spawned entities + if (num_entities >= MAX_ENTITIES) + return; + + /** TODO: Read static entity status */ + + switch (type) + { + case E_ENEMY: + entity[num_entities] = entities_create_enemy(x, y); + num_entities++; + break; + + case E_KEY: + entity[num_entities] = entities_create_key(x, y); + num_entities++; + break; + + case E_MEDKIT: + entity[num_entities] = entities_create_medkit(x, y); + num_entities++; + break; + } +} + +/** + * @brief GAME spawn a fireball at a given location. + * + * @param x X coordinate + * @param y Y coordinate + */ +void game_spawn_fireball(float x, float y) +{ + // Limit the number of spawned entities + if (num_entities >= MAX_ENTITIES) + return; + + // Remove if already exists, don't throw anything. Not the best, + // but shouldn't happen too often + EntityUID uid = entities_get_uid(E_FIREBALL, x, y); + if (game_is_entity_spawned(uid)) + return; + + // Calculate direction. 32 angles + int16_t dir = FIREBALL_ANGLES * + ((atan2f(y - player.pos.y, x - player.pos.x) / PI) + 1); + + if (dir < 0) + dir += FIREBALL_ANGLES * 2; + + entity[num_entities] = entities_create_fireball(x, y, dir); + num_entities++; +} + +/** + * @brief GAME remove an entity. + * + * @param uid Entity UID number + */ +void game_remove_entity(EntityUID uid) +{ + uint8_t i = 0; + bool found = false; + + while (i < num_entities) + { + if (!found && entity[i].uid == uid) + { + found = true; + num_entities--; + } + + if (found) + entity[i] = entity[i + 1]; + + i++; + } +} + +/** + * @brief GAME remove a static entity. + * + * @param uid Entity UID number + */ +void game_remove_static_entity(EntityUID uid) +{ + uint8_t i = 0; + bool found = false; + + while (i < num_static_entities) + { + if (!found && static_entity[i].uid == uid) + { + found = true; + num_static_entities--; + } + + if (found) + static_entity[i] = static_entity[i + 1]; + + i++; + } +} + +/** + * @brief GAME detect collision between entities and level blocks. + * + * @param level Level byte map + * @param pos Position to be checked + * @param rel_x X relative direction + * @param rel_y Y relative direction + * @param only_walls Check only walls collisions + * @return EntityUID Entity UID number + */ +EntityUID game_detect_collision(const uint8_t level[], Coords *pos, float rel_x, + float rel_y, bool only_walls) +{ + // Wall collision + uint8_t round_x = pos->x + rel_x; + uint8_t round_y = pos->y + rel_y; + uint8_t block = game_get_level_entity(level, round_x, round_y); + + if (block == E_WALL) + { + sound_play(hit_wall_snd, HIT_WALL_SND_LEN); + return entities_get_uid(block, round_x, round_y); + } + + if (only_walls) + return UID_NULL; + + // Entity collision + for (uint8_t i = 0; i < num_entities; i++) + { + // Don't collide with itself + if (&(entity[i].pos) == pos) + continue; + + EntityType type = entities_get_type(entity[i].uid); + + // Only ALIVE enemy collision + if ((type != E_ENEMY) || + (entity[i].state == S_DEAD) || + (entity[i].state == S_HIDDEN)) + continue; + + Coords new_coords = {entity[i].pos.x - rel_x, entity[i].pos.y - rel_y}; + uint8_t distance = coords_get_distance(pos, &new_coords); + + // Check distance and if it's getting closer + if ((distance < ENEMY_COLLIDER_DIST) && + (distance < entity[i].distance)) + return entity[i].uid; + } + + return UID_NULL; +} + +/** + * @brief GAME update position if possible, otherwise return collided uid. + * + * @param level Level byte map + * @param pos Position to be checked + * @param rel_x X relative direction + * @param rel_y Y relative direction + * @param only_walls Check only walls collisions + * @return EntityUID Entity UID number + */ +EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, + float rel_y, bool only_walls) +{ + EntityUID collide_x = + game_detect_collision(level, pos, rel_x, 0, only_walls); + EntityUID collide_y = + game_detect_collision(level, pos, 0, rel_y, only_walls); + + if (!collide_x) + pos->x += rel_x; + if (!collide_y) + pos->y += rel_y; + + return (collide_x || collide_y || UID_NULL); +} + +/** + * @brief GAME player fire shootgun and compute damage. + * + */ +void game_fire_shootgun(void) +{ + sound_play(shoot_snd, SHOOT_SND_LEN); + + for (uint8_t i = 0; i < num_entities; i++) + { + // Shoot only ALIVE enemies + if ((entities_get_type(entity[i].uid) != E_ENEMY) || + (entity[i].state == S_DEAD) || + (entity[i].state == S_HIDDEN)) + continue; + + Coords transform = game_translate_into_view(&(entity[i].pos)); + if ((fabsf(transform.x) < 20.0f) && (transform.y > 0.0f)) + { + uint8_t damage = MIN( + GUN_MAX_DAMAGE, + GUN_MAX_DAMAGE / + (fabsf(transform.x) * entity[i].distance) / 5.0f); + if (damage > 0) + { + entity[i].health = MAX(0, entity[i].health - damage); + entity[i].state = S_HIT; + entity[i].timer = 4; + } + } + } +} + +/** + * @brief GAME execute entities AI logic. + * + * @param level Level byte map + */ +void game_update_entities(const uint8_t level[]) +{ + uint8_t i = 0; + while (i < num_entities) + { + // Update distance + entity[i].distance = coords_get_distance( + &(player.pos), &(entity[i].pos)); + + // Run the timer. Works with actual frames. + if (entity[i].timer > 0) + entity[i].timer--; + + // Too far away. put it in doze mode + if (entity[i].distance > MAX_ENTITY_DISTANCE) + { + game_remove_entity(entity[i].uid); + continue; + } + + // Bypass render if hidden + if (entity[i].state == S_HIDDEN) + { + i++; + continue; + } + + EntityType type = entities_get_type(entity[i].uid); + switch (type) + { + case E_ENEMY: + { + // Enemy "IA" + if (entity[i].health == 0) + { + if (entity[i].state != S_DEAD) + { + entity[i].state = S_DEAD; // Entity is dead + entity[i].timer = 6; + } + } + else if (entity[i].state == S_HIT) + { + if (entity[i].timer == 0) + { + entity[i].state = S_ALERT; // Back to alert state + entity[i].timer = 40; // Delay next fireball thrown + } + } + else if (entity[i].state == S_FIRING) + { + if (entity[i].timer == 0) + { + entity[i].state = S_ALERT; // Back to alert state + entity[i].timer = 40; // Delay next fireball thrown + } + } + else + { + if ((entity[i].distance > ENEMY_MELEE_DIST) && + (entity[i].distance < MAX_ENEMY_VIEW)) + { + if (entity[i].state != S_ALERT) + { + entity[i].state = S_ALERT; // Back to alert state + entity[i].timer = 20; // used to throw fireballs + } + else + { + if (entity[i].timer == 0) + { + // Throw a fireball + game_spawn_fireball( + entity[i].pos.x, entity[i].pos.y); + entity[i].state = S_FIRING; + entity[i].timer = 6; + } + else + { + // Move towards to the player + game_update_position( + level, + &(entity[i].pos), + SIGN(player.pos.x, entity[i].pos.x) * + ENEMY_SPEED * delta_time, + SIGN(player.pos.y, entity[i].pos.y) * + ENEMY_SPEED * delta_time, + true); + } + } + } + else if (entity[i].distance <= ENEMY_MELEE_DIST) + { + if (entity[i].state != S_MELEE) + { + // Preparing the melee attack + entity[i].state = S_MELEE; + entity[i].timer = 10; + } + else if (entity[i].timer == 0) + { + // Melee attack + player.health = + MAX(0, player.health - ENEMY_MELEE_DAMAGE); + entity[i].timer = 14; + flash_screen = true; + } + } + else + { + entity[i].state = S_STAND; + } + } + break; + } + + case E_FIREBALL: + { + if (entity[i].distance < FIREBALL_COLLIDER_DIST) + { + // Hit the player and disappear + player.health = + MAX(0, player.health - ENEMY_FIREBALL_DAMAGE); + flash_screen = true; + game_remove_entity(entity[i].uid); + continue; + } + else + { + // Move, only collide with walls. + // Note: using health to store the angle of the movement + EntityUID collided = game_update_position( + level, + &(entity[i].pos), + cosf((float)entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED, + sinf((float)entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED, + true); + + if (collided) + { + game_remove_entity(entity[i].uid); + continue; + } + } + break; + } + + case E_MEDKIT: + { + if (entity[i].distance < ITEM_COLLIDER_DIST) + { + // Pickup + sound_play(medkit_snd, MEDKIT_SND_LEN); + entity[i].state = S_HIDDEN; + player.health = MIN(100, player.health + 50); + flash_screen = true; + } + break; + } + + case E_KEY: + { + if (entity[i].distance < ITEM_COLLIDER_DIST) + { + // Pickup + sound_play(get_key_snd, GET_KEY_SND_LEN); + entity[i].state = S_HIDDEN; + player.keys++; + flash_screen = true; + } + break; + } + } + + i++; + } +} + +/** + * @brief GAME render map with raycasting technique. + * NOTE: Based on https://lodev.org/cgtutor/raycasting.html + * + * @param level Level byte map + * @param view_height View height of the camera + */ +void game_render_map(const uint8_t level[], float view_height) +{ + EntityUID last_uid; + + for (uint8_t x = 0; x < SCREEN_WIDTH; x += RES_DIVIDER) + { + float camera_x = 2 * (float)x / SCREEN_WIDTH - 1; + float ray_x = player.dir.x + player.plane.x * camera_x; + float ray_y = player.dir.y + player.plane.y * camera_x; + uint8_t map_x = (uint8_t)(player.pos.x); + uint8_t map_y = (uint8_t)(player.pos.y); + Coords map_coords = {player.pos.x, player.pos.y}; + float delta_x = fabsf(1 / ray_x); + float delta_y = fabsf(1 / ray_y); + + int8_t step_x; + int8_t step_y; + float side_x; + float side_y; + + if (ray_x < 0) + { + step_x = -1; + side_x = (player.pos.x - map_x) * delta_x; + } + else + { + step_x = 1; + side_x = (map_x + 1.0 - player.pos.x) * delta_x; + } + + if (ray_y < 0) + { + step_y = -1; + side_y = (player.pos.y - map_y) * delta_y; + } + else + { + step_y = 1; + side_y = (map_y + 1.0 - player.pos.y) * delta_y; + } + + // Wall detection + uint8_t depth = 0; + bool hit = false; + bool side; + while (!hit && (depth < MAX_RENDER_DEPTH)) + { + if (side_x < side_y) + { + side_x += delta_x; + map_x += step_x; + side = false; + } + else + { + side_y += delta_y; + map_y += step_y; + side = true; + } + + uint8_t block = game_get_level_entity(level, map_x, map_y); + + if (block == E_WALL) + hit = true; + else + { + // Spawning entities here, as soon they are visible for the + // player. Not the best place, but would be a very performance + // cost scan for them in another loop + if ((block == E_ENEMY) || (block & 0b00001000)) + { + // Check that it's close to the player + if (coords_get_distance(&(player.pos), &map_coords) < + MAX_ENTITY_DISTANCE) + { + EntityUID uid = entities_get_uid(block, map_x, map_y); + if (last_uid != uid && !game_is_entity_spawned(uid)) + { + game_spawn_entity(block, map_x, map_y); + last_uid = uid; + } + } + } + } + + depth++; + } + + if (hit) + { + float distance; + if (!side) + distance = + MAX(1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); + else + distance = + MAX(1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); + + // store zbuffer value for the column + zbuffer[x / Z_RES_DIVIDER] = + MIN(distance * DISTANCE_MULTIPLIER, 0xff); + + // rendered line height + uint8_t line_height = RENDER_HEIGHT / distance; + + display_draw_vline( + x, + view_height / distance - line_height / 2 + RENDER_HEIGHT / 2, + view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, + GRADIENT_COUNT - (side * 2) - + (distance / MAX_RENDER_DEPTH * GRADIENT_COUNT)); + } + } +} + +/** + * @brief GAME sort entities from far to close. + * + */ +void game_sort_entities(void) +{ + uint8_t gap = num_entities; + bool swapped = false; + while ((gap > 1) || (swapped)) + { + // shrink factor 1.3 + gap = (gap * 10) / 13; + if ((gap == 9) || (gap == 10)) + gap = 11; + if (gap < 1) + gap = 1; + + swapped = false; + for (uint8_t i = 0; i < num_entities - gap; i++) + { + uint8_t j = i + gap; + if (entity[i].distance < entity[j].distance) + { + SWAP(entity[i], entity[j]); + swapped = true; + } + } + } +} + +/** + * @brief GAME translate 2D map coordinates into camera coordinates. + * + * @param pos 2D map coordinates + * @return Coords Camera coordinates + */ +Coords game_translate_into_view(Coords *pos) +{ + // Translate sprite position to relative to camera + float sprite_x = pos->x - player.pos.x; + float sprite_y = pos->y - player.pos.y; + + // Required for correct matrix multiplication + float inv_det = + 1.0f / (player.plane.x * player.dir.y - player.dir.x * player.plane.y); + float transform_x = + inv_det * (player.dir.y * sprite_x - player.dir.x * sprite_y); + float transform_y = + inv_det * (-player.plane.y * sprite_x + player.plane.x * sprite_y); + + return (Coords){transform_x, transform_y}; +} + +/** + * @brief GAME render entities sprites. + * + * @param view_height View height of the camera + */ +void game_render_entities(float view_height) +{ + game_sort_entities(); + + for (uint8_t i = 0; i < num_entities; i++) + { + if (entity[i].state == S_HIDDEN) + continue; + + Coords transform = game_translate_into_view(&(entity[i].pos)); + + // don´t render if behind the player or too far away + if ((transform.y <= 0.1f) || (transform.y > MAX_SPRITE_DEPTH)) + continue; + + int16_t sprite_screen_x = + HALF_WIDTH * (1.0f + (transform.x / transform.y)); + int8_t sprite_screen_y = + (RENDER_HEIGHT / 2) + (view_height / transform.y); + + // Don't try to render if outside of screen + // doing this pre-shortcut due int16 -> int8 conversion + // makes out-of-screen values fit into the screen space + if ((sprite_screen_x < -HALF_WIDTH) || + (sprite_screen_x > SCREEN_WIDTH + HALF_WIDTH)) + continue; + + switch (entities_get_type(entity[i].uid)) + { + case E_ENEMY: + { + uint8_t sprite; + if (entity[i].state == S_ALERT) + sprite = (platform_millis() / 500) % 2; // Walking + else if (entity[i].state == S_FIRING) + sprite = 2; // Fireball + else if (entity[i].state == S_HIT) + sprite = 3; // Hit + else if (entity[i].state == S_MELEE) + sprite = entity[i].timer > 10 ? 2 : 1; // Melee atack + else if (entity[i].state == S_DEAD) + sprite = entity[i].timer > 0 ? 3 : 4; // Dying + else + sprite = 0; // Stand + + display_draw_sprite( + sprite_screen_x - BMP_IMP_WIDTH * 0.5f / transform.y, + sprite_screen_y - 8 / transform.y, bmp_imp_bits, + bmp_imp_mask, + BMP_IMP_WIDTH, + BMP_IMP_HEIGHT, + sprite, + transform.y); + break; + } + + case E_FIREBALL: + { + display_draw_sprite( + sprite_screen_x - BMP_FIREBALL_WIDTH / 2 / transform.y, + sprite_screen_y - BMP_FIREBALL_HEIGHT / 2 / transform.y, + bmp_fireball_bits, + bmp_fireball_mask, + BMP_FIREBALL_WIDTH, + BMP_FIREBALL_HEIGHT, + 0, + transform.y); + break; + } + + case E_MEDKIT: + { + display_draw_sprite( + sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, + sprite_screen_y + 5 / transform.y, + bmp_items_bits, + bmp_items_mask, + BMP_ITEMS_WIDTH, + BMP_ITEMS_HEIGHT, + 0, + transform.y); + break; + } + + case E_KEY: + { + display_draw_sprite( + sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, + sprite_screen_y + 5 / transform.y, + bmp_items_bits, + bmp_items_mask, + BMP_ITEMS_WIDTH, + BMP_ITEMS_HEIGHT, + 1, + transform.y); + break; + } + } + } +} + +/** + * @brief GAME render player gun sprite. + * + * @param gun_pos Gun cyclic position + * @param jogging Player jogging speed + */ +void game_render_gun(uint8_t gun_pos, float jogging) +{ + // jogging + uint8_t x = 48 + sinf(platform_millis() * JOGGING_SPEED) * 10 * jogging; + uint8_t y = RENDER_HEIGHT - gun_pos + + fabsf(cosf(platform_millis() * JOGGING_SPEED)) * 8 * jogging; + + // Gun fire + if (gun_pos > GUN_SHOT_POS - 2) + display_draw_bitmap(x + 6, y - 11, bmp_fire_bits, BMP_FIRE_WIDTH, + BMP_FIRE_HEIGHT, true); + + // Don't draw over the hud + uint8_t clip_height = MAX(0, MIN(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); + + // Draw the gun (black mask + actual sprite) + display_draw_bitmap(x, y, bmp_gun_mask, BMP_GUN_WIDTH, clip_height, false); + display_draw_bitmap(x, y, bmp_gun_bits, BMP_GUN_WIDTH, clip_height, true); +} + +/** + * @brief GAME render heads-up display (HUD). + * + */ +void game_render_hud(void) +{ + // Clear HUD + display_draw_rect(0, RENDER_HEIGHT, SCREEN_WIDTH, HUD_HEIGHT, false); + + // Draw HUD symbols + display_draw_text(2, RENDER_HEIGHT, "{}", false); + display_draw_text(40, RENDER_HEIGHT, "[]", false); + + // Update stats + display_draw_int(12, RENDER_HEIGHT, player.health); + display_draw_int(50, RENDER_HEIGHT, player.keys); + display_draw_int(114, RENDER_HEIGHT, (uint8_t)(display_get_fps())); + display_draw_int(82, RENDER_HEIGHT, num_entities); +} + +/** + * @brief GAME run intro scene. + * + */ +void game_run_intro_scene(void) +{ + display_draw_bitmap( + (SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, + (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, + bmp_logo_bits, + BMP_LOGO_WIDTH, + BMP_LOGO_HEIGHT, + true); + + display_draw_text( + SCREEN_WIDTH / 2 - 25, + SCREEN_HEIGHT * 0.8f, + "PRESS FIRE", + true); + + if (input_fire()) + game_jump_to_scene(SCENE_LEVEL1); +} + +/** + * @brief GAME run level scene. + * + */ +void game_run_level_scene(void) +{ + static bool gun_fired; + static uint8_t gun_pos; + static float rot_speed; + static float old_dir_x; + static float old_plane_x; + static float view_height; + static float jogging; + + // If the player is alive + if (player.health > 0) + { + // Player speed + if (input_up()) + { + player.velocity += (MOV_SPEED - player.velocity) * 0.4f; + jogging = fabsf(player.velocity) * MOV_SPEED_INV; + } + else if (input_down()) + { + player.velocity -= (MOV_SPEED + player.velocity) * 0.4f; + jogging = fabsf(player.velocity) * MOV_SPEED_INV; + } + else + { + player.velocity *= 0.5f; + jogging = fabsf(player.velocity) * MOV_SPEED_INV; + } + + // Player rotation + if (input_right()) + { + rot_speed = ROT_SPEED * delta_time; + old_dir_x = player.dir.x; + player.dir.x = player.dir.x * cosf(-rot_speed) - + player.dir.y * sinf(-rot_speed); + player.dir.y = old_dir_x * sinf(-rot_speed) + + player.dir.y * cosf(-rot_speed); + old_plane_x = player.plane.x; + player.plane.x = player.plane.x * cosf(-rot_speed) - + player.plane.y * sinf(-rot_speed); + player.plane.y = old_plane_x * sinf(-rot_speed) + + player.plane.y * cosf(-rot_speed); + } + else if (input_left()) + { + rot_speed = ROT_SPEED * delta_time; + old_dir_x = player.dir.x; + player.dir.x = player.dir.x * cosf(rot_speed) - + player.dir.y * sinf(rot_speed); + player.dir.y = old_dir_x * sinf(rot_speed) + + player.dir.y * cosf(rot_speed); + old_plane_x = player.plane.x; + player.plane.x = player.plane.x * cosf(rot_speed) - + player.plane.y * sinf(rot_speed); + player.plane.y = old_plane_x * sinf(rot_speed) + + player.plane.y * cosf(rot_speed); + } + + view_height = + fabsf(sinf(platform_millis() * JOGGING_SPEED)) * 6.0f * jogging; + + if (view_height > 5.9f) + { + if (walk_sound_toggle) + { + sound_play(walk1_snd, WALK1_SND_LEN); + walk_sound_toggle = false; + } + else + { + sound_play(walk2_snd, WALK2_SND_LEN); + walk_sound_toggle = true; + } + } + + // Update gun + if (gun_pos > GUN_TARGET_POS) + { + // Right after fire + gun_pos -= 1; + } + else if (gun_pos < GUN_TARGET_POS) + { + // Showing up + gun_pos += 2; + } + else if (!gun_fired && input_fire()) + { + // Ready to fire and fire pressed + gun_pos = GUN_SHOT_POS; + gun_fired = true; + game_fire_shootgun(); + } + else if (gun_fired && !input_fire()) + { + // Just fired and restored position + gun_fired = false; + } + + // Update player + game_update_position( + level_1, + &(player.pos), + player.dir.x * player.velocity * delta_time, + player.dir.y * player.velocity * delta_time, + false); + + // Update entities + game_update_entities(level_1); + } + else + { + // The player is dead + if (view_height > -10.0f) + view_height--; + else if (input_fire()) + game_jump_to_scene(SCENE_INTRO); + + if (gun_pos > 1) + gun_pos -= 2; + } + + // Render stuff + game_render_map(level_1, view_height); + game_render_entities(view_height); + game_render_gun(gun_pos, jogging); + + // Fade in effect + if (fade_screen > 0) + { + display_fade(fade_screen, false); + fade_screen--; + return; + } + game_render_hud(); + + // Flash screen + if (flash_screen) + { + display_invert(); + flash_screen = false; + } + + // Exit routine + if (input_exit()) + game_jump_to_scene(SCENE_INTRO); +} + +/** + * @brief GAME main function. + * + */ +void main(void) +{ + /* Initialize game */ + platform_init(); + display_init(); + sound_init(); + input_init(); + game_run_scene = game_run_intro_scene; + + while (!input_exit()) + { + /* Start drawing */ + display_draw_start(); + + /* Read user inputs */ + input_update(); + + /* Run current game scene */ + game_run_scene(); + + /* Stop drawing */ + display_draw_stop(); + } +} + +/* -------------------------------------------------------------------------- */ \ No newline at end of file From 36cb313fb80ee5bfd001f1106a12bcb2519bd30c Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Fri, 21 Jul 2023 22:27:54 +0200 Subject: [PATCH 04/18] doom nano brutality mod now works Signed-off-by: Lorenzo Gualniera --- inc/sound.h | 11 +- src/game.c | 392 ++++++---------- src/game_old.c | 1157 ------------------------------------------------ src/sound.c | 6 + 4 files changed, 156 insertions(+), 1410 deletions(-) delete mode 100644 src/game_old.c diff --git a/inc/sound.h b/inc/sound.h index a2635a3..3069490 100644 --- a/inc/sound.h +++ b/inc/sound.h @@ -179,12 +179,6 @@ static const uint8_t medkit_snd[] = { static const uint8_t MELEE_SND_LEN = 9; static const uint8_t melee_snd[] = {0x8f, 0x8e, 0x8e}; -uint8_t idx = 0; -bool sound = false; -uint16_t snd_ptr = 0; -uint8_t snd_len = 0; -uint8_t music = 0; - /* Function prototypes ------------------------------------------------------ */ /** @@ -214,6 +208,11 @@ void sound_play(const uint8_t *snd, uint8_t len); */ uint16_t sound_get_frequency(void); +/* Global variables --------------------------------------------------------- */ + +bool sound; +uint8_t music; + #endif /* SOUND_H */ /* -------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/src/game.c b/src/game.c index e130578..64e7834 100644 --- a/src/game.c +++ b/src/game.c @@ -69,7 +69,12 @@ static void game_render_hud(void); /* Scenes */ static void game_jump_to_scene(GameScene scene); static void game_run_intro_scene(void); +static void game_run_story_scene(void); +static void game_run_music_scene(void); static void game_run_level_scene(void); +static void game_run_difficulty_scene(void); +static void game_run_score_scene(void); + void updateHud(void); // temporary @@ -77,7 +82,7 @@ void updateHud(void); // temporary static bool exit_scene = false; static bool invert_screen = false; -static uint8_t flash_screen = 0; +static bool flash_screen = false; static uint8_t z = 6; static bool coll = 0; static uint8_t jump = 0; @@ -100,7 +105,7 @@ static uint8_t num_static_entities = 0; static uint8_t x = 0; static uint8_t enemyCount = 0; static uint8_t del = 0; -static bool levelID = false; +static uint8_t *game_level = E1M1; static uint8_t enemyGoal = 20; static bool fade_e = true; static bool debug = false; @@ -120,7 +125,7 @@ static float old_dir_x; static float old_plane_x; static float view_height; static float jogging; -static uint8_t fade = GRADIENT_COUNT - 1; +static uint8_t fade_screen = GRADIENT_COUNT - 1; static void (*game_run_scene)(void); @@ -133,8 +138,24 @@ void game_jump_to_scene(GameScene scene) game_run_scene = game_run_intro_scene; break; + case SCENE_SCORE: + game_run_scene = game_run_score_scene; + break; + + case SCENE_MUSIC: + game_run_scene = game_run_music_scene; + break; + + case SCENE_DIFFICULTY: + game_run_scene = game_run_difficulty_scene; + break; + + case SCENE_STORY: + game_run_scene = game_run_story_scene; + break; + case SCENE_LEVEL: - game_init_level_scene(E1M1); + game_init_level_scene(game_level); game_run_scene = game_run_level_scene; break; @@ -155,17 +176,8 @@ void game_init_level_scene(const uint8_t level[]) old_plane_x; view_height; jogging; - fade = GRADIENT_COUNT - 1; - + fade_screen = GRADIENT_COUNT - 1; mc = false; - if (levelID == false) - { - game_init_level_scene(E1M1); - } - if (levelID == true) - { - game_init_level_scene(E1M2); - } // Initialize game scene callback game_run_scene = game_run_intro_scene; @@ -292,7 +304,7 @@ void game_remove_entity(EntityUID uid) } } -void clearEntities() +void clearEntities(void) { uint8_t i = num_entities; bool found; @@ -656,7 +668,7 @@ void game_update_entities(const uint8_t level[]) player.health = MAX(0, player.health - ENEMY_MELEE_DAMAGE * difficulty); } entity[i].timer = 14; - flash_screen = 1; + flash_screen = true; updateHud(); } } @@ -678,7 +690,7 @@ void game_update_entities(const uint8_t level[]) { player.health = MAX(0, player.health - ENEMY_FIREBALL_DAMAGE * difficulty); } - flash_screen = 1; + flash_screen = true; updateHud(); game_remove_entity(entity[i].uid); continue; // continue in the loop @@ -723,7 +735,7 @@ void game_update_entities(const uint8_t level[]) player.health = MIN(100, player.health + 25); } updateHud(); - flash_screen = 1; + flash_screen = true; z = 3; updateHud(); z = 2; @@ -770,7 +782,7 @@ void game_update_entities(const uint8_t level[]) } // The map raycaster. Based on https://lodev.org/cgtutor/raycasting.html -void renderMap(const uint8_t level[], float view_height) +void game_render_map(const uint8_t level[], float view_height) { EntityUID last_uid; @@ -1088,7 +1100,7 @@ void game_render_gun(uint8_t gun_pos, float amount_jogging, bool gun_fired, uint } // Only needed first time -void game_render_hud() +void game_render_hud(void) { if (debug == false) { @@ -1105,7 +1117,7 @@ void game_render_hud() } // Render values for the HUD -void updateHud() +void updateHud(void) { display_draw_rect(12, 58, 100, 6, false); display_draw_rect(50, 58, 15, 6, false); @@ -1154,17 +1166,17 @@ void updateHud() } else if (z == 7) { - if (levelID == true && bss == true) + if (game_level == E1M2 && bss == true) { - display_draw_text(37, 58, enemyCount2, false); + display_draw_int(37, 58, enemyCount2); display_draw_text(52, 58, "OUT OF ", false); - display_draw_text(87, 58, enemyGoal2, false); + display_draw_int(87, 58, enemyGoal2); } - else if (levelID == false) + else if (game_level == E1M1) { - display_draw_text(37, 58, enemyCount, false); + display_draw_int(37, 58, enemyCount); display_draw_text(52, 58, "OUT OF ", false); - display_draw_text(87, 58, enemyGoal, false); + display_draw_int(87, 58, enemyGoal); } } else if (z == 8) @@ -1189,8 +1201,8 @@ void updateHud() display_draw_rect(1, 58, 8, 6, false); display_draw_text(2, 58, "{}", false); display_draw_text(103, 58, "[]", false); - display_draw_text(12, 58, player.health, false); - display_draw_text(113, 58, player.keys, false); + display_draw_int(12, 58, player.health); + display_draw_int(113, 58, player.keys); } else { @@ -1207,16 +1219,15 @@ void updateHud() } // Debug stats -void renderStats() +void renderStats(void) { } -void softReset() +void softReset(void) { - asm volatile("jmp 0"); } -void game_run_story_scene() +void game_run_story_scene(void) { display_draw_rect(1, 1, 127, 63, false); @@ -1242,7 +1253,8 @@ void game_run_story_scene() display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, "BUT TO START LOOKING FOR ", false); display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, "EXIT, WHILE FIGHT ALIENS.", false); - levelID = true; + // Go to next level + game_level = E1M2; } else { @@ -1258,8 +1270,6 @@ void game_run_story_scene() display_draw_text(SCREEN_WIDTH / 2.1 - 24, SCREEN_HEIGHT * .01, "THE STORY", false); display_draw_text(SCREEN_WIDTH / 2 - 27, SCREEN_HEIGHT * .91, "PRESS FIRE", false); - display_update(); - if (input_fire()) { fade_e = true; @@ -1274,13 +1284,13 @@ void game_run_story_scene() } } -void game_run_score_scene() +void game_run_score_scene(void) { - score = player.keys / 2; score += player.health; score *= 43; score *= difficulty; + if (player.secret != 0) { score += 69; @@ -1304,6 +1314,7 @@ void game_run_score_scene() BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, 1); + display_draw_text(SCREEN_WIDTH / 2.36 - 52, SCREEN_HEIGHT * .79, "NANO BRUTALITY", false); display_draw_text(SCREEN_WIDTH / 0.99 - 45, SCREEN_HEIGHT * .2, "YOU WIN", false); if (player.cheats == false) @@ -1312,25 +1323,25 @@ void game_run_score_scene() if (a < score) { a += 155; - display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a, false); + display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); sound_play(walk1_snd, WALK1_SND_LEN); } else if (a > score) { a = score; - display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a, false); + display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); m = false; music = 1; sound_play(shot_snd, SHOT_SND_LEN); } else { - display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a, false); + display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, "PRESS FIRE", false); if (input_fire()) { display_draw_rect(1, 1, 127, 63, false); - display_update(); + music = 99; platform_delay(1000); fade_e = true; @@ -1347,7 +1358,7 @@ void game_run_score_scene() if (input_fire()) { display_draw_rect(1, 1, 127, 63, false); - display_update(); + music = 99; platform_delay(1000); fade_e = true; @@ -1362,40 +1373,38 @@ void game_run_score_scene() mc = true; } } - display_update(); fade_e = false; game_jump_to_scene(SCENE_SCORE); } -// Intro screen -void game_run_intro_scene() +/** + * @brief GAME run intro scene. + * + */ +void game_run_intro_scene(void) { - music = 1; - display_draw_bitmap( (SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, - (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 6, + (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, - 1); + true); - platform_delay(100); - display_draw_text(SCREEN_WIDTH / 2.36 - 25, SCREEN_HEIGHT * .79, "NANO BRUTALITY", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 25, SCREEN_HEIGHT * .3, "PRESS", false); - display_draw_text(SCREEN_WIDTH / 0.99 - 25, SCREEN_HEIGHT * .3, "FIRE", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 25, SCREEN_HEIGHT * .91, "V 1.5", false); + display_draw_text( + SCREEN_WIDTH / 2 - 25, + SCREEN_HEIGHT * 0.8f, + "PRESS FIRE", + true); - display_update(); sound_play(mus_s1_snd, MUS_S1_SND_LEN); + if (input_fire()) game_jump_to_scene(SCENE_DIFFICULTY); - - // wait for fire } -void game_run_difficulty_scene() +void game_run_difficulty_scene(void) { platform_delay(200); @@ -1447,8 +1456,6 @@ void game_run_difficulty_scene() fade_e = true; game_jump_to_scene(SCENE_MUSIC); } - - display_update(); } void game_run_music_scene(void) @@ -1480,8 +1487,6 @@ void game_run_music_scene(void) fade_e = true; game_jump_to_scene(SCENE_STORY); } - - display_update(); } void game_run_level_scene(void) @@ -1497,7 +1502,7 @@ void game_run_level_scene(void) coll = true; } - if (levelID == false) + if (game_level == E1M1) { k = player.keys; } @@ -1516,7 +1521,7 @@ void game_run_level_scene(void) player.secret++; } - if (player.pos.x >= 46 && player.pos.x <= 47 && player.pos.y >= 35 && player.pos.y <= 36 && levelID == true) + if (player.pos.x >= 46 && player.pos.x <= 47 && player.pos.y >= 35 && player.pos.y <= 36 && game_level == E1M2) { player.pos.x = 12.5; player.pos.y = 33.5; @@ -1525,14 +1530,14 @@ void game_run_level_scene(void) game_spawn_entity(E_ENEMY, 13, 38); bss = true; } - if (player.pos.y >= 55 && player.pos.y <= 56 && player.pos.x >= 12 && player.pos.x <= 23 && levelID == true) + if (player.pos.y >= 55 && player.pos.y <= 56 && player.pos.x >= 12 && player.pos.x <= 23 && game_level == E1M2) { mid = 3; m = false; sound_play(mus_s1_snd, MUS_S1_SND_LEN); game_jump_to_scene(SCENE_STORY); } - if (levelID == true && bss == true) + if (game_level == E1M2 && bss == true) { if (enemyCount == 1 || enemyCount == 5 || enemyCount == 9) { @@ -1703,7 +1708,7 @@ void game_run_level_scene(void) } else if (gun_fired && !input_fire()) { - // just fired and restored position + // Just fired and restored position gun_fired = false; reload1 = true; } @@ -1713,6 +1718,37 @@ void game_run_level_scene(void) gun_fired = true; game_fire_shootgun(); } + + if (enemyCount == enemyGoal && game_level == E1M1) + { + z = 3; + updateHud(); + z = 5; + updateHud(); + if (del == 0) + { + platform_delay(200); + del++; + } + if (input_fire()) + { + player.pos.x = 230; + player.pos.y = 50; + mid = 2; + enemyCount = 0; + z = 3; + updateHud(); + game_jump_to_scene(SCENE_STORY); + } + } + + game_update_position( + game_level, + &(player.pos), + player.dir.x * player.velocity * delta_time * vel, + player.dir.y * player.velocity * delta_time * vel, false); + + game_update_entities(game_level); } else { @@ -1737,79 +1773,6 @@ void game_run_level_scene(void) } } - if (fabsf(player.velocity) > 0.003) - { - - if (levelID == false) - { - game_update_position( - E1M1, - &(player.pos), - player.dir.x * player.velocity * delta_time * vel, - player.dir.y * player.velocity * delta_time * vel, false); - } - if (levelID == true) - { - game_update_position( - E1M2, - &(player.pos), - player.dir.x * player.velocity * delta_time * vel, - player.dir.y * player.velocity * delta_time * vel, false); - } - } - else - { - player.velocity = 0; - } - - if (enemyCount == enemyGoal && levelID == false) - { - z = 3; - updateHud(); - z = 5; - updateHud(); - if (del == 0) - { - platform_delay(200); - del++; - } - if (input_fire()) - { - player.pos.x = 230; - player.pos.y = 50; - mid = 2; - enemyCount = 0; - z = 3; - updateHud(); - game_jump_to_scene(SCENE_STORY); - } - } - - // Update things - if (levelID == false) - { - game_update_entities(E1M1); - } - if (levelID == true) - { - game_update_entities(E1M2); - } - - updateHud(); - - // Render stuff - - if (levelID == false) - { - renderMap(E1M1, view_height); - } - else if (levelID == true) - { - renderMap(E1M2, view_height); - } - - game_render_entities(view_height); - if (reload1 == true) { r++; @@ -1842,122 +1805,57 @@ void game_run_level_scene(void) rc1 = 0; } + // Render stuff + updateHud(); + game_render_map(game_level ? game_level : E1M2, view_height); + game_render_entities(view_height); game_render_gun(gun_pos, jogging, gun_fired, rc1); // Fade in effect - if (fade > 0) + if (fade_screen > 0) { - display_fade(fade, false); - fade--; - - if (fade == 0) - { - // Only draw the hud after fade in effect - game_render_hud(); - } - } - else - { - renderStats(); + display_fade(fade_screen, false); + fade_screen--; + return; } + game_render_hud(); - // flash screen - if (flash_screen > 0) + // Flash screen + if (flash_screen) { - invert_screen = !invert_screen; - flash_screen--; - } - else if (invert_screen) - { - invert_screen = 0; - } - updateHud(); - - // Draw the frame - if (invert_screen) display_invert(); - display_update(); - - // Exit routine - if (input_left() && input_right() && input_up() && input_down() && input_fire()) - { - z = 3; - updateHud(); - if (debug == true) - { - z = 3; - updateHud(); - z = 10; - debug = false; - updateHud(); - } - else - { - z = 3; - updateHud(); - z = 11; - debug = true; - updateHud(); - player.cheats = true; - } - updateHud(); - platform_delay(500); + flash_screen = false; } -} -void loop(void) -{ - switch (scene) - { - case INTRO: - { - - game_run_intro_scene(); - break; - } - case SCENE_SCORE: - { - game_run_score_scene(); - break; - } - case SCENE_MUSIC: - { - - game_run_music_scene(); - break; - } - case SCENE_DIFFICULTY: - { - game_run_difficulty_scene(); - break; - } - case SCENE_LEVEL: - { - - game_run_level_scene(); - - break; - } - case SCENE_STORY: - { - game_run_story_scene(); - - break; - } - } - - if (fade_e == true) - { // fade out effect - for (uint8_t i = 0; i < GRADIENT_COUNT; i++) - { - display_fade(i, 0); - display_update(); - platform_delay(40); - } - } - exit_scene = false; + // Exit routine + if (input_exit()) + game_jump_to_scene(SCENE_INTRO); - // Stop (so it doesn't repeat forever driving you crazy--you're welcome). + // Exit routine + // if (input_left() && input_right() && input_up() && input_down() && input_fire()) + // { + // z = 3; + // updateHud(); + // if (debug == true) + // { + // z = 3; + // updateHud(); + // z = 10; + // debug = false; + // updateHud(); + // } + // else + // { + // z = 3; + // updateHud(); + // z = 11; + // debug = true; + // updateHud(); + // player.cheats = true; + // } + // updateHud(); + // platform_delay(500); + // } } void main(void) @@ -1983,4 +1881,4 @@ void main(void) /* Stop drawing */ display_draw_stop(); } -} \ No newline at end of file +} diff --git a/src/game_old.c b/src/game_old.c deleted file mode 100644 index 548d4a3..0000000 --- a/src/game_old.c +++ /dev/null @@ -1,1157 +0,0 @@ -/* Includes ----------------------------------------------------------------- */ - -#include -#include -#include -#include -#include -#include - -#include "constants.h" -#include "coords.h" -#include "display.h" -#include "entities.h" -#include "input.h" -#include "level.h" -#include "platform.h" -#include "sound.h" -#include "sprites.h" -#include "utils.h" - -/** TODO: verify if using pointers instead of returning struct is faster */ -/** TODO: integrate doom brutality expansion */ - -/* Data types --------------------------------------------------------------- */ - -typedef enum -{ - SCENE_INTRO, - SCENE_LEVEL1, - /* Add more levels here */ -} GameScene; - -/* Function prototypes ------------------------------------------------------ */ - -/* Level */ -static void game_init_level_scene(const uint8_t level[]); - -/* Entities */ -static EntityType game_get_level_entity(const uint8_t level[], uint8_t x, - uint8_t y); -static bool game_is_entity_spawned(EntityUID uid); -static bool game_is_static_entity_spawned(EntityUID uid); -static void game_spawn_entity(EntityType type, uint8_t x, uint8_t y); -static void game_spawn_fireball(float x, float y); -static void game_remove_entity(EntityUID uid); -static void game_remove_static_entity(EntityUID uid); -static void game_update_entities(const uint8_t level[]); -static void game_sort_entities(void); - -/* Game mechanics */ -static EntityUID game_detect_collision(const uint8_t level[], Coords *pos, - float rel_x, float rel_y, - bool only_walls); -static EntityUID game_update_position(const uint8_t level[], Coords *pos, - float rel_x, float rel_y, - bool only_walls); -static void game_fire_shootgun(void); - -/* Graphics */ -static Coords game_translate_into_view(Coords *pos); -static void game_render_map(const uint8_t level[], float view_height); -static void game_render_entities(float view_height); -static void game_render_gun(uint8_t gun_pos, float jogging); -static void game_render_hud(void); - -/* Scenes */ -static void game_jump_to_scene(GameScene scene); -static void game_run_intro_scene(void); -static void game_run_level_scene(void); - -/* Global variables --------------------------------------------------------- */ - -/* Entities */ -static Player player; -static Entity entity[MAX_ENTITIES]; -static uint8_t num_entities; -static StaticEntity static_entity[MAX_STATIC_ENTITIES]; -static uint8_t num_static_entities; - -/* Graphics */ -static bool flash_screen; -static uint8_t fade_screen; - -/* Sound effects */ -static bool walk_sound_toggle; - -/* Scene */ -static void (*game_run_scene)(void); - -/* Function definitions ----------------------------------------------------- */ - -/** - * @brief GAME jump to another scene at the end of the current frame. - * - * @param scene Game scene - */ -void game_jump_to_scene(GameScene scene) -{ - switch (scene) - { - case SCENE_INTRO: - game_run_scene = game_run_intro_scene; - break; - - case SCENE_LEVEL1: - game_init_level_scene(level_1); - game_run_scene = game_run_level_scene; - break; - - default: - game_run_scene = game_run_intro_scene; - break; - } -} - -/** - * @brief GAME initialize level state. - * - * @param level Level byte map - */ -void game_init_level_scene(const uint8_t level[]) -{ - // Initialize game entities - memset(entity, 0x00, sizeof(Entity) * MAX_ENTITIES); - memset(static_entity, 0x00, sizeof(StaticEntity) * MAX_STATIC_ENTITIES); - num_entities = 0; - num_static_entities = 0; - - // Initialize screen effects - flash_screen = false; - fade_screen = GRADIENT_COUNT - 1; - - // Initialize audio effects - walk_sound_toggle = false; - - // Initialize game scene callback - game_run_scene = game_run_intro_scene; - - // Find player in the map and create instance - for (uint8_t y = LEVEL_HEIGHT - 1; y >= 0; y--) - { - for (uint8_t x = 0; x < LEVEL_WIDTH; x++) - { - uint8_t block = game_get_level_entity(level, x, y); - - if (block == E_PLAYER) - { - player = entities_create_player(x, y); - return; - } - - /** TODO: Create other static entities */ - } - } -} - -/** - * @brief GAME get entity type from level byte map. - * - * @param level Level byte map - * @param x X coordinate - * @param y Y coordinate - * @return EntityType Entity type - */ -EntityType game_get_level_entity(const uint8_t level[], uint8_t x, uint8_t y) -{ - if ((x < 0) || (x >= LEVEL_WIDTH) || (y < 0) || (y >= LEVEL_HEIGHT)) - return E_FLOOR; - - // Y is read in inverse order - uint8_t byte = level[((LEVEL_HEIGHT - 1 - y) * LEVEL_WIDTH + x) / 2]; - byte >>= (x % 2) ? 0 : 4; - - return byte & 0x0f; -} - -/** - * @brief GAME check if an entity with given UID is already spawned. - * - * @param uid Entity UID number - * @return bool Entity is spawned - */ -bool game_is_entity_spawned(EntityUID uid) -{ - for (uint8_t i = 0; i < num_entities; i++) - { - if (entity[i].uid == uid) - return true; - } - - return false; -} - -/** - * @brief GAME check if a static entity with given UID is already spawned. - * - * @param uid Entity UID number - * @return bool Static entity is spawned - */ -bool game_is_static_entity_spawned(EntityUID uid) -{ - for (uint8_t i = 0; i < num_static_entities; i++) - { - if (static_entity[i].uid == uid) - return true; - } - - return false; -} - -/** - * @brief GAME spawn a new entity at a given location. - * - * @param type Entity type - * @param x X coordinate - * @param y Y coordinate - */ -void game_spawn_entity(EntityType type, uint8_t x, uint8_t y) -{ - // Limit the number of spawned entities - if (num_entities >= MAX_ENTITIES) - return; - - /** TODO: Read static entity status */ - - switch (type) - { - case E_ENEMY: - entity[num_entities] = entities_create_enemy(x, y); - num_entities++; - break; - - case E_KEY: - entity[num_entities] = entities_create_key(x, y); - num_entities++; - break; - - case E_MEDKIT: - entity[num_entities] = entities_create_medkit(x, y); - num_entities++; - break; - } -} - -/** - * @brief GAME spawn a fireball at a given location. - * - * @param x X coordinate - * @param y Y coordinate - */ -void game_spawn_fireball(float x, float y) -{ - // Limit the number of spawned entities - if (num_entities >= MAX_ENTITIES) - return; - - // Remove if already exists, don't throw anything. Not the best, - // but shouldn't happen too often - EntityUID uid = entities_get_uid(E_FIREBALL, x, y); - if (game_is_entity_spawned(uid)) - return; - - // Calculate direction. 32 angles - int16_t dir = FIREBALL_ANGLES * - ((atan2f(y - player.pos.y, x - player.pos.x) / PI) + 1); - - if (dir < 0) - dir += FIREBALL_ANGLES * 2; - - entity[num_entities] = entities_create_fireball(x, y, dir); - num_entities++; -} - -/** - * @brief GAME remove an entity. - * - * @param uid Entity UID number - */ -void game_remove_entity(EntityUID uid) -{ - uint8_t i = 0; - bool found = false; - - while (i < num_entities) - { - if (!found && entity[i].uid == uid) - { - found = true; - num_entities--; - } - - if (found) - entity[i] = entity[i + 1]; - - i++; - } -} - -/** - * @brief GAME remove a static entity. - * - * @param uid Entity UID number - */ -void game_remove_static_entity(EntityUID uid) -{ - uint8_t i = 0; - bool found = false; - - while (i < num_static_entities) - { - if (!found && static_entity[i].uid == uid) - { - found = true; - num_static_entities--; - } - - if (found) - static_entity[i] = static_entity[i + 1]; - - i++; - } -} - -/** - * @brief GAME detect collision between entities and level blocks. - * - * @param level Level byte map - * @param pos Position to be checked - * @param rel_x X relative direction - * @param rel_y Y relative direction - * @param only_walls Check only walls collisions - * @return EntityUID Entity UID number - */ -EntityUID game_detect_collision(const uint8_t level[], Coords *pos, float rel_x, - float rel_y, bool only_walls) -{ - // Wall collision - uint8_t round_x = pos->x + rel_x; - uint8_t round_y = pos->y + rel_y; - uint8_t block = game_get_level_entity(level, round_x, round_y); - - if (block == E_WALL) - { - sound_play(hit_wall_snd, HIT_WALL_SND_LEN); - return entities_get_uid(block, round_x, round_y); - } - - if (only_walls) - return UID_NULL; - - // Entity collision - for (uint8_t i = 0; i < num_entities; i++) - { - // Don't collide with itself - if (&(entity[i].pos) == pos) - continue; - - EntityType type = entities_get_type(entity[i].uid); - - // Only ALIVE enemy collision - if ((type != E_ENEMY) || - (entity[i].state == S_DEAD) || - (entity[i].state == S_HIDDEN)) - continue; - - Coords new_coords = {entity[i].pos.x - rel_x, entity[i].pos.y - rel_y}; - uint8_t distance = coords_get_distance(pos, &new_coords); - - // Check distance and if it's getting closer - if ((distance < ENEMY_COLLIDER_DIST) && - (distance < entity[i].distance)) - return entity[i].uid; - } - - return UID_NULL; -} - -/** - * @brief GAME update position if possible, otherwise return collided uid. - * - * @param level Level byte map - * @param pos Position to be checked - * @param rel_x X relative direction - * @param rel_y Y relative direction - * @param only_walls Check only walls collisions - * @return EntityUID Entity UID number - */ -EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, - float rel_y, bool only_walls) -{ - EntityUID collide_x = - game_detect_collision(level, pos, rel_x, 0, only_walls); - EntityUID collide_y = - game_detect_collision(level, pos, 0, rel_y, only_walls); - - if (!collide_x) - pos->x += rel_x; - if (!collide_y) - pos->y += rel_y; - - return (collide_x || collide_y || UID_NULL); -} - -/** - * @brief GAME player fire shootgun and compute damage. - * - */ -void game_fire_shootgun(void) -{ - sound_play(shoot_snd, SHOOT_SND_LEN); - - for (uint8_t i = 0; i < num_entities; i++) - { - // Shoot only ALIVE enemies - if ((entities_get_type(entity[i].uid) != E_ENEMY) || - (entity[i].state == S_DEAD) || - (entity[i].state == S_HIDDEN)) - continue; - - Coords transform = game_translate_into_view(&(entity[i].pos)); - if ((fabsf(transform.x) < 20.0f) && (transform.y > 0.0f)) - { - uint8_t damage = MIN( - GUN_MAX_DAMAGE, - GUN_MAX_DAMAGE / - (fabsf(transform.x) * entity[i].distance) / 5.0f); - if (damage > 0) - { - entity[i].health = MAX(0, entity[i].health - damage); - entity[i].state = S_HIT; - entity[i].timer = 4; - } - } - } -} - -/** - * @brief GAME execute entities AI logic. - * - * @param level Level byte map - */ -void game_update_entities(const uint8_t level[]) -{ - uint8_t i = 0; - while (i < num_entities) - { - // Update distance - entity[i].distance = coords_get_distance( - &(player.pos), &(entity[i].pos)); - - // Run the timer. Works with actual frames. - if (entity[i].timer > 0) - entity[i].timer--; - - // Too far away. put it in doze mode - if (entity[i].distance > MAX_ENTITY_DISTANCE) - { - game_remove_entity(entity[i].uid); - continue; - } - - // Bypass render if hidden - if (entity[i].state == S_HIDDEN) - { - i++; - continue; - } - - EntityType type = entities_get_type(entity[i].uid); - switch (type) - { - case E_ENEMY: - { - // Enemy "IA" - if (entity[i].health == 0) - { - if (entity[i].state != S_DEAD) - { - entity[i].state = S_DEAD; // Entity is dead - entity[i].timer = 6; - } - } - else if (entity[i].state == S_HIT) - { - if (entity[i].timer == 0) - { - entity[i].state = S_ALERT; // Back to alert state - entity[i].timer = 40; // Delay next fireball thrown - } - } - else if (entity[i].state == S_FIRING) - { - if (entity[i].timer == 0) - { - entity[i].state = S_ALERT; // Back to alert state - entity[i].timer = 40; // Delay next fireball thrown - } - } - else - { - if ((entity[i].distance > ENEMY_MELEE_DIST) && - (entity[i].distance < MAX_ENEMY_VIEW)) - { - if (entity[i].state != S_ALERT) - { - entity[i].state = S_ALERT; // Back to alert state - entity[i].timer = 20; // used to throw fireballs - } - else - { - if (entity[i].timer == 0) - { - // Throw a fireball - game_spawn_fireball( - entity[i].pos.x, entity[i].pos.y); - entity[i].state = S_FIRING; - entity[i].timer = 6; - } - else - { - // Move towards to the player - game_update_position( - level, - &(entity[i].pos), - SIGN(player.pos.x, entity[i].pos.x) * - ENEMY_SPEED * delta_time, - SIGN(player.pos.y, entity[i].pos.y) * - ENEMY_SPEED * delta_time, - true); - } - } - } - else if (entity[i].distance <= ENEMY_MELEE_DIST) - { - if (entity[i].state != S_MELEE) - { - // Preparing the melee attack - entity[i].state = S_MELEE; - entity[i].timer = 10; - } - else if (entity[i].timer == 0) - { - // Melee attack - player.health = - MAX(0, player.health - ENEMY_MELEE_DAMAGE); - entity[i].timer = 14; - flash_screen = true; - } - } - else - { - entity[i].state = S_STAND; - } - } - break; - } - - case E_FIREBALL: - { - if (entity[i].distance < FIREBALL_COLLIDER_DIST) - { - // Hit the player and disappear - player.health = - MAX(0, player.health - ENEMY_FIREBALL_DAMAGE); - flash_screen = true; - game_remove_entity(entity[i].uid); - continue; - } - else - { - // Move, only collide with walls. - // Note: using health to store the angle of the movement - EntityUID collided = game_update_position( - level, - &(entity[i].pos), - cosf((float)entity[i].health / FIREBALL_ANGLES * PI) * - FIREBALL_SPEED, - sinf((float)entity[i].health / FIREBALL_ANGLES * PI) * - FIREBALL_SPEED, - true); - - if (collided) - { - game_remove_entity(entity[i].uid); - continue; - } - } - break; - } - - case E_MEDKIT: - { - if (entity[i].distance < ITEM_COLLIDER_DIST) - { - // Pickup - sound_play(medkit_snd, MEDKIT_SND_LEN); - entity[i].state = S_HIDDEN; - player.health = MIN(100, player.health + 50); - flash_screen = true; - } - break; - } - - case E_KEY: - { - if (entity[i].distance < ITEM_COLLIDER_DIST) - { - // Pickup - sound_play(get_key_snd, GET_KEY_SND_LEN); - entity[i].state = S_HIDDEN; - player.keys++; - flash_screen = true; - } - break; - } - } - - i++; - } -} - -/** - * @brief GAME render map with raycasting technique. - * NOTE: Based on https://lodev.org/cgtutor/raycasting.html - * - * @param level Level byte map - * @param view_height View height of the camera - */ -void game_render_map(const uint8_t level[], float view_height) -{ - EntityUID last_uid; - - for (uint8_t x = 0; x < SCREEN_WIDTH; x += RES_DIVIDER) - { - float camera_x = 2 * (float)x / SCREEN_WIDTH - 1; - float ray_x = player.dir.x + player.plane.x * camera_x; - float ray_y = player.dir.y + player.plane.y * camera_x; - uint8_t map_x = (uint8_t)(player.pos.x); - uint8_t map_y = (uint8_t)(player.pos.y); - Coords map_coords = {player.pos.x, player.pos.y}; - float delta_x = fabsf(1 / ray_x); - float delta_y = fabsf(1 / ray_y); - - int8_t step_x; - int8_t step_y; - float side_x; - float side_y; - - if (ray_x < 0) - { - step_x = -1; - side_x = (player.pos.x - map_x) * delta_x; - } - else - { - step_x = 1; - side_x = (map_x + 1.0 - player.pos.x) * delta_x; - } - - if (ray_y < 0) - { - step_y = -1; - side_y = (player.pos.y - map_y) * delta_y; - } - else - { - step_y = 1; - side_y = (map_y + 1.0 - player.pos.y) * delta_y; - } - - // Wall detection - uint8_t depth = 0; - bool hit = false; - bool side; - while (!hit && (depth < MAX_RENDER_DEPTH)) - { - if (side_x < side_y) - { - side_x += delta_x; - map_x += step_x; - side = false; - } - else - { - side_y += delta_y; - map_y += step_y; - side = true; - } - - uint8_t block = game_get_level_entity(level, map_x, map_y); - - if (block == E_WALL) - hit = true; - else - { - // Spawning entities here, as soon they are visible for the - // player. Not the best place, but would be a very performance - // cost scan for them in another loop - if ((block == E_ENEMY) || (block & 0b00001000)) - { - // Check that it's close to the player - if (coords_get_distance(&(player.pos), &map_coords) < - MAX_ENTITY_DISTANCE) - { - EntityUID uid = entities_get_uid(block, map_x, map_y); - if (last_uid != uid && !game_is_entity_spawned(uid)) - { - game_spawn_entity(block, map_x, map_y); - last_uid = uid; - } - } - } - } - - depth++; - } - - if (hit) - { - float distance; - if (!side) - distance = - MAX(1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); - else - distance = - MAX(1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); - - // store zbuffer value for the column - zbuffer[x / Z_RES_DIVIDER] = - MIN(distance * DISTANCE_MULTIPLIER, 0xff); - - // rendered line height - uint8_t line_height = RENDER_HEIGHT / distance; - - display_draw_vline( - x, - view_height / distance - line_height / 2 + RENDER_HEIGHT / 2, - view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, - GRADIENT_COUNT - (side * 2) - - (distance / MAX_RENDER_DEPTH * GRADIENT_COUNT)); - } - } -} - -/** - * @brief GAME sort entities from far to close. - * - */ -void game_sort_entities(void) -{ - uint8_t gap = num_entities; - bool swapped = false; - while ((gap > 1) || (swapped)) - { - // shrink factor 1.3 - gap = (gap * 10) / 13; - if ((gap == 9) || (gap == 10)) - gap = 11; - if (gap < 1) - gap = 1; - - swapped = false; - for (uint8_t i = 0; i < num_entities - gap; i++) - { - uint8_t j = i + gap; - if (entity[i].distance < entity[j].distance) - { - SWAP(entity[i], entity[j]); - swapped = true; - } - } - } -} - -/** - * @brief GAME translate 2D map coordinates into camera coordinates. - * - * @param pos 2D map coordinates - * @return Coords Camera coordinates - */ -Coords game_translate_into_view(Coords *pos) -{ - // Translate sprite position to relative to camera - float sprite_x = pos->x - player.pos.x; - float sprite_y = pos->y - player.pos.y; - - // Required for correct matrix multiplication - float inv_det = - 1.0f / (player.plane.x * player.dir.y - player.dir.x * player.plane.y); - float transform_x = - inv_det * (player.dir.y * sprite_x - player.dir.x * sprite_y); - float transform_y = - inv_det * (-player.plane.y * sprite_x + player.plane.x * sprite_y); - - return (Coords){transform_x, transform_y}; -} - -/** - * @brief GAME render entities sprites. - * - * @param view_height View height of the camera - */ -void game_render_entities(float view_height) -{ - game_sort_entities(); - - for (uint8_t i = 0; i < num_entities; i++) - { - if (entity[i].state == S_HIDDEN) - continue; - - Coords transform = game_translate_into_view(&(entity[i].pos)); - - // don´t render if behind the player or too far away - if ((transform.y <= 0.1f) || (transform.y > MAX_SPRITE_DEPTH)) - continue; - - int16_t sprite_screen_x = - HALF_WIDTH * (1.0f + (transform.x / transform.y)); - int8_t sprite_screen_y = - (RENDER_HEIGHT / 2) + (view_height / transform.y); - - // Don't try to render if outside of screen - // doing this pre-shortcut due int16 -> int8 conversion - // makes out-of-screen values fit into the screen space - if ((sprite_screen_x < -HALF_WIDTH) || - (sprite_screen_x > SCREEN_WIDTH + HALF_WIDTH)) - continue; - - switch (entities_get_type(entity[i].uid)) - { - case E_ENEMY: - { - uint8_t sprite; - if (entity[i].state == S_ALERT) - sprite = (platform_millis() / 500) % 2; // Walking - else if (entity[i].state == S_FIRING) - sprite = 2; // Fireball - else if (entity[i].state == S_HIT) - sprite = 3; // Hit - else if (entity[i].state == S_MELEE) - sprite = entity[i].timer > 10 ? 2 : 1; // Melee atack - else if (entity[i].state == S_DEAD) - sprite = entity[i].timer > 0 ? 3 : 4; // Dying - else - sprite = 0; // Stand - - display_draw_sprite( - sprite_screen_x - BMP_IMP_WIDTH * 0.5f / transform.y, - sprite_screen_y - 8 / transform.y, bmp_imp_bits, - bmp_imp_mask, - BMP_IMP_WIDTH, - BMP_IMP_HEIGHT, - sprite, - transform.y); - break; - } - - case E_FIREBALL: - { - display_draw_sprite( - sprite_screen_x - BMP_FIREBALL_WIDTH / 2 / transform.y, - sprite_screen_y - BMP_FIREBALL_HEIGHT / 2 / transform.y, - bmp_fireball_bits, - bmp_fireball_mask, - BMP_FIREBALL_WIDTH, - BMP_FIREBALL_HEIGHT, - 0, - transform.y); - break; - } - - case E_MEDKIT: - { - display_draw_sprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, - bmp_items_bits, - bmp_items_mask, - BMP_ITEMS_WIDTH, - BMP_ITEMS_HEIGHT, - 0, - transform.y); - break; - } - - case E_KEY: - { - display_draw_sprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, - bmp_items_bits, - bmp_items_mask, - BMP_ITEMS_WIDTH, - BMP_ITEMS_HEIGHT, - 1, - transform.y); - break; - } - } - } -} - -/** - * @brief GAME render player gun sprite. - * - * @param gun_pos Gun cyclic position - * @param jogging Player jogging speed - */ -void game_render_gun(uint8_t gun_pos, float jogging) -{ - // jogging - uint8_t x = 48 + sinf(platform_millis() * JOGGING_SPEED) * 10 * jogging; - uint8_t y = RENDER_HEIGHT - gun_pos + - fabsf(cosf(platform_millis() * JOGGING_SPEED)) * 8 * jogging; - - // Gun fire - if (gun_pos > GUN_SHOT_POS - 2) - display_draw_bitmap(x + 6, y - 11, bmp_fire_bits, BMP_FIRE_WIDTH, - BMP_FIRE_HEIGHT, true); - - // Don't draw over the hud - uint8_t clip_height = MAX(0, MIN(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); - - // Draw the gun (black mask + actual sprite) - display_draw_bitmap(x, y, bmp_gun_mask, BMP_GUN_WIDTH, clip_height, false); - display_draw_bitmap(x, y, bmp_gun_bits, BMP_GUN_WIDTH, clip_height, true); -} - -/** - * @brief GAME render heads-up display (HUD). - * - */ -void game_render_hud(void) -{ - // Clear HUD - display_draw_rect(0, RENDER_HEIGHT, SCREEN_WIDTH, HUD_HEIGHT, false); - - // Draw HUD symbols - display_draw_text(2, RENDER_HEIGHT, "{}", false); - display_draw_text(40, RENDER_HEIGHT, "[]", false); - - // Update stats - display_draw_int(12, RENDER_HEIGHT, player.health); - display_draw_int(50, RENDER_HEIGHT, player.keys); - display_draw_int(114, RENDER_HEIGHT, (uint8_t)(display_get_fps())); - display_draw_int(82, RENDER_HEIGHT, num_entities); -} - -/** - * @brief GAME run intro scene. - * - */ -void game_run_intro_scene(void) -{ - display_draw_bitmap( - (SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, - (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, - bmp_logo_bits, - BMP_LOGO_WIDTH, - BMP_LOGO_HEIGHT, - true); - - display_draw_text( - SCREEN_WIDTH / 2 - 25, - SCREEN_HEIGHT * 0.8f, - "PRESS FIRE", - true); - - if (input_fire()) - game_jump_to_scene(SCENE_LEVEL1); -} - -/** - * @brief GAME run level scene. - * - */ -void game_run_level_scene(void) -{ - static bool gun_fired; - static uint8_t gun_pos; - static float rot_speed; - static float old_dir_x; - static float old_plane_x; - static float view_height; - static float jogging; - - // If the player is alive - if (player.health > 0) - { - // Player speed - if (input_up()) - { - player.velocity += (MOV_SPEED - player.velocity) * 0.4f; - jogging = fabsf(player.velocity) * MOV_SPEED_INV; - } - else if (input_down()) - { - player.velocity -= (MOV_SPEED + player.velocity) * 0.4f; - jogging = fabsf(player.velocity) * MOV_SPEED_INV; - } - else - { - player.velocity *= 0.5f; - jogging = fabsf(player.velocity) * MOV_SPEED_INV; - } - - // Player rotation - if (input_right()) - { - rot_speed = ROT_SPEED * delta_time; - old_dir_x = player.dir.x; - player.dir.x = player.dir.x * cosf(-rot_speed) - - player.dir.y * sinf(-rot_speed); - player.dir.y = old_dir_x * sinf(-rot_speed) + - player.dir.y * cosf(-rot_speed); - old_plane_x = player.plane.x; - player.plane.x = player.plane.x * cosf(-rot_speed) - - player.plane.y * sinf(-rot_speed); - player.plane.y = old_plane_x * sinf(-rot_speed) + - player.plane.y * cosf(-rot_speed); - } - else if (input_left()) - { - rot_speed = ROT_SPEED * delta_time; - old_dir_x = player.dir.x; - player.dir.x = player.dir.x * cosf(rot_speed) - - player.dir.y * sinf(rot_speed); - player.dir.y = old_dir_x * sinf(rot_speed) + - player.dir.y * cosf(rot_speed); - old_plane_x = player.plane.x; - player.plane.x = player.plane.x * cosf(rot_speed) - - player.plane.y * sinf(rot_speed); - player.plane.y = old_plane_x * sinf(rot_speed) + - player.plane.y * cosf(rot_speed); - } - - view_height = - fabsf(sinf(platform_millis() * JOGGING_SPEED)) * 6.0f * jogging; - - if (view_height > 5.9f) - { - if (walk_sound_toggle) - { - sound_play(walk1_snd, WALK1_SND_LEN); - walk_sound_toggle = false; - } - else - { - sound_play(walk2_snd, WALK2_SND_LEN); - walk_sound_toggle = true; - } - } - - // Update gun - if (gun_pos > GUN_TARGET_POS) - { - // Right after fire - gun_pos -= 1; - } - else if (gun_pos < GUN_TARGET_POS) - { - // Showing up - gun_pos += 2; - } - else if (!gun_fired && input_fire()) - { - // Ready to fire and fire pressed - gun_pos = GUN_SHOT_POS; - gun_fired = true; - game_fire_shootgun(); - } - else if (gun_fired && !input_fire()) - { - // Just fired and restored position - gun_fired = false; - } - - // Update player - game_update_position( - level_1, - &(player.pos), - player.dir.x * player.velocity * delta_time, - player.dir.y * player.velocity * delta_time, - false); - - // Update entities - game_update_entities(level_1); - } - else - { - // The player is dead - if (view_height > -10.0f) - view_height--; - else if (input_fire()) - game_jump_to_scene(SCENE_INTRO); - - if (gun_pos > 1) - gun_pos -= 2; - } - - // Render stuff - game_render_map(level_1, view_height); - game_render_entities(view_height); - game_render_gun(gun_pos, jogging); - - // Fade in effect - if (fade_screen > 0) - { - display_fade(fade_screen, false); - fade_screen--; - return; - } - game_render_hud(); - - // Flash screen - if (flash_screen) - { - display_invert(); - flash_screen = false; - } - - // Exit routine - if (input_exit()) - game_jump_to_scene(SCENE_INTRO); -} - -/** - * @brief GAME main function. - * - */ -void main(void) -{ - /* Initialize game */ - platform_init(); - display_init(); - sound_init(); - input_init(); - game_run_scene = game_run_intro_scene; - - while (!input_exit()) - { - /* Start drawing */ - display_draw_start(); - - /* Read user inputs */ - input_update(); - - /* Run current game scene */ - game_run_scene(); - - /* Stop drawing */ - display_draw_stop(); - } -} - -/* -------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/src/sound.c b/src/sound.c index a32264b..c6e3c54 100644 --- a/src/sound.c +++ b/src/sound.c @@ -13,6 +13,9 @@ static uint8_t sound_len; static uint8_t sound_idx; static uint32_t sound_t0; +extern bool sound; +extern uint8_t music; + /* Function definitions ----------------------------------------------------- */ /** @@ -23,6 +26,9 @@ void sound_init(void) { sound_ptr = NULL; sound_len = 0; + + sound = false; + music = 0; } /** From 45e0cb07fadc75c823470c82743152673af7b7fa Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sat, 22 Jul 2023 18:18:10 +0200 Subject: [PATCH 05/18] fix all warnings Signed-off-by: Lorenzo Gualniera --- inc/constants.h | 64 ++++++++++++++++++++++++++----------------------- inc/display.h | 2 -- src/display.c | 2 +- src/game.c | 17 ++++++------- 4 files changed, 44 insertions(+), 41 deletions(-) diff --git a/inc/constants.h b/inc/constants.h index b65f8f0..dc5ac95 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -8,6 +8,28 @@ /* Frame rate */ #define FPS 15 #define FRAME_TIME (1000.0f / FPS) + +/* Higher values will result in lower horizontal resolution when rasterize and + * lower process and memory usage. Lower will require more process and memory, + * but looks nicer. */ +#define RES_DIVIDER 2 + +/* Zbuffer resolution divider. We sacrifice resolution to save memory. */ +#define Z_RES_DIVIDER 2 + +/* Distances are stored as uint8_t, multiplying the distance we can obtain more + * precision taking care of keep numbers inside the type range. + * Max is 256 / MAX_RENDER_DEPTH */ +#define DISTANCE_MULTIPLIER 20 +#define MAX_RENDER_DEPTH 12 +#define MAX_SPRITE_DEPTH 8 + +/* Faster rendering of vertical lines */ +#define OPTIMIZE_RAYCASTING 1 + +/* Depth buffer for sprites */ +#define ZBUFFER_SIZE ((SCREEN_WIDTH / Z_RES_DIVIDER) + 4) + /* Display */ #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 @@ -16,40 +38,22 @@ #define RENDER_HEIGHT 58 // Raycaster working height #define HUD_HEIGHT 6 // HUD working height -#define RES_DIVIDER 2 // Higher values will result in lower horizontal resolution when rasterize and lower process and memory usage - // Lower will require more process and memory, but looks nicer -#define Z_RES_DIVIDER 2 // Zbuffer resolution divider. We sacrifice resolution to save memory -#define DISTANCE_MULTIPLIER 20 // Distances are stored as uint8_t, multiplying the distance we can obtain more precision taking care - // of keep numbers inside the type range. Max is 256 / MAX_RENDER_DEPTH -#define MAX_RENDER_DEPTH 12 -#define MAX_SPRITE_DEPTH 8 - -#define ZBUFFER_SIZE SCREEN_WIDTH / Z_RES_DIVIDER + 4 - -// Level +/* Level */ #define LEVEL_WIDTH_BASE 6 #define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) #define LEVEL_HEIGHT 57 -#define LEVEL_SIZE LEVEL_WIDTH / 2 * LEVEL_HEIGHT - -// scenes -#define INTRO 0 -#define GAME_PLAY 1 -#define DIFF 2 -#define MUS 3 -#define MID 4 -#define SCORE 5 -// Game -#define GUN_TARGET_POS 18 -#define GUN_SHOT_POS GUN_TARGET_POS + 8 +#define LEVEL_SIZE ((LEVEL_WIDTH / 2) * LEVEL_HEIGHT) -#define ROT_SPEED .12 -#define MOV_SPEED .1 -#define MOV_SPEED_INV 2.5 // 1 / MOV_SPEED +/* Game */ +#define GUN_TARGET_POS 18 +#define GUN_SHOT_POS (GUN_TARGET_POS + 8) -#define JOGGING_SPEED .005 -#define ENEMY_SPEED .04 -#define FIREBALL_SPEED .2 +#define ROT_SPEED 0.12f +#define MOV_SPEED 0.1f +#define GUN_SPEED 2.5f +#define JOGGING_SPEED 0.005f +#define ENEMY_SPEED 0.04f +#define FIREBALL_SPEED 0.2f #define FIREBALL_ANGLES 45 // Num of angles per PI #define MAX_ENTITIES 12 // Max num of active entities @@ -61,7 +65,7 @@ #define ENEMY_COLLIDER_DIST 4 // * DISTANCE_MULTIPLIER #define FIREBALL_COLLIDER_DIST 3 // * DISTANCE_MULTIPLIER #define ENEMY_MELEE_DIST 9 // * DISTANCE_MULTIPLIER -#define WALL_COLLIDER_DIST .2 +#define WALL_COLLIDER_DIST 0.2f #define ENEMY_MELEE_DAMAGE 18 #define ENEMY_FIREBALL_DAMAGE 25 diff --git a/inc/display.h b/inc/display.h index 60465cc..5a05553 100644 --- a/inc/display.h +++ b/inc/display.h @@ -12,8 +12,6 @@ /* Definitions -------------------------------------------------------------- */ -#define OPTIMIZE_DISPLAY -#define ZBUFFER_SIZE (SCREEN_WIDTH / Z_RES_DIVIDER) #define DISPLAY_BUF_SIZE (SCREEN_WIDTH * ((SCREEN_HEIGHT + 7) / 8)) /* Function prototypes ------------------------------------------------------ */ diff --git a/src/display.c b/src/display.c index 522ccc7..cf14e7d 100644 --- a/src/display.c +++ b/src/display.c @@ -255,7 +255,7 @@ void display_draw_vline(uint8_t x, int8_t start_y, int8_t end_y, uint8_t i) int8_t lower_y = MAX(MIN(start_y, end_y), 0); int8_t higher_y = MIN(MAX(start_y, end_y), RENDER_HEIGHT - 1); -#ifdef OPTIMIZE_DISPLAY +#if OPTIMIZE_RAYCASTING for (uint8_t c = 0; c < RES_DIVIDER; c++) { uint8_t bp; diff --git a/src/game.c b/src/game.c index 64e7834..2c04890 100644 --- a/src/game.c +++ b/src/game.c @@ -1,5 +1,6 @@ /* Includes ----------------------------------------------------------------- */ +#include #include #include #include @@ -105,7 +106,6 @@ static uint8_t num_static_entities = 0; static uint8_t x = 0; static uint8_t enemyCount = 0; static uint8_t del = 0; -static uint8_t *game_level = E1M1; static uint8_t enemyGoal = 20; static bool fade_e = true; static bool debug = false; @@ -127,6 +127,7 @@ static float view_height; static float jogging; static uint8_t fade_screen = GRADIENT_COUNT - 1; +static const uint8_t *game_level = E1M1; static void (*game_run_scene)(void); // Jump to another scene @@ -1062,8 +1063,8 @@ void game_render_entities(float view_height) void game_render_gun(uint8_t gun_pos, float amount_jogging, bool gun_fired, uint8_t r1) { // jogging - char x = 48 + sinf((float)platform_millis() * JOGGING_SPEED) * 10 * amount_jogging - 9; - char y = RENDER_HEIGHT - gun_pos + fabsf(cosf((float)platform_millis() * JOGGING_SPEED)) * 8 * amount_jogging - 3; + int8_t x = 48 + sinf((float)platform_millis() * JOGGING_SPEED) * 10 * amount_jogging - 9; + int8_t y = RENDER_HEIGHT - gun_pos + fabsf(cosf((float)platform_millis() * JOGGING_SPEED)) * 8 * amount_jogging - 3; uint8_t clip_height = MAX(0, MIN(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); if (gun_pos > GUN_SHOT_POS - 2) { @@ -1606,13 +1607,13 @@ void game_run_level_scene(void) } else { - jogging = fabsf(player.velocity) * MOV_SPEED_INV * 2; + jogging = fabsf(player.velocity) * GUN_SPEED * 2; } } else if (input_down()) { - jogging = fabsf(player.velocity) * MOV_SPEED_INV * 2; + jogging = fabsf(player.velocity) * GUN_SPEED * 2; player.velocity += (-MOV_SPEED - player.velocity) * .4; if (jump == 1 || jump == 2) { @@ -1621,7 +1622,7 @@ void game_run_level_scene(void) } else { - jogging = fabsf(player.velocity) * MOV_SPEED_INV * 2; + jogging = fabsf(player.velocity) * GUN_SPEED * 2; } } else @@ -1633,7 +1634,7 @@ void game_run_level_scene(void) } else { - jogging = fabsf(player.velocity) * MOV_SPEED_INV * 2; + jogging = fabsf(player.velocity) * GUN_SPEED * 2; } player.velocity *= .5; } @@ -1763,7 +1764,7 @@ void game_run_level_scene(void) else if (input_fire()) { - game_jump_to_scene(INTRO); + game_jump_to_scene(SCENE_INTRO); } if (gun_pos > 0) gun_pos -= 2; From d916228c23d5357105557fc6e55e592c62b78e8b Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sat, 22 Jul 2023 19:52:47 +0200 Subject: [PATCH 06/18] start refactoring of doom nano brutality main Signed-off-by: Lorenzo Gualniera --- inc/sprites.h | 2 - src/game.c | 823 ++++++++++++++++++++++++++++---------------------- 2 files changed, 461 insertions(+), 364 deletions(-) diff --git a/inc/sprites.h b/inc/sprites.h index 419c586..ee29acf 100644 --- a/inc/sprites.h +++ b/inc/sprites.h @@ -377,8 +377,6 @@ static const uint8_t bmp_items_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}; -// Gradient for lighting. -// Note: Width and height are in bytes #define GRADIENT_WIDTH 2 #define GRADIENT_HEIGHT 8 #define GRADIENT_COUNT 8 diff --git a/src/game.c b/src/game.c index 2c04890..7f743a3 100644 --- a/src/game.c +++ b/src/game.c @@ -1,11 +1,11 @@ /* Includes ----------------------------------------------------------------- */ -#include -#include -#include +#include #include +#include +#include +#include #include -#include #include #include "constants.h" @@ -20,18 +20,17 @@ #include "utils.h" /** TODO: verify if using pointers instead of returning struct is faster */ -/** TODO: integrate doom brutality expansion */ /* Data types --------------------------------------------------------------- */ typedef enum { SCENE_INTRO, - SCENE_SCORE, - SCENE_MUSIC, SCENE_DIFFICULTY, + SCENE_MUSIC, + SCENE_STORY, SCENE_LEVEL, - SCENE_STORY + SCENE_SCORE } GameScene; /* Function prototypes ------------------------------------------------------ */ @@ -48,6 +47,7 @@ static void game_spawn_entity(EntityType type, uint8_t x, uint8_t y); static void game_spawn_fireball(float x, float y); static void game_remove_entity(EntityUID uid); static void game_remove_static_entity(EntityUID uid); +static void game_clear_dead_enemy(void); static void game_update_entities(const uint8_t level[]); static void game_sort_entities(void); @@ -64,73 +64,79 @@ static void game_fire_shootgun(void); static Coords game_translate_into_view(Coords *pos); static void game_render_map(const uint8_t level[], float view_height); static void game_render_entities(float view_height); -void game_render_gun(uint8_t gun_pos, float amount_jogging, bool gun_fired, uint8_t r1); +static void game_render_gun(uint8_t pos, float jogging, bool fired, + uint8_t reload); static void game_render_hud(void); /* Scenes */ static void game_jump_to_scene(GameScene scene); static void game_run_intro_scene(void); -static void game_run_story_scene(void); +static void game_run_difficulty_scene(void); static void game_run_music_scene(void); +static void game_run_story_scene(void); static void game_run_level_scene(void); -static void game_run_difficulty_scene(void); static void game_run_score_scene(void); - -void updateHud(void); // temporary +void updateHud(void); /** TODO: merge with render HUD */ /* Global variables --------------------------------------------------------- */ -static bool exit_scene = false; -static bool invert_screen = false; -static bool flash_screen = false; static uint8_t z = 6; -static bool coll = 0; +static bool coll = false; static uint8_t jump = 0; static uint8_t jump_height = 0; static uint8_t vel = 1; -static uint8_t difficulty = 1; +static uint8_t game_difficulty = 1; static uint8_t noclip = 0; static bool m = true; static uint8_t rc1 = 0; static int16_t a = 0; -static uint8_t enemyCount2 = 0; -static uint8_t enemyGoal2 = 8; +static uint8_t enemy_count2 = 0; +static uint8_t enemy_goal2 = 8; // game // player and entities static Player player; static Entity entity[MAX_ENTITIES]; -static StaticEntity static_entity[MAX_STATIC_ENTITIES]; static uint8_t num_entities = 0; +static StaticEntity static_entity[MAX_STATIC_ENTITIES]; static uint8_t num_static_entities = 0; + static uint8_t x = 0; -static uint8_t enemyCount = 0; static uint8_t del = 0; -static uint8_t enemyGoal = 20; +static uint8_t enemy_count = 0; +static uint8_t enemy_goal = 20; static bool fade_e = true; static bool debug = false; static uint8_t r = 0; static bool reload1 = false; -static int16_t score; +static int16_t game_score; static uint8_t k; static int8_t mid = 1; static bool bss = false; static bool mc = false; // init static bool gun_fired = false; -static bool walkSoundToggle = false; +static bool walk_sound_toggle = false; static uint8_t gun_pos = 0; static float rot_speed; static float old_dir_x; static float old_plane_x; static float view_height; static float jogging; + +static bool flash_screen = false; static uint8_t fade_screen = GRADIENT_COUNT - 1; static const uint8_t *game_level = E1M1; static void (*game_run_scene)(void); -// Jump to another scene +/* Function definitions ----------------------------------------------------- */ + +/** + * @brief GAME jump to another scene at the end of the current frame. + * + * @param scene Game scene + */ void game_jump_to_scene(GameScene scene) { switch (scene) @@ -166,11 +172,16 @@ void game_jump_to_scene(GameScene scene) } } -// Finds the player in the map +/** + * @brief GAME initialize level state. + * + * @param level Level byte map + */ void game_init_level_scene(const uint8_t level[]) { + /** TODO: move this stuff somewhere else */ gun_fired = false; - walkSoundToggle = false; + walk_sound_toggle = false; gun_pos = 0; rot_speed; old_dir_x; @@ -180,8 +191,18 @@ void game_init_level_scene(const uint8_t level[]) fade_screen = GRADIENT_COUNT - 1; mc = false; - // Initialize game scene callback - game_run_scene = game_run_intro_scene; + // Initialize game entities + memset(entity, 0x00, sizeof(Entity) * MAX_ENTITIES); + memset(static_entity, 0x00, sizeof(StaticEntity) * MAX_STATIC_ENTITIES); + num_entities = 0; + num_static_entities = 0; + + // Initialize screen effects + flash_screen = false; + fade_screen = GRADIENT_COUNT - 1; + + // Initialize audio effects + walk_sound_toggle = false; // Find player in the map and create instance for (uint8_t y = LEVEL_HEIGHT - 1; y >= 0; y--) @@ -201,6 +222,14 @@ void game_init_level_scene(const uint8_t level[]) } } +/** + * @brief GAME get entity type from level byte map. + * + * @param level Level byte map + * @param x X coordinate + * @param y Y coordinate + * @return EntityType Entity type + */ EntityType game_get_level_entity(const uint8_t level[], uint8_t x, uint8_t y) { if ((x < 0) || (x >= LEVEL_WIDTH) || (y < 0) || (y >= LEVEL_HEIGHT)) @@ -213,6 +242,12 @@ EntityType game_get_level_entity(const uint8_t level[], uint8_t x, uint8_t y) return byte & 0x0f; } +/** + * @brief GAME check if an entity with given UID is already spawned. + * + * @param uid Entity UID number + * @return bool Entity is spawned + */ bool game_is_entity_spawned(EntityUID uid) { for (uint8_t i = 0; i < num_entities; i++) @@ -224,6 +259,12 @@ bool game_is_entity_spawned(EntityUID uid) return false; } +/** + * @brief GAME check if a static entity with given UID is already spawned. + * + * @param uid Entity UID number + * @return bool Static entity is spawned + */ bool game_is_static_entity_spawned(EntityUID uid) { for (uint8_t i = 0; i < num_static_entities; i++) @@ -235,6 +276,13 @@ bool game_is_static_entity_spawned(EntityUID uid) return false; } +/** + * @brief GAME spawn a new entity at a given location. + * + * @param type Entity type + * @param x X coordinate + * @param y Y coordinate + */ void game_spawn_entity(EntityType type, uint8_t x, uint8_t y) { // Limit the number of spawned entities @@ -262,15 +310,21 @@ void game_spawn_entity(EntityType type, uint8_t x, uint8_t y) } } +/** + * @brief GAME spawn a fireball at a given location. + * + * @param x X coordinate + * @param y Y coordinate + */ void game_spawn_fireball(float x, float y) { // Limit the number of spawned entities if (num_entities >= MAX_ENTITIES) return; - // Remove if already exists, don't throw anything. Not the best, - // but shouldn't happen too often - EntityUID uid = entities_get_uid(E_FIREBALL, x, y); + // Remove if already exists, don't throw anything + // Not the best, but shouldn't happen too often + EntityUID uid = entities_get_uid(E_FIREBALL, (uint8_t)x, (uint8_t)y); if (game_is_entity_spawned(uid)) return; @@ -285,6 +339,11 @@ void game_spawn_fireball(float x, float y) num_entities++; } +/** + * @brief GAME remove an entity. + * + * @param uid Entity UID number + */ void game_remove_entity(EntityUID uid) { uint8_t i = 0; @@ -305,33 +364,11 @@ void game_remove_entity(EntityUID uid) } } -void clearEntities(void) -{ - uint8_t i = num_entities; - bool found; - while (found == false) - { - i--; - if (entity[i].state != S_DEAD && entities_get_type(entity[i].uid) != E_ENEMY) - { - found = true; - } - } - i--; - while (entity[i].state != S_DEAD && entities_get_type(entity[i].uid) != E_ENEMY && found == true) - { - i--; - if (i == 0) - { - break; - } - } - if (i > 0 && entity[i].state == S_DEAD) - { - game_remove_entity(entity[i].uid); - } -} - +/** + * @brief GAME remove a static entity. + * + * @param uid Entity UID number + */ void game_remove_static_entity(EntityUID uid) { uint8_t i = 0; @@ -352,6 +389,35 @@ void game_remove_static_entity(EntityUID uid) } } +/** + * @brief GAME clear farthest dead enemy entity. + * + */ +void game_clear_dead_enemy(void) +{ + uint8_t i = num_entities - 1; + while (i >= 0) + { + EntityType type = entities_get_type(entity[i].uid); + if ((type == E_ENEMY) && (entity[i].state == S_DEAD)) + { + game_remove_entity(entity[i].uid); + return; + } + i--; + } +} + +/** + * @brief GAME detect collision between entities and level blocks. + * + * @param level Level byte map + * @param pos Position to be checked + * @param rel_x X relative direction + * @param rel_y Y relative direction + * @param only_walls Check only walls collisions + * @return EntityUID Entity UID number + */ EntityUID game_detect_collision(const uint8_t level[], Coords *pos, float rel_x, float rel_y, bool only_walls) { @@ -417,7 +483,36 @@ EntityUID game_detect_collision(const uint8_t level[], Coords *pos, float rel_x, return UID_NULL; } -// Shoot +/** + * @brief GAME update position if possible, otherwise return collided uid. + * + * @param level Level byte map + * @param pos Position to be checked + * @param rel_x X relative direction + * @param rel_y Y relative direction + * @param only_walls Check only walls collisions + * @return EntityUID Entity UID number + */ +EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, + float rel_y, bool only_walls) +{ + EntityUID collide_x = + game_detect_collision(level, pos, rel_x, 0.0f, only_walls); + EntityUID collide_y = + game_detect_collision(level, pos, 0.0f, rel_y, only_walls); + + if (!collide_x) + pos->x += rel_x; + if (!collide_y) + pos->y += rel_y; + + return (collide_x || collide_y || UID_NULL); +} + +/** + * @brief GAME player fire shootgun and compute damage. + * + */ void game_fire_shootgun(void) { if (player.keys != 0) @@ -427,33 +522,36 @@ void game_fire_shootgun(void) for (uint8_t i = 0; i < num_entities; i++) { // Shoot only ALIVE enemies - if (entities_get_type(entity[i].uid) != E_ENEMY || entity[i].state == S_DEAD || entity[i].state == S_HIDDEN) - { + if ((entities_get_type(entity[i].uid) != E_ENEMY) || + (entity[i].state == S_DEAD) || + (entity[i].state == S_HIDDEN)) continue; - } + Coords transform = game_translate_into_view(&(entity[i].pos)); - if (fabsf(transform.x) < 20 && transform.y > 0) + if ((fabsf(transform.x) < 20.0f) && (transform.y > 0)) { - uint8_t damage = MIN(GUN_MAX_DAMAGE, GUN_MAX_DAMAGE / (fabsf(transform.x) * entity[i].distance) / 5); - if (jump == 1 || jump == 2) - { + uint8_t damage = MIN( + GUN_MAX_DAMAGE, + GUN_MAX_DAMAGE / + (fabsf(transform.x) * entity[i].distance) / 5.0f); + + if ((jump == 1) || (jump == 2)) damage = damage / 3; - } - if (difficulty == 1) - { - damage = damage * 1.5; - } - else if (difficulty == 2) - { + + /** TODO: check if difficulty is easy->1, medium->2 etc..*/ + if (game_difficulty == 1) + damage *= 1.5f; + else if (game_difficulty == 2) damage = damage; - } else - { - damage = damage * 0.70; - } + damage *= 0.7f; + if (damage > 0) { - entity[i].health = MAX(0, entity[i].health - damage / difficulty); + /** TODO: change this equation so that game difficulty only + * appears in damage calculation + */ + entity[i].health = MAX(0, entity[i].health - damage / game_difficulty); entity[i].state = S_HIT; entity[i].timer = 2; } @@ -469,33 +567,32 @@ void game_fire_shootgun(void) if (entity[i].distance <= ENEMY_MELEE_DIST) { // Shoot only ALIVE enemies - if (entities_get_type(entity[i].uid) != E_ENEMY || entity[i].state == S_DEAD || entity[i].state == S_HIDDEN) - { + if ((entities_get_type(entity[i].uid) != E_ENEMY) || + (entity[i].state == S_DEAD) || + (entity[i].state == S_HIDDEN)) continue; - } + Coords transform = game_translate_into_view(&(entity[i].pos)); if (fabsf(transform.x) < 20 && transform.y > 0) { - uint8_t damage = MIN(GUN_MAX_DAMAGE, GUN_MAX_DAMAGE / (fabsf(transform.x) * entity[i].distance) / 5); - if (jump == 1 || jump == 2) - { + uint8_t damage = MIN( + GUN_MAX_DAMAGE, + GUN_MAX_DAMAGE / + (fabsf(transform.x) * entity[i].distance) / 5); + + /** TODO: why is it different now? cut down duplication */ + if ((jump == 1) || (jump == 2)) damage = damage / 3; - } - if (difficulty == 1) - { + if (game_difficulty == 1) damage = damage + damage / 4.0; - } - else if (difficulty == 2) - { + else if (game_difficulty == 2) damage = damage - damage * 0.1; - } else - { damage = damage * 0.60; - } + if (damage > 0) { - entity[i].health = MAX(0, entity[i].health - damage / difficulty); + entity[i].health = MAX(0, entity[i].health - damage / game_difficulty); entity[i].state = S_HIT; entity[i].timer = 2; } @@ -504,26 +601,10 @@ void game_fire_shootgun(void) } } + /** TODO: move all rendering to the end of the scene not in the middle */ updateHud(); } -// Update coords if possible. Return the collided uid, if any -EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, - float rel_y, bool only_walls) -{ - EntityUID collide_x = - game_detect_collision(level, pos, rel_x, 0, only_walls); - EntityUID collide_y = - game_detect_collision(level, pos, 0, rel_y, only_walls); - - if (!collide_x) - pos->x += rel_x; - if (!collide_y) - pos->y += rel_y; - - return (collide_x || collide_y || UID_NULL); -} - void game_update_entities(const uint8_t level[]) { x = rand() % 4 + 1; @@ -558,7 +639,6 @@ void game_update_entities(const uint8_t level[]) { case E_ENEMY: { - // Enemy "IA" if (entity[i].health == 0) { @@ -568,33 +648,33 @@ void game_update_entities(const uint8_t level[]) { game_spawn_entity(E_KEY, entity[i].pos.x, entity[i].pos.y); entity[i].a = true; - enemyCount++; + enemy_count++; z = 7; } else if (x == 2) { game_spawn_entity(E_KEY, entity[i].pos.x, entity[i].pos.y); entity[i].a = true; - enemyCount++; + enemy_count++; z = 7; } else if (x == 3) { game_spawn_entity(E_MEDKIT, entity[i].pos.x, entity[i].pos.y); entity[i].a = true; - enemyCount++; + enemy_count++; z = 7; } else { entity[i].a = true; - enemyCount++; + enemy_count++; z = 7; } if (bss == true) - enemyCount2++; + enemy_count2++; } - if (bss == true && enemyCount > 2) + if (bss == true && enemy_count > 2) { } if (entity[i].state != S_DEAD) @@ -625,7 +705,8 @@ void game_update_entities(const uint8_t level[]) else { // ALERT STATE - if (entity[i].distance > ENEMY_MELEE_DIST && entity[i].distance < MAX_ENEMY_VIEW) + if (entity[i].distance > ENEMY_MELEE_DIST && + entity[i].distance < MAX_ENEMY_VIEW) { if (entity[i].state != S_ALERT) { @@ -644,12 +725,12 @@ void game_update_entities(const uint8_t level[]) else { // move towards to the player. - game_update_position( - level, - &(entity[i].pos), - SIGN(player.pos.x, entity[i].pos.x) * ENEMY_SPEED * delta_time, - SIGN(player.pos.y, entity[i].pos.y) * ENEMY_SPEED * delta_time, - true); + game_update_position(level, &(entity[i].pos), + SIGN(player.pos.x, entity[i].pos.x) * + ENEMY_SPEED * delta_time, + SIGN(player.pos.y, entity[i].pos.y) * + ENEMY_SPEED * delta_time, + true); } } } @@ -666,7 +747,8 @@ void game_update_entities(const uint8_t level[]) // Melee attack; if (debug == false) { - player.health = MAX(0, player.health - ENEMY_MELEE_DAMAGE * difficulty); + player.health = + MAX(0, player.health - ENEMY_MELEE_DAMAGE * game_difficulty); } entity[i].timer = 14; flash_screen = true; @@ -689,7 +771,8 @@ void game_update_entities(const uint8_t level[]) // Hit the player and disappear if (debug == false) { - player.health = MAX(0, player.health - ENEMY_FIREBALL_DAMAGE * difficulty); + player.health = + MAX(0, player.health - ENEMY_FIREBALL_DAMAGE * game_difficulty); } flash_screen = true; updateHud(); @@ -701,10 +784,11 @@ void game_update_entities(const uint8_t level[]) // Move. Only collide with walls. // Note: using health to store the angle of the movement EntityUID collided = game_update_position( - level, - &(entity[i].pos), - cosf((float)entity[i].health / FIREBALL_ANGLES * PI) * FIREBALL_SPEED, - sinf((float)entity[i].health / FIREBALL_ANGLES * PI) * FIREBALL_SPEED, + level, &(entity[i].pos), + cosf((float)entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED, + sinf((float)entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED, true); if (collided) @@ -718,16 +802,17 @@ void game_update_entities(const uint8_t level[]) case E_MEDKIT: { - if (entity[i].distance < ITEM_COLLIDER_DIST && player.health != 100 && jump_height < 14) + if (entity[i].distance < ITEM_COLLIDER_DIST && player.health != 100 && + jump_height < 14) { // pickup sound_play(medkit_snd, MEDKIT_SND_LEN); entity[i].state = S_HIDDEN; - if (difficulty == 1) + if (game_difficulty == 1) { player.health = MIN(100, player.health + 65); } - else if (difficulty == 2) + else if (game_difficulty == 2) { player.health = MIN(100, player.health + 50); } @@ -747,16 +832,17 @@ void game_update_entities(const uint8_t level[]) case E_KEY: { - if (entity[i].distance < ITEM_COLLIDER_DIST && player.keys < 240 && jump_height < 14) + if (entity[i].distance < ITEM_COLLIDER_DIST && player.keys < 240 && + jump_height < 14) { // pickup sound_play(get_key_snd, GET_KEY_SND_LEN); entity[i].state = S_HIDDEN; - if (difficulty == 1) + if (game_difficulty == 1) { player.keys = player.keys + 13; } - else if (difficulty == 2) + else if (game_difficulty == 2) { player.keys = player.keys + 10; } @@ -829,7 +915,7 @@ void game_render_map(const uint8_t level[], float view_height) uint8_t depth = 0; bool hit = 0; bool side; - bool coll = 0; + bool coll = false; while (!hit && depth < MAX_RENDER_DEPTH) { if (side_x < side_y) @@ -847,21 +933,24 @@ void game_render_map(const uint8_t level[], float view_height) uint8_t block = game_get_level_entity(level, map_x, map_y); - if (block == E_WALL || block == E_DOOR || block == E_DOOR2 || block == E_DOOR3 || block == E_COLL) + if (block == E_WALL || block == E_DOOR || block == E_DOOR2 || + block == E_DOOR3 || block == E_COLL) { hit = 1; if (block == E_COLL) - coll = 1; + coll = true; } else { // Spawning entities here, as soon they are visible for the // player. Not the best place, but would be a very performance // cost scan for them in another loop - if (block == E_ENEMY || (block & 0b00001000) /* all collectable items */) + if (block == E_ENEMY || + (block & 0b00001000) /* all collectable items */) { // Check that it's close to the player - if (coords_get_distance(&(player.pos), &map_coords) < MAX_ENTITY_DISTANCE) + if (coords_get_distance(&(player.pos), &map_coords) < + MAX_ENTITY_DISTANCE) { EntityUID uid = entities_get_uid(block, map_x, map_y); if (last_uid != uid && !game_is_entity_spawned(uid)) @@ -880,14 +969,10 @@ void game_render_map(const uint8_t level[], float view_height) { float distance; - if (side == 0) - { - distance = MAX(1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); - } - else - { + if (side) distance = MAX(1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); - } + else + distance = MAX(1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); // store zbuffer value for the column zbuffer[x / Z_RES_DIVIDER] = MIN(distance * DISTANCE_MULTIPLIER, 255); @@ -895,21 +980,22 @@ void game_render_map(const uint8_t level[], float view_height) // rendered line height uint8_t line_height = RENDER_HEIGHT / distance - 1; - if (coll == true) + if (coll) { display_draw_vline( x, view_height / distance - line_height / 2 + RENDER_HEIGHT / 2 - 17, view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, - GRADIENT_COUNT - (int)(distance / MAX_RENDER_DEPTH * GRADIENT_COUNT) - side * 2); + GRADIENT_COUNT - + (int)(distance / MAX_RENDER_DEPTH * GRADIENT_COUNT) - side * 2); } else { display_draw_vline( - x, - view_height / distance - line_height / 2 + RENDER_HEIGHT / 2, + x, view_height / distance - line_height / 2 + RENDER_HEIGHT / 2, view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, - GRADIENT_COUNT - (int)(distance / MAX_RENDER_DEPTH * GRADIENT_COUNT) - side * 2); + GRADIENT_COUNT - + (int)(distance / MAX_RENDER_DEPTH * GRADIENT_COUNT) - side * 2); } } } @@ -974,10 +1060,8 @@ void game_render_entities(float view_height) if ((transform.y <= 0.1f) || (transform.y > MAX_SPRITE_DEPTH)) continue; - int16_t sprite_screen_x = - HALF_WIDTH * (1.0f + (transform.x / transform.y)); - int8_t sprite_screen_y = - (RENDER_HEIGHT / 2) + (view_height / transform.y); + int16_t sprite_screen_x = HALF_WIDTH * (1.0f + (transform.x / transform.y)); + int8_t sprite_screen_y = (RENDER_HEIGHT / 2) + (view_height / transform.y); // Don't try to render if outside of screen // doing this pre-shortcut due int16 -> int8 conversion @@ -1006,12 +1090,8 @@ void game_render_entities(float view_height) display_draw_sprite( sprite_screen_x - BMP_IMP_WIDTH * 0.5f / transform.y, - sprite_screen_y - 8 / transform.y, bmp_imp_bits, - bmp_imp_mask, - BMP_IMP_WIDTH, - BMP_IMP_HEIGHT, - sprite, - transform.y); + sprite_screen_y - 8 / transform.y, bmp_imp_bits, bmp_imp_mask, + BMP_IMP_WIDTH, BMP_IMP_HEIGHT, sprite, transform.y); break; } @@ -1020,84 +1100,70 @@ void game_render_entities(float view_height) display_draw_sprite( sprite_screen_x - BMP_FIREBALL_WIDTH / 2 / transform.y, sprite_screen_y - BMP_FIREBALL_HEIGHT / 2 / transform.y, - bmp_fireball_bits, - bmp_fireball_mask, - BMP_FIREBALL_WIDTH, - BMP_FIREBALL_HEIGHT, - 0, - transform.y); + bmp_fireball_bits, bmp_fireball_mask, BMP_FIREBALL_WIDTH, + BMP_FIREBALL_HEIGHT, 0, transform.y); break; } case E_MEDKIT: { - display_draw_sprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, - bmp_items_bits, - bmp_items_mask, - BMP_ITEMS_WIDTH, - BMP_ITEMS_HEIGHT, - 0, - transform.y); + display_draw_sprite(sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, + sprite_screen_y + 5 / transform.y, bmp_items_bits, + bmp_items_mask, BMP_ITEMS_WIDTH, BMP_ITEMS_HEIGHT, + 0, transform.y); break; } case E_KEY: { - display_draw_sprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, - bmp_items_bits, - bmp_items_mask, - BMP_ITEMS_WIDTH, - BMP_ITEMS_HEIGHT, - 1, - transform.y); + display_draw_sprite(sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, + sprite_screen_y + 5 / transform.y, bmp_items_bits, + bmp_items_mask, BMP_ITEMS_WIDTH, BMP_ITEMS_HEIGHT, + 1, transform.y); break; } } } } -void game_render_gun(uint8_t gun_pos, float amount_jogging, bool gun_fired, uint8_t r1) +void game_render_gun(uint8_t pos, float jogging, bool fired, uint8_t reload) { - // jogging - int8_t x = 48 + sinf((float)platform_millis() * JOGGING_SPEED) * 10 * amount_jogging - 9; - int8_t y = RENDER_HEIGHT - gun_pos + fabsf(cosf((float)platform_millis() * JOGGING_SPEED)) * 8 * amount_jogging - 3; - uint8_t clip_height = MAX(0, MIN(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); - if (gun_pos > GUN_SHOT_POS - 2) - { - // Gun fire - if (player.keys > 0 && gun_fired == true) - { - display_draw_bitmap(x + 14, y - 11, bmp_fire_bits, BMP_FIRE_WIDTH, BMP_FIRE_HEIGHT, 1); - } - } - if (r1 == 1) - { + // Jogging + int8_t x = 48 + sinf(platform_millis() * JOGGING_SPEED) * 10 * jogging - 9; + int8_t y = RENDER_HEIGHT - pos + + fabsf(cosf(platform_millis() * JOGGING_SPEED)) * 8 * jogging - 3; + + // Gun fire + if (pos > GUN_SHOT_POS - 2) + if (player.keys > 0 && fired == true) + display_draw_bitmap(x + 14, y - 11, bmp_fire_bits, BMP_FIRE_WIDTH, + BMP_FIRE_HEIGHT, 1); + + // Reload animation + uint8_t clip_height; + switch (reload) + { + case 1: clip_height = MAX(0, MIN(y + BMP_RE1_HEIGHT, RENDER_HEIGHT) - y + 22); - display_draw_bitmap(x - 10, y - 22, bmp_re1_mask, BMP_RE1_WIDTH, clip_height, 0); - display_draw_bitmap(x - 10, y - 22, bmp_re1_bits, BMP_RE1_WIDTH, clip_height, 1); - } - else if (r1 == 2) - { + display_draw_bitmap(x - 10, y - 22, bmp_re1_mask, BMP_RE1_WIDTH, + clip_height, 0); + display_draw_bitmap(x - 10, y - 22, bmp_re1_bits, BMP_RE1_WIDTH, + clip_height, 1); + break; + + case 2: clip_height = MAX(0, MIN(y + BMP_RE2_HEIGHT, RENDER_HEIGHT) - y + 22); - display_draw_bitmap(x - 10, y - 22, bmp_re2_mask, BMP_RE2_WIDTH, clip_height, 0); - display_draw_bitmap(x - 10, y - 22, bmp_re2_bits, BMP_RE2_WIDTH, clip_height, 1); - } - else if (r1 == 0) - { + display_draw_bitmap(x - 10, y - 22, bmp_re2_mask, BMP_RE2_WIDTH, + clip_height, 0); + display_draw_bitmap(x - 10, y - 22, bmp_re2_bits, BMP_RE2_WIDTH, + clip_height, 1); + + default: + clip_height = MAX(0, MIN(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); display_draw_bitmap(x, y, bmp_gun_mask, BMP_GUN_WIDTH, clip_height, 0); display_draw_bitmap(x, y, bmp_gun_bits, BMP_GUN_WIDTH, clip_height, 1); + break; } - else - { - } - - // Don't draw over the hud! - - // Draw the gun (black mask + actual sprite). } // Only needed first time @@ -1128,11 +1194,11 @@ void updateHud(void) { display_draw_text(31, 58, "FOUND ", false); display_draw_text(65, 58, " SHELLS", false); - if (difficulty == 1) + if (game_difficulty == 1) { display_draw_text(57, 58, "13", false); } - else if (difficulty == 2) + else if (game_difficulty == 2) { display_draw_text(57, 58, "10", false); } @@ -1169,15 +1235,15 @@ void updateHud(void) { if (game_level == E1M2 && bss == true) { - display_draw_int(37, 58, enemyCount2); + display_draw_int(37, 58, enemy_count2); display_draw_text(52, 58, "OUT OF ", false); - display_draw_int(87, 58, enemyGoal2); + display_draw_int(87, 58, enemy_goal2); } else if (game_level == E1M1) { - display_draw_int(37, 58, enemyCount); + display_draw_int(37, 58, enemy_count); display_draw_text(52, 58, "OUT OF ", false); - display_draw_int(87, 58, enemyGoal); + display_draw_int(87, 58, enemy_goal); } } else if (z == 8) @@ -1220,13 +1286,9 @@ void updateHud(void) } // Debug stats -void renderStats(void) -{ -} +void renderStats(void) {} -void softReset(void) -{ -} +void softReset(void) {} void game_run_story_scene(void) { @@ -1234,42 +1296,68 @@ void game_run_story_scene(void) if (mid == 1) { - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, "YEAR 2027. HUMANS REACHED", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, "OTHER PLANETS, BUT WE ARE", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, "NOT ALONE, THERE IS ALSO", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, "HOSTILE ALIENS HERE. YOU", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, "ARE AN UNKNOWN MARINE,", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, "WHO FIGHT IN OLD LAB FOR", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, "REMNANTS OF EARTH. RESIST", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, "ALIENS TO ESCAPE.", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, + "YEAR 2027. HUMANS REACHED", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, + "OTHER PLANETS, BUT WE ARE", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, + "NOT ALONE, THERE IS ALSO", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, + "HOSTILE ALIENS HERE. YOU", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, + "ARE AN UNKNOWN MARINE,", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, + "WHO FIGHT IN OLD LAB FOR", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, + "REMNANTS OF EARTH. RESIST", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, + "ALIENS TO ESCAPE.", false); } else if (mid == 2) { - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, "AFTER KILLING BUNCH OF ", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, "ALIENS, LIGHTS TURNED OFF", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, "AND THE FLOOR COLLAPSED", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, "UNDER YOUR FEET AND YOU ", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, "FELL INTO THE UTILITY", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, "ROOMS. YOU HAVE NO CHOICE", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, "BUT TO START LOOKING FOR ", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, "EXIT, WHILE FIGHT ALIENS.", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, + "AFTER KILLING BUNCH OF ", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, + "ALIENS, LIGHTS TURNED OFF", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, + "AND THE FLOOR COLLAPSED", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, + "UNDER YOUR FEET AND YOU ", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, + "FELL INTO THE UTILITY", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, + "ROOMS. YOU HAVE NO CHOICE", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, + "BUT TO START LOOKING FOR ", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, + "EXIT, WHILE FIGHT ALIENS.", false); // Go to next level game_level = E1M2; } else { - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, "AFTER HARD FIGHT YOU WENT", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, "TO EXIT. AND AS SOON AS", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, "YOU STEP OUT, AN ALIEN", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, "ATTACKS YOU FROM BEHIND", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, "AND KILLS YOU. YOU DIDNT", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, "EXPECT THIS. YOUR FIGHT", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, "CAN NOT END LIKE THIS...", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, "THE END (MAYBE...)", false); - } - display_draw_text(SCREEN_WIDTH / 2.1 - 24, SCREEN_HEIGHT * .01, "THE STORY", false); - display_draw_text(SCREEN_WIDTH / 2 - 27, SCREEN_HEIGHT * .91, "PRESS FIRE", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, + "AFTER HARD FIGHT YOU WENT", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, + "TO EXIT. AND AS SOON AS", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, + "YOU STEP OUT, AN ALIEN", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, + "ATTACKS YOU FROM BEHIND", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, + "AND KILLS YOU. YOU DIDNT", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, + "EXPECT THIS. YOUR FIGHT", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, + "CAN NOT END LIKE THIS...", false); + display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, + "THE END (MAYBE...)", false); + } + display_draw_text(SCREEN_WIDTH / 2.1 - 24, SCREEN_HEIGHT * .01, "THE STORY", + false); + display_draw_text(SCREEN_WIDTH / 2 - 27, SCREEN_HEIGHT * .91, "PRESS FIRE", + false); if (input_fire()) { @@ -1287,49 +1375,48 @@ void game_run_story_scene(void) void game_run_score_scene(void) { - score = player.keys / 2; - score += player.health; - score *= 43; - score *= difficulty; + game_score = player.keys / 2; + game_score += player.health; + game_score *= 43; + game_score *= game_difficulty; if (player.secret != 0) { - score += 69; + game_score += 69; } if (player.secret2 += 0) { - score += 69; + game_score += 69; } if (player.secret3 += 0) { - score += 69; + game_score += 69; } - score += k; + game_score += k; display_draw_rect(1, 1, 127, 63, false); - display_draw_bitmap( - (SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2 - 27, - (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 6, - bmp_logo_bits, - BMP_LOGO_WIDTH, - BMP_LOGO_HEIGHT, - 1); + display_draw_bitmap((SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2 - 27, + (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 6, bmp_logo_bits, + BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, 1); - display_draw_text(SCREEN_WIDTH / 2.36 - 52, SCREEN_HEIGHT * .79, "NANO BRUTALITY", false); - display_draw_text(SCREEN_WIDTH / 0.99 - 45, SCREEN_HEIGHT * .2, "YOU WIN", false); + display_draw_text(SCREEN_WIDTH / 2.36 - 52, SCREEN_HEIGHT * .79, + "NANO BRUTALITY", false); + display_draw_text(SCREEN_WIDTH / 0.99 - 45, SCREEN_HEIGHT * .2, "YOU WIN", + false); if (player.cheats == false) { - display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .4, "SCENE_SCORE", false); - if (a < score) + display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .4, + "SCENE_SCORE", false); + if (a < game_score) { a += 155; display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); sound_play(walk1_snd, WALK1_SND_LEN); } - else if (a > score) + else if (a > game_score) { - a = score; + a = game_score; display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); m = false; music = 1; @@ -1338,7 +1425,8 @@ void game_run_score_scene(void) else { display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); - display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, "PRESS FIRE", false); + display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, + "PRESS FIRE", false); if (input_fire()) { display_draw_rect(1, 1, 127, 63, false); @@ -1352,10 +1440,14 @@ void game_run_score_scene(void) } else if (player.cheats == true) { - display_draw_text(SCREEN_WIDTH / 0.99 - 49, SCREEN_HEIGHT * .4, "NO SCENE_SCORE", false); - display_draw_text(SCREEN_WIDTH / 0.99 - 37, SCREEN_HEIGHT * .5, "FOR", false); - display_draw_text(SCREEN_WIDTH / 0.99 - 49, SCREEN_HEIGHT * .6, "CHEATERS", false); - display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, "PRESS FIRE", false); + display_draw_text(SCREEN_WIDTH / 0.99 - 49, SCREEN_HEIGHT * .4, + "NO SCENE_SCORE", false); + display_draw_text(SCREEN_WIDTH / 0.99 - 37, SCREEN_HEIGHT * .5, "FOR", + false); + display_draw_text(SCREEN_WIDTH / 0.99 - 49, SCREEN_HEIGHT * .6, "CHEATERS", + false); + display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, + "PRESS FIRE", false); if (input_fire()) { display_draw_rect(1, 1, 127, 63, false); @@ -1385,19 +1477,12 @@ void game_run_score_scene(void) */ void game_run_intro_scene(void) { - display_draw_bitmap( - (SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, - (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, - bmp_logo_bits, - BMP_LOGO_WIDTH, - BMP_LOGO_HEIGHT, - true); - - display_draw_text( - SCREEN_WIDTH / 2 - 25, - SCREEN_HEIGHT * 0.8f, - "PRESS FIRE", - true); + display_draw_bitmap((SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, + (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, bmp_logo_bits, + BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, true); + + display_draw_text(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * 0.8f, "PRESS FIRE", + true); sound_play(mus_s1_snd, MUS_S1_SND_LEN); @@ -1410,20 +1495,26 @@ void game_run_difficulty_scene(void) platform_delay(200); display_draw_rect(1, 1, 127, 63, false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .05, "CHOOSE SKILL LEVEL", false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .05, + "CHOOSE SKILL LEVEL", false); display_draw_text(SCREEN_WIDTH / 2.75 - 25, SCREEN_HEIGHT * .3, "I", false); - display_draw_text(SCREEN_WIDTH / 2.4 - 25, SCREEN_HEIGHT * .3, "M TOO YOUNG TO DIE.", false); + display_draw_text(SCREEN_WIDTH / 2.4 - 25, SCREEN_HEIGHT * .3, + "M TOO YOUNG TO DIE.", false); display_draw_text(SCREEN_WIDTH / 2.6 - 25, SCREEN_HEIGHT * .26, ",", false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .43, "HURT ME PLENTY.", false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .56, "NIGHTMARE.", false); - display_draw_text(SCREEN_WIDTH / 3.32 - 25, SCREEN_HEIGHT * .77, "NOTE - BUTTONS OUTSIDE", false); - display_draw_text(SCREEN_WIDTH / 4.1 - 25, SCREEN_HEIGHT * .9, "GAMEPLAY WORK AS U THINK", false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .43, + "HURT ME PLENTY.", false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .56, "NIGHTMARE.", + false); + display_draw_text(SCREEN_WIDTH / 3.32 - 25, SCREEN_HEIGHT * .77, + "NOTE - BUTTONS OUTSIDE", false); + display_draw_text(SCREEN_WIDTH / 4.1 - 25, SCREEN_HEIGHT * .9, + "GAMEPLAY WORK AS U THINK", false); - if (difficulty == 2) + if (game_difficulty == 2) { display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .43, "#", false); } - else if (difficulty == 1) + else if (game_difficulty == 1) { display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .3, "#", false); } @@ -1434,20 +1525,20 @@ void game_run_difficulty_scene(void) if (input_down()) { - difficulty++; - if (difficulty == 4) + game_difficulty++; + if (game_difficulty == 4) { - difficulty = 1; + game_difficulty = 1; } fade_e = false; game_jump_to_scene(SCENE_DIFFICULTY); } else if (input_up()) { - difficulty--; - if (difficulty == 0) + game_difficulty--; + if (game_difficulty == 0) { - difficulty = 3; + game_difficulty = 3; } fade_e = false; game_jump_to_scene(SCENE_DIFFICULTY); @@ -1465,9 +1556,12 @@ void game_run_music_scene(void) platform_delay(200); display_draw_rect(1, 1, 127, 63, false); - display_draw_text(SCREEN_WIDTH / 2.75 - 25, SCREEN_HEIGHT * .25, "MUSIC", false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .39, "OFF", false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .50, "ON (NOT RECOMENDED)", false); + display_draw_text(SCREEN_WIDTH / 2.75 - 25, SCREEN_HEIGHT * .25, "MUSIC", + false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .39, "OFF", + false); + display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .50, + "ON (NOT RECOMENDED)", false); if (m == false) { @@ -1495,13 +1589,9 @@ void game_run_level_scene(void) display_get_fps(); if (player.keys == 0) - { coll = false; - } - else if (player.keys != 0) - { + else coll = true; - } if (game_level == E1M1) { @@ -1515,23 +1605,26 @@ void game_run_level_scene(void) // Clear only the 3d view memset(display_buf, 0, SCREEN_WIDTH * (RENDER_HEIGHT / 8)); - if (player.pos.x >= 2 && player.pos.x <= 3 && player.pos.y >= 54 && player.pos.y <= 55 && z == 1 && player.secret < 2) + if (player.pos.x >= 2 && player.pos.x <= 3 && player.pos.y >= 54 && + player.pos.y <= 55 && z == 1 && player.secret < 2) { game_spawn_entity(E_ENEMY, 1, 51); game_spawn_entity(E_ENEMY, 3, 51); player.secret++; } - if (player.pos.x >= 46 && player.pos.x <= 47 && player.pos.y >= 35 && player.pos.y <= 36 && game_level == E1M2) + if (player.pos.x >= 46 && player.pos.x <= 47 && player.pos.y >= 35 && + player.pos.y <= 36 && game_level == E1M2) { player.pos.x = 12.5; player.pos.y = 33.5; - enemyCount = 0; + enemy_count = 0; game_spawn_entity(E_ENEMY, 10, 38); game_spawn_entity(E_ENEMY, 13, 38); bss = true; } - if (player.pos.y >= 55 && player.pos.y <= 56 && player.pos.x >= 12 && player.pos.x <= 23 && game_level == E1M2) + if (player.pos.y >= 55 && player.pos.y <= 56 && player.pos.x >= 12 && + player.pos.x <= 23 && game_level == E1M2) { mid = 3; m = false; @@ -1540,23 +1633,23 @@ void game_run_level_scene(void) } if (game_level == E1M2 && bss == true) { - if (enemyCount == 1 || enemyCount == 5 || enemyCount == 9) + if (enemy_count == 1 || enemy_count == 5 || enemy_count == 9) { - clearEntities(); - enemyCount++; + game_clear_dead_enemy(); + enemy_count++; game_spawn_entity(E_ENEMY, 13, 38); } - else if (enemyCount == 3 || enemyCount == 7 || enemyCount == 11) + else if (enemy_count == 3 || enemy_count == 7 || enemy_count == 11) { - clearEntities(); - enemyCount++; + game_clear_dead_enemy(); + enemy_count++; game_spawn_entity(E_ENEMY, 10, 38); } - else if (enemyCount == 13) + else if (enemy_count == 13) { player.pos.y = player.pos.y + 12; - enemyCount = 0; - enemyCount2 = 8; + enemy_count = 0; + enemy_count2 = 8; updateHud(); } } @@ -1569,7 +1662,6 @@ void game_run_level_scene(void) // If the player is alive if (player.health > 0) { - if (jump == 1 || jump == 2) { if (jump_height > 0 && jump == 2) @@ -1591,14 +1683,14 @@ void game_run_level_scene(void) } if (jump == 0) { - view_height = fabsf(sinf(platform_millis() * JOGGING_SPEED)) * 6 * jogging; + view_height = + fabsf(sinf(platform_millis() * JOGGING_SPEED)) * 6 * jogging; vel = 1; } // Player speed if (input_up()) { - player.velocity += (MOV_SPEED - player.velocity) * .4; if (jump == 1 || jump == 2) { @@ -1612,7 +1704,6 @@ void game_run_level_scene(void) } else if (input_down()) { - jogging = fabsf(player.velocity) * GUN_SPEED * 2; player.velocity += (-MOV_SPEED - player.velocity) * .4; if (jump == 1 || jump == 2) @@ -1642,25 +1733,31 @@ void game_run_level_scene(void) // Player rotation if (input_right()) { - rot_speed = ROT_SPEED * delta_time; old_dir_x = player.dir.x; - player.dir.x = player.dir.x * cosf(-rot_speed) - player.dir.y * sinf(-rot_speed); - player.dir.y = old_dir_x * sinf(-rot_speed) + player.dir.y * cosf(-rot_speed); + player.dir.x = + player.dir.x * cosf(-rot_speed) - player.dir.y * sinf(-rot_speed); + player.dir.y = + old_dir_x * sinf(-rot_speed) + player.dir.y * cosf(-rot_speed); old_plane_x = player.plane.x; - player.plane.x = player.plane.x * cosf(-rot_speed) - player.plane.y * sinf(-rot_speed); - player.plane.y = old_plane_x * sinf(-rot_speed) + player.plane.y * cosf(-rot_speed); + player.plane.x = + player.plane.x * cosf(-rot_speed) - player.plane.y * sinf(-rot_speed); + player.plane.y = + old_plane_x * sinf(-rot_speed) + player.plane.y * cosf(-rot_speed); } else if (input_left()) { - rot_speed = ROT_SPEED * delta_time; old_dir_x = player.dir.x; - player.dir.x = player.dir.x * cosf(rot_speed) - player.dir.y * sinf(rot_speed); - player.dir.y = old_dir_x * sinf(rot_speed) + player.dir.y * cosf(rot_speed); + player.dir.x = + player.dir.x * cosf(rot_speed) - player.dir.y * sinf(rot_speed); + player.dir.y = + old_dir_x * sinf(rot_speed) + player.dir.y * cosf(rot_speed); old_plane_x = player.plane.x; - player.plane.x = player.plane.x * cosf(rot_speed) - player.plane.y * sinf(rot_speed); - player.plane.y = old_plane_x * sinf(rot_speed) + player.plane.y * cosf(rot_speed); + player.plane.x = + player.plane.x * cosf(rot_speed) - player.plane.y * sinf(rot_speed); + player.plane.y = + old_plane_x * sinf(rot_speed) + player.plane.y * cosf(rot_speed); } if (input_left() && input_right() && jump == 0) @@ -1673,15 +1770,15 @@ void game_run_level_scene(void) { if (sound == false) { - if (walkSoundToggle) + if (walk_sound_toggle) { sound_play(walk1_snd, WALK1_SND_LEN); - walkSoundToggle = false; + walk_sound_toggle = false; } else { sound_play(walk2_snd, WALK2_SND_LEN); - walkSoundToggle = true; + walk_sound_toggle = true; } } } @@ -1696,7 +1793,8 @@ void game_run_level_scene(void) // Showing up gun_pos += 2; } - else if (!gun_fired && input_fire() && player.keys > 0 && reload1 == false) + else if (!gun_fired && input_fire() && player.keys > 0 && + reload1 == false) { // ready to fire and fire pressed gun_pos = GUN_SHOT_POS; @@ -1713,14 +1811,15 @@ void game_run_level_scene(void) gun_fired = false; reload1 = true; } - else if (!gun_fired && input_fire() && player.keys == 0 && reload1 == false) + else if (!gun_fired && input_fire() && player.keys == 0 && + reload1 == false) { gun_pos = GUN_SHOT_POS; gun_fired = true; game_fire_shootgun(); } - if (enemyCount == enemyGoal && game_level == E1M1) + if (enemy_count == enemy_goal && game_level == E1M1) { z = 3; updateHud(); @@ -1736,18 +1835,17 @@ void game_run_level_scene(void) player.pos.x = 230; player.pos.y = 50; mid = 2; - enemyCount = 0; + enemy_count = 0; z = 3; updateHud(); game_jump_to_scene(SCENE_STORY); } } - game_update_position( - game_level, - &(player.pos), - player.dir.x * player.velocity * delta_time * vel, - player.dir.y * player.velocity * delta_time * vel, false); + game_update_position(game_level, &(player.pos), + player.dir.x * player.velocity * delta_time * vel, + player.dir.y * player.velocity * delta_time * vel, + false); game_update_entities(game_level); } @@ -1833,7 +1931,8 @@ void game_run_level_scene(void) game_jump_to_scene(SCENE_INTRO); // Exit routine - // if (input_left() && input_right() && input_up() && input_down() && input_fire()) + // if (input_left() && input_right() && input_up() && input_down() && + // input_fire()) // { // z = 3; // updateHud(); From 5c1b09f7b8bcf67b74990bfe1ca396dccb14773b Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 23 Jul 2023 12:35:47 +0200 Subject: [PATCH 07/18] round 2 of refactoring doom nano brutality main Signed-off-by: Lorenzo Gualniera --- inc/constants.h | 34 +++-- inc/display.h | 2 +- inc/entities.h | 50 +++---- src/display.c | 2 +- src/game.c | 381 +++++++++++++++++++++++++++--------------------- 5 files changed, 266 insertions(+), 203 deletions(-) diff --git a/inc/constants.h b/inc/constants.h index dc5ac95..65575df 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -35,8 +35,8 @@ #define SCREEN_HEIGHT 64 #define HALF_WIDTH (SCREEN_WIDTH / 2) #define HALF_HEIGHT (SCREEN_HEIGHT / 2) -#define RENDER_HEIGHT 58 // Raycaster working height -#define HUD_HEIGHT 6 // HUD working height +#define RENDER_HEIGHT 58 +#define HUD_HEIGHT 6 /* Level */ #define LEVEL_WIDTH_BASE 6 @@ -48,29 +48,39 @@ #define GUN_TARGET_POS 18 #define GUN_SHOT_POS (GUN_TARGET_POS + 8) -#define ROT_SPEED 0.12f +#define ROT_SPEED 0.05f #define MOV_SPEED 0.1f #define GUN_SPEED 2.5f #define JOGGING_SPEED 0.005f #define ENEMY_SPEED 0.04f #define FIREBALL_SPEED 0.2f -#define FIREBALL_ANGLES 45 // Num of angles per PI +#define FIREBALL_ANGLES 45 -#define MAX_ENTITIES 12 // Max num of active entities -#define MAX_STATIC_ENTITIES 24 // Max num of entities in sleep mode +#define MAX_ENTITIES 12 +#define MAX_STATIC_ENTITIES 24 -#define MAX_ENTITY_DISTANCE 200 // * DISTANCE_MULTIPLIER -#define MAX_ENEMY_VIEW 90 // * DISTANCE_MULTIPLIER -#define ITEM_COLLIDER_DIST 6 // * DISTANCE_MULTIPLIER -#define ENEMY_COLLIDER_DIST 4 // * DISTANCE_MULTIPLIER -#define FIREBALL_COLLIDER_DIST 3 // * DISTANCE_MULTIPLIER -#define ENEMY_MELEE_DIST 9 // * DISTANCE_MULTIPLIER +#define MAX_ENTITY_DISTANCE 200 +#define MAX_ENEMY_VIEW 90 +#define ITEM_COLLIDER_DIST 6 +#define ENEMY_COLLIDER_DIST 4 +#define FIREBALL_COLLIDER_DIST 3 +#define ENEMY_MELEE_DIST 9 #define WALL_COLLIDER_DIST 0.2f #define ENEMY_MELEE_DAMAGE 18 #define ENEMY_FIREBALL_DAMAGE 25 #define GUN_MAX_DAMAGE 80 +#define PLAYER_MAX_HEALTH 100 +#define MEDKIT_HEAL_LOW 25 +#define MEDKIT_HEAL_MEDIUM 50 +#define MEDKIT_HEAL_HIGH 65 + +#define PLAYER_MAX_AMMO 255 +#define AMMO_NUM_LOW 9 +#define AMMO_NUM_MEDIUM 10 +#define AMMO_NUM_HIGH 13 + #endif /* CONSTANTS_H */ /* -------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/inc/display.h b/inc/display.h index 5a05553..d471ae1 100644 --- a/inc/display.h +++ b/inc/display.h @@ -161,7 +161,7 @@ void display_draw_vline(uint8_t x, int8_t start_y, int8_t end_y, uint8_t i); * @param color Color value */ void display_draw_bitmap(int16_t x, int16_t y, const uint8_t bitmap[], - int16_t w, int16_t h, uint16_t color); + int16_t w, int16_t h, bool color); /** * @brief DISPLAY draw sprite to display buffer. diff --git a/inc/entities.h b/inc/entities.h index 593d586..4418203 100644 --- a/inc/entities.h +++ b/inc/entities.h @@ -20,31 +20,31 @@ typedef uint16_t EntityUID; typedef enum { - E_FLOOR = 0x0, // . (also null) - E_WALL = 0xF, // # - E_DOOR = 0xD, - E_DOOR2 = 0xA, - E_DOOR3 = 0xB, - E_COLL = 0xC, - E_PLAYER = 0x1, // P - E_ENEMY = 0x2, // E - E_EXIT = 0x7, // X - E_MEDKIT = 0x8, // M - E_KEY = 0x9, // K - E_FIREBALL = 0xA // not in map + E_FLOOR = 0x0, + E_WALL = 0xF, + E_DOOR = 0xD, + E_DOOR2 = 0xA, + E_DOOR3 = 0xB, + E_COLL = 0xC, + E_PLAYER = 0x1, + E_ENEMY = 0x2, + E_EXIT = 0x7, + E_MEDKIT = 0x8, + E_AMMO = 0x9, + E_FIREBALL = 0xA } EntityType; typedef enum { - S_STAND = 0, - S_ALERT = 1, - S_FIRING = 2, - S_MELEE = 3, - S_HIT = 4, - S_DEAD = 5, - S_HIDDEN = 6, - S_OPEN = 7, - S_CLOSE = 8, + S_STAND, + S_ALERT, + S_FIRING, + S_MELEE, + S_HIT, + S_DEAD, + S_HIDDEN, + S_OPEN, + S_CLOSE } EntityStatus; typedef struct @@ -54,7 +54,7 @@ typedef struct Coords plane; float velocity; uint8_t health; - uint8_t keys; + uint8_t ammo; uint8_t secret; uint8_t secret2; uint8_t secret3; @@ -119,7 +119,7 @@ static inline Player entities_create_player(uint8_t x, uint8_t y) .plane = {0.0f, -0.66f}, .velocity = 0.0f, .health = 100, - .keys = 10, + .ammo = 10, .secret = 0, .secret2 = 0, .secret3 = 0, @@ -177,7 +177,7 @@ static inline Entity entities_create_medkit(uint8_t x, uint8_t y) static inline Entity entities_create_key(uint8_t x, uint8_t y) { return (Entity){ - .uid = entities_get_uid(E_KEY, x, y), + .uid = entities_get_uid(E_AMMO, x, y), .pos = {x + 0.5f, y + 0.5f}, .state = S_STAND, .health = 100, @@ -198,7 +198,7 @@ static inline Entity entities_create_key(uint8_t x, uint8_t y) static inline Entity entities_create_fireball(uint8_t x, uint8_t y, uint8_t dir) { return (Entity){ - .uid = entities_get_uid(E_KEY, x, y), + .uid = entities_get_uid(E_AMMO, x, y), .pos = {x + 0.5f, y + 0.5f}, .state = S_STAND, .health = dir, diff --git a/src/display.c b/src/display.c index cf14e7d..4484799 100644 --- a/src/display.c +++ b/src/display.c @@ -308,7 +308,7 @@ void display_draw_vline(uint8_t x, int8_t start_y, int8_t end_y, uint8_t i) * @param color Color value */ void display_draw_bitmap(int16_t x, int16_t y, const uint8_t bitmap[], - int16_t w, int16_t h, uint16_t color) + int16_t w, int16_t h, bool color) { // Bitmap scanline pad = whole byte int16_t byteWidth = (w + 7) / 8; diff --git a/src/game.c b/src/game.c index 7f743a3..10c5dbf 100644 --- a/src/game.c +++ b/src/game.c @@ -59,6 +59,7 @@ static EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, float rel_y, bool only_walls); static void game_fire_shootgun(void); +EntityType game_get_item_drop(void); /* Graphics */ static Coords game_translate_into_view(Coords *pos); @@ -101,7 +102,6 @@ static uint8_t num_entities = 0; static StaticEntity static_entity[MAX_STATIC_ENTITIES]; static uint8_t num_static_entities = 0; -static uint8_t x = 0; static uint8_t del = 0; static uint8_t enemy_count = 0; static uint8_t enemy_goal = 20; @@ -298,7 +298,7 @@ void game_spawn_entity(EntityType type, uint8_t x, uint8_t y) num_entities++; break; - case E_KEY: + case E_AMMO: entity[num_entities] = entities_create_key(x, y); num_entities++; break; @@ -515,7 +515,7 @@ EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, */ void game_fire_shootgun(void) { - if (player.keys != 0) + if (player.ammo != 0) { z = 3; sound_play(shoot_snd, SHOOT_SND_LEN); @@ -551,7 +551,8 @@ void game_fire_shootgun(void) /** TODO: change this equation so that game difficulty only * appears in damage calculation */ - entity[i].health = MAX(0, entity[i].health - damage / game_difficulty); + entity[i].health = MAX( + 0, entity[i].health - damage / game_difficulty); entity[i].state = S_HIT; entity[i].timer = 2; } @@ -605,9 +606,35 @@ void game_fire_shootgun(void) updateHud(); } +/** + * @brief GAME get random item drop. + * + * @return EntityType Random item between ammo, medkit, or nothing + */ +EntityType game_get_item_drop(void) +{ + EntityType item = 0; + + uint8_t random_item = rand() % 4; + if (random_item > 0) + { + if (random_item < 3) + item = E_AMMO; + else + item = E_MEDKIT; + } + + return item; +} + +/** + * @brief GAME execute entities AI logic. + * + * @param level Level byte map + */ void game_update_entities(const uint8_t level[]) { - x = rand() % 4 + 1; + uint8_t i = 0; while (i < num_entities) { @@ -637,100 +664,84 @@ void game_update_entities(const uint8_t level[]) switch (type) { + /** TODO: move enemy AI to separate function */ case E_ENEMY: { // Enemy "IA" if (entity[i].health == 0) { + if (entity[i].state != S_DEAD) + { + entity[i].state = S_DEAD; + entity[i].timer = 6; + } + + /** TODO: what is .a property? */ if (entity[i].a == false) { - if (x == 1) - { - game_spawn_entity(E_KEY, entity[i].pos.x, entity[i].pos.y); - entity[i].a = true; - enemy_count++; - z = 7; - } - else if (x == 2) - { - game_spawn_entity(E_KEY, entity[i].pos.x, entity[i].pos.y); - entity[i].a = true; - enemy_count++; - z = 7; - } - else if (x == 3) - { - game_spawn_entity(E_MEDKIT, entity[i].pos.x, entity[i].pos.y); - entity[i].a = true; - enemy_count++; - z = 7; - } - else - { - entity[i].a = true; - enemy_count++; - z = 7; - } + EntityType item = game_get_item_drop(); + game_spawn_entity(item, entity[i].pos.x, entity[i].pos.y); + + entity[i].a = true; + enemy_count++; + z = 7; + if (bss == true) enemy_count2++; } + + /** TODO: why is this here? */ if (bss == true && enemy_count > 2) { } - if (entity[i].state != S_DEAD) - { - entity[i].state = S_DEAD; - entity[i].timer = 6; - } } else if (entity[i].state == S_HIT) { if (entity[i].timer == 0) { - // Back to alert state - entity[i].state = S_ALERT; - entity[i].timer = 40; // delay next fireball thrown + entity[i].state = S_ALERT; // Back to alert state + entity[i].timer = 40; // Delay next fireball thrown } } else if (entity[i].state == S_FIRING) { if (entity[i].timer == 0) { - // Back to alert state - entity[i].state = S_ALERT; - entity[i].timer = 40; - // delay next fireball throwm + entity[i].state = S_ALERT; // Back to alert state + entity[i].timer = 40; // Delay next fireball thrown } } else { - // ALERT STATE - if (entity[i].distance > ENEMY_MELEE_DIST && - entity[i].distance < MAX_ENEMY_VIEW) + if ((entity[i].distance > ENEMY_MELEE_DIST) && + (entity[i].distance < MAX_ENEMY_VIEW)) { if (entity[i].state != S_ALERT) { - entity[i].state = S_ALERT; - entity[i].timer = 20; // used to throw fireballs + entity[i].state = S_ALERT; // Back to alert state + entity[i].timer = 20; // used to throw fireballs } else { if (entity[i].timer == 0) { // Throw a fireball - game_spawn_fireball(entity[i].pos.x, entity[i].pos.y); + game_spawn_fireball( + entity[i].pos.x, entity[i].pos.y); entity[i].state = S_FIRING; entity[i].timer = 6; } else { - // move towards to the player. - game_update_position(level, &(entity[i].pos), - SIGN(player.pos.x, entity[i].pos.x) * - ENEMY_SPEED * delta_time, - SIGN(player.pos.y, entity[i].pos.y) * - ENEMY_SPEED * delta_time, - true); + // Move towards to the player + game_update_position( + level, + &(entity[i].pos), + SIGN(player.pos.x, entity[i].pos.x) * + ENEMY_SPEED * delta_time, + SIGN(player.pos.y, entity[i].pos.y) * + ENEMY_SPEED * delta_time, + true); } } } @@ -744,11 +755,11 @@ void game_update_entities(const uint8_t level[]) } else if (entity[i].timer == 0) { - // Melee attack; - if (debug == false) + // Melee attack + if (!debug) { - player.health = - MAX(0, player.health - ENEMY_MELEE_DAMAGE * game_difficulty); + uint8_t damage = ENEMY_MELEE_DAMAGE * game_difficulty; + player.health = MAX(0, player.health - damage); } entity[i].timer = 14; flash_screen = true; @@ -756,10 +767,7 @@ void game_update_entities(const uint8_t level[]) } } else - { - // stand entity[i].state = S_STAND; - } } break; } @@ -769,22 +777,23 @@ void game_update_entities(const uint8_t level[]) if (entity[i].distance < FIREBALL_COLLIDER_DIST) { // Hit the player and disappear - if (debug == false) + if (!debug) { - player.health = - MAX(0, player.health - ENEMY_FIREBALL_DAMAGE * game_difficulty); + uint8_t damage = ENEMY_MELEE_DAMAGE * game_difficulty; + player.health = MAX(0, player.health - damage); } flash_screen = true; - updateHud(); game_remove_entity(entity[i].uid); - continue; // continue in the loop + updateHud(); + continue; } else { // Move. Only collide with walls. // Note: using health to store the angle of the movement EntityUID collided = game_update_position( - level, &(entity[i].pos), + level, + &(entity[i].pos), cosf((float)entity[i].health / FIREBALL_ANGLES * PI) * FIREBALL_SPEED, sinf((float)entity[i].health / FIREBALL_ANGLES * PI) * @@ -794,7 +803,7 @@ void game_update_entities(const uint8_t level[]) if (collided) { game_remove_entity(entity[i].uid); - continue; // continue in the entity check loop + continue; } } break; @@ -802,26 +811,27 @@ void game_update_entities(const uint8_t level[]) case E_MEDKIT: { - if (entity[i].distance < ITEM_COLLIDER_DIST && player.health != 100 && - jump_height < 14) + if ((entity[i].distance < ITEM_COLLIDER_DIST) && + (player.health != PLAYER_MAX_HEALTH) && + (jump_height < 14)) { - // pickup + // Pickup sound_play(medkit_snd, MEDKIT_SND_LEN); entity[i].state = S_HIDDEN; + + uint16_t health; if (game_difficulty == 1) - { - player.health = MIN(100, player.health + 65); - } + health = player.health + MEDKIT_HEAL_HIGH; else if (game_difficulty == 2) - { - player.health = MIN(100, player.health + 50); - } + health = player.health + MEDKIT_HEAL_MEDIUM; else - { - player.health = MIN(100, player.health + 25); - } - updateHud(); + health = player.health + MEDKIT_HEAL_LOW; + + player.health = MIN(PLAYER_MAX_HEALTH, health); flash_screen = true; + + /** TODO: why so many updates of the HUD? */ + updateHud(); z = 3; updateHud(); z = 2; @@ -830,30 +840,27 @@ void game_update_entities(const uint8_t level[]) break; } - case E_KEY: + case E_AMMO: { - if (entity[i].distance < ITEM_COLLIDER_DIST && player.keys < 240 && - jump_height < 14) + if ((entity[i].distance < ITEM_COLLIDER_DIST) && + (player.ammo < PLAYER_MAX_AMMO) && + (jump_height < 14)) { // pickup sound_play(get_key_snd, GET_KEY_SND_LEN); entity[i].state = S_HIDDEN; + + uint16_t ammo; if (game_difficulty == 1) - { - player.keys = player.keys + 13; - } + ammo = player.ammo + AMMO_NUM_HIGH; else if (game_difficulty == 2) - { - player.keys = player.keys + 10; - } + ammo = player.ammo + AMMO_NUM_MEDIUM; else - { - player.keys = player.keys + 9; - } - if (player.keys > 240) - { - player.keys = 240; - } + ammo = player.ammo + AMMO_NUM_LOW; + + player.ammo = MIN(PLAYER_MAX_AMMO, ammo); + + /** TODO: why so many updates of the HUD? */ updateHud(); z = 3; updateHud(); @@ -868,7 +875,13 @@ void game_update_entities(const uint8_t level[]) } } -// The map raycaster. Based on https://lodev.org/cgtutor/raycasting.html +/** + * @brief GAME render map with raycasting technique. + * NOTE: Based on https://lodev.org/cgtutor/raycasting.html + * + * @param level Level byte map + * @param view_height View height of the camera + */ void game_render_map(const uint8_t level[], float view_height) { EntityUID last_uid; @@ -881,8 +894,8 @@ void game_render_map(const uint8_t level[], float view_height) uint8_t map_x = (uint8_t)(player.pos.x); uint8_t map_y = (uint8_t)(player.pos.y); Coords map_coords = {player.pos.x, player.pos.y}; - float delta_x = fabsf(1 / ray_x); - float delta_y = fabsf(1 / ray_y); + float delta_x = fabsf(1.0f / ray_x); + float delta_y = fabsf(1.0f / ray_y); int8_t step_x; int8_t step_y; @@ -897,7 +910,7 @@ void game_render_map(const uint8_t level[], float view_height) else { step_x = 1; - side_x = (map_x + 1.0 - player.pos.x) * delta_x; + side_x = (map_x + 1.0f - player.pos.x) * delta_x; } if (ray_y < 0) @@ -908,35 +921,35 @@ void game_render_map(const uint8_t level[], float view_height) else { step_y = 1; - side_y = (map_y + 1.0 - player.pos.y) * delta_y; + side_y = (map_y + 1.0f - player.pos.y) * delta_y; } // Wall detection uint8_t depth = 0; - bool hit = 0; + bool hit = false; bool side; bool coll = false; - while (!hit && depth < MAX_RENDER_DEPTH) + while ((!hit) && (depth < MAX_RENDER_DEPTH)) { if (side_x < side_y) { side_x += delta_x; map_x += step_x; - side = 0; + side = false; } else { side_y += delta_y; map_y += step_y; - side = 1; + side = true; } uint8_t block = game_get_level_entity(level, map_x, map_y); - if (block == E_WALL || block == E_DOOR || block == E_DOOR2 || - block == E_DOOR3 || block == E_COLL) + if ((block == E_WALL) || (block == E_DOOR) || (block == E_DOOR2) || + (block == E_DOOR3) || (block == E_COLL)) { - hit = 1; + hit = true; if (block == E_COLL) coll = true; } @@ -945,8 +958,7 @@ void game_render_map(const uint8_t level[], float view_height) // Spawning entities here, as soon they are visible for the // player. Not the best place, but would be a very performance // cost scan for them in another loop - if (block == E_ENEMY || - (block & 0b00001000) /* all collectable items */) + if ((block == E_ENEMY) || (block & 0b00001000)) { // Check that it's close to the player if (coords_get_distance(&(player.pos), &map_coords) < @@ -970,38 +982,33 @@ void game_render_map(const uint8_t level[], float view_height) float distance; if (side) - distance = MAX(1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); + distance = + MAX(1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); else - distance = MAX(1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); + distance = + MAX(1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); - // store zbuffer value for the column - zbuffer[x / Z_RES_DIVIDER] = MIN(distance * DISTANCE_MULTIPLIER, 255); + // Store zbuffer value for the column + zbuffer[x / Z_RES_DIVIDER] = + MIN(distance * DISTANCE_MULTIPLIER, 0xff); - // rendered line height + // Render vertical line uint8_t line_height = RENDER_HEIGHT / distance - 1; - - if (coll) - { - display_draw_vline( - x, - view_height / distance - line_height / 2 + RENDER_HEIGHT / 2 - 17, - view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, - GRADIENT_COUNT - - (int)(distance / MAX_RENDER_DEPTH * GRADIENT_COUNT) - side * 2); - } - else - { - display_draw_vline( - x, view_height / distance - line_height / 2 + RENDER_HEIGHT / 2, - view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, - GRADIENT_COUNT - - (int)(distance / MAX_RENDER_DEPTH * GRADIENT_COUNT) - side * 2); - } + display_draw_vline( + x, + view_height / distance - line_height / 2 + RENDER_HEIGHT / 2 + + (-17 ? coll : 0), + view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, + GRADIENT_COUNT - (side * 2) - + (distance / MAX_RENDER_DEPTH * GRADIENT_COUNT)); } } } -// Sort entities from far to close +/** + * @brief GAME sort entities from far to close. + * + */ void game_sort_entities(void) { uint8_t gap = num_entities; @@ -1028,6 +1035,12 @@ void game_sort_entities(void) } } +/** + * @brief GAME translate 2D map coordinates into camera coordinates. + * + * @param pos 2D map coordinates + * @return Coords Camera coordinates + */ Coords game_translate_into_view(Coords *pos) { // Translate sprite position to relative to camera @@ -1045,6 +1058,11 @@ Coords game_translate_into_view(Coords *pos) return (Coords){transform_x, transform_y}; } +/** + * @brief GAME render entities sprites. + * + * @param view_height View height of the camera + */ void game_render_entities(float view_height) { game_sort_entities(); @@ -1060,8 +1078,10 @@ void game_render_entities(float view_height) if ((transform.y <= 0.1f) || (transform.y > MAX_SPRITE_DEPTH)) continue; - int16_t sprite_screen_x = HALF_WIDTH * (1.0f + (transform.x / transform.y)); - int8_t sprite_screen_y = (RENDER_HEIGHT / 2) + (view_height / transform.y); + int16_t sprite_screen_x = + HALF_WIDTH * (1.0f + (transform.x / transform.y)); + int8_t sprite_screen_y = + (RENDER_HEIGHT / 2) + (view_height / transform.y); // Don't try to render if outside of screen // doing this pre-shortcut due int16 -> int8 conversion @@ -1090,8 +1110,12 @@ void game_render_entities(float view_height) display_draw_sprite( sprite_screen_x - BMP_IMP_WIDTH * 0.5f / transform.y, - sprite_screen_y - 8 / transform.y, bmp_imp_bits, bmp_imp_mask, - BMP_IMP_WIDTH, BMP_IMP_HEIGHT, sprite, transform.y); + sprite_screen_y - 8 / transform.y, bmp_imp_bits, + bmp_imp_mask, + BMP_IMP_WIDTH, + BMP_IMP_HEIGHT, + sprite, + transform.y); break; } @@ -1100,32 +1124,52 @@ void game_render_entities(float view_height) display_draw_sprite( sprite_screen_x - BMP_FIREBALL_WIDTH / 2 / transform.y, sprite_screen_y - BMP_FIREBALL_HEIGHT / 2 / transform.y, - bmp_fireball_bits, bmp_fireball_mask, BMP_FIREBALL_WIDTH, - BMP_FIREBALL_HEIGHT, 0, transform.y); + bmp_fireball_bits, + bmp_fireball_mask, + BMP_FIREBALL_WIDTH, + BMP_FIREBALL_HEIGHT, + 0, + transform.y); break; } case E_MEDKIT: { - display_draw_sprite(sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, bmp_items_bits, - bmp_items_mask, BMP_ITEMS_WIDTH, BMP_ITEMS_HEIGHT, - 0, transform.y); + display_draw_sprite( + sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, + sprite_screen_y + 5 / transform.y, + bmp_items_bits, + bmp_items_mask, + BMP_ITEMS_WIDTH, + BMP_ITEMS_HEIGHT, + 0, + transform.y); break; } - case E_KEY: + case E_AMMO: { - display_draw_sprite(sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, bmp_items_bits, - bmp_items_mask, BMP_ITEMS_WIDTH, BMP_ITEMS_HEIGHT, - 1, transform.y); + display_draw_sprite( + sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, + sprite_screen_y + 5 / transform.y, + bmp_items_bits, + bmp_items_mask, + BMP_ITEMS_WIDTH, + BMP_ITEMS_HEIGHT, + 1, + transform.y); break; } } } } +/** + * @brief GAME render player gun sprite. + * + * @param gun_pos Gun cyclic position + * @param jogging Player jogging speed + */ void game_render_gun(uint8_t pos, float jogging, bool fired, uint8_t reload) { // Jogging @@ -1134,10 +1178,9 @@ void game_render_gun(uint8_t pos, float jogging, bool fired, uint8_t reload) fabsf(cosf(platform_millis() * JOGGING_SPEED)) * 8 * jogging - 3; // Gun fire - if (pos > GUN_SHOT_POS - 2) - if (player.keys > 0 && fired == true) - display_draw_bitmap(x + 14, y - 11, bmp_fire_bits, BMP_FIRE_WIDTH, - BMP_FIRE_HEIGHT, 1); + if ((pos > GUN_SHOT_POS - 2) && (player.ammo > 0) && (fired)) + display_draw_bitmap(x + 14, y - 11, bmp_fire_bits, BMP_FIRE_WIDTH, + BMP_FIRE_HEIGHT, 1); // Reload animation uint8_t clip_height; @@ -1269,7 +1312,7 @@ void updateHud(void) display_draw_text(2, 58, "{}", false); display_draw_text(103, 58, "[]", false); display_draw_int(12, 58, player.health); - display_draw_int(113, 58, player.keys); + display_draw_int(113, 58, player.ammo); } else { @@ -1375,7 +1418,7 @@ void game_run_story_scene(void) void game_run_score_scene(void) { - game_score = player.keys / 2; + game_score = player.ammo / 2; game_score += player.health; game_score *= 43; game_score *= game_difficulty; @@ -1588,14 +1631,14 @@ void game_run_level_scene(void) { display_get_fps(); - if (player.keys == 0) + if (player.ammo == 0) coll = false; else coll = true; if (game_level == E1M1) { - k = player.keys; + k = player.ammo; } display_draw_rect(1, 58, 100, 2, false); @@ -1793,7 +1836,7 @@ void game_run_level_scene(void) // Showing up gun_pos += 2; } - else if (!gun_fired && input_fire() && player.keys > 0 && + else if (!gun_fired && input_fire() && player.ammo > 0 && reload1 == false) { // ready to fire and fire pressed @@ -1802,7 +1845,7 @@ void game_run_level_scene(void) game_fire_shootgun(); if (debug == false) { - player.keys--; + player.ammo--; } } else if (gun_fired && !input_fire()) @@ -1811,7 +1854,7 @@ void game_run_level_scene(void) gun_fired = false; reload1 = true; } - else if (!gun_fired && input_fire() && player.keys == 0 && + else if (!gun_fired && input_fire() && player.ammo == 0 && reload1 == false) { gun_pos = GUN_SHOT_POS; @@ -1978,6 +2021,16 @@ void main(void) /* Run current game scene */ game_run_scene(); + printf("vel: %f\thp: %d\tammo: %d\ts: %d\ts1: %d\ts2: %d\tscore: %d\tcheats: %d\n", + player.velocity, + player.health, + player.ammo, + player.secret, + player.secret2, + player.secret3, + player.score, + player.cheats); + /* Stop drawing */ display_draw_stop(); } From 03bfbf670d1b132c12861878b31cea65002e69c5 Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 23 Jul 2023 23:23:47 +0200 Subject: [PATCH 08/18] refactoring of hud text rendering system Signed-off-by: Lorenzo Gualniera --- inc/constants.h | 2 + src/game.c | 275 +++++++++++++++++++----------------------------- 2 files changed, 110 insertions(+), 167 deletions(-) diff --git a/inc/constants.h b/inc/constants.h index 65575df..cb56de8 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -81,6 +81,8 @@ #define AMMO_NUM_MEDIUM 10 #define AMMO_NUM_HIGH 13 +#define TEXT_SPACING 1 + #endif /* CONSTANTS_H */ /* -------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/src/game.c b/src/game.c index 10c5dbf..4264eda 100644 --- a/src/game.c +++ b/src/game.c @@ -33,6 +33,27 @@ typedef enum SCENE_SCORE } GameScene; +typedef enum +{ + TEXT_BLANK_SPACE, + TEXT_FOUND_AMMO, + TEXT_FOUND_MEDKIT, + TEXT_FOUND_SECRET, + TEXT_GOAL_KILLS, + TEXT_GOAL_FIND_EXIT, + TEXT_GAME_OVER, + TEXT_YOU_WIN, + TEXT_DEBUG_MODE_ON, + TEXT_DEBUG_MODE_OFF +} GameText; + +typedef enum +{ + DIFFICULTY_EASY, + DIFFICULTY_MEDIUM, + DIFFICULTY_HARD, +} GameDifficulty; + /* Function prototypes ------------------------------------------------------ */ /* Level */ @@ -68,6 +89,7 @@ static void game_render_entities(float view_height); static void game_render_gun(uint8_t pos, float jogging, bool fired, uint8_t reload); static void game_render_hud(void); +static void game_render_hud_text(void); /* Scenes */ static void game_jump_to_scene(GameScene scene); @@ -78,8 +100,6 @@ static void game_run_story_scene(void); static void game_run_level_scene(void); static void game_run_score_scene(void); -void updateHud(void); /** TODO: merge with render HUD */ - /* Global variables --------------------------------------------------------- */ static uint8_t z = 6; @@ -127,6 +147,7 @@ static float jogging; static bool flash_screen = false; static uint8_t fade_screen = GRADIENT_COUNT - 1; +static GameText game_hud_text = TEXT_GOAL_KILLS; static const uint8_t *game_level = E1M1; static void (*game_run_scene)(void); @@ -426,31 +447,28 @@ EntityUID game_detect_collision(const uint8_t level[], Coords *pos, float rel_x, uint8_t round_y = pos->y + rel_y; uint8_t block = game_get_level_entity(level, round_x, round_y); - if (block == E_WALL & debug == false) + if ((block == E_WALL) & (debug == false)) { sound_play(hit_wall_snd, HIT_WALL_SND_LEN); return entities_get_uid(block, round_x, round_y); } - else if (block == E_DOOR && player.secret == false) + else if ((block == E_DOOR) && (player.secret == false)) { - z = 8; player.secret = true; - updateHud(); + game_hud_text = TEXT_FOUND_SECRET; sound_play(s_snd, S_SND_LEN); } - else if (block == E_DOOR2 && player.secret2 == false) + else if ((block == E_DOOR2) && (player.secret2 == false)) { - z = 8; player.secret2 = true; - updateHud(); + game_hud_text = TEXT_FOUND_SECRET; sound_play(s_snd, S_SND_LEN); } - else if (block == E_DOOR3 && player.secret3 == false) + else if ((block == E_DOOR3) && (player.secret3 == false)) { - z = 8; player.secret3 = true; + game_hud_text = TEXT_FOUND_SECRET; sound_play(s_snd, S_SND_LEN); - updateHud(); } if (only_walls) @@ -517,7 +535,6 @@ void game_fire_shootgun(void) { if (player.ammo != 0) { - z = 3; sound_play(shoot_snd, SHOOT_SND_LEN); for (uint8_t i = 0; i < num_entities; i++) { @@ -561,7 +578,6 @@ void game_fire_shootgun(void) } else { - z = 3; sound_play(melee_snd, MELEE_SND_LEN); for (uint8_t i = 0; i < num_entities; i++) { @@ -602,8 +618,8 @@ void game_fire_shootgun(void) } } - /** TODO: move all rendering to the end of the scene not in the middle */ - updateHud(); + // Clear last HUD text after shooting + game_hud_text = TEXT_BLANK_SPACE; } /** @@ -634,7 +650,6 @@ EntityType game_get_item_drop(void) */ void game_update_entities(const uint8_t level[]) { - uint8_t i = 0; while (i < num_entities) { @@ -672,6 +687,7 @@ void game_update_entities(const uint8_t level[]) { if (entity[i].state != S_DEAD) { + game_hud_text = TEXT_GOAL_KILLS; entity[i].state = S_DEAD; entity[i].timer = 6; } @@ -763,7 +779,6 @@ void game_update_entities(const uint8_t level[]) } entity[i].timer = 14; flash_screen = true; - updateHud(); } } else @@ -784,7 +799,6 @@ void game_update_entities(const uint8_t level[]) } flash_screen = true; game_remove_entity(entity[i].uid); - updateHud(); continue; } else @@ -829,13 +843,7 @@ void game_update_entities(const uint8_t level[]) player.health = MIN(PLAYER_MAX_HEALTH, health); flash_screen = true; - - /** TODO: why so many updates of the HUD? */ - updateHud(); - z = 3; - updateHud(); - z = 2; - updateHud(); + game_hud_text = TEXT_FOUND_MEDKIT; } break; } @@ -859,13 +867,7 @@ void game_update_entities(const uint8_t level[]) ammo = player.ammo + AMMO_NUM_LOW; player.ammo = MIN(PLAYER_MAX_AMMO, ammo); - - /** TODO: why so many updates of the HUD? */ - updateHud(); - z = 3; - updateHud(); - z = 1; - updateHud(); + game_hud_text = TEXT_FOUND_AMMO; } break; } @@ -1209,128 +1211,81 @@ void game_render_gun(uint8_t pos, float jogging, bool fired, uint8_t reload) } } -// Only needed first time +/** + * @brief GAME render heads-up display (HUD). + * + */ void game_render_hud(void) { - if (debug == false) - { - display_draw_text(2, 58, "{}", false); // Health symbol - display_draw_text(105, 58, "[]", false); // Keys symbol - updateHud(); - } - else - { - display_draw_text(2, 58, "X", false); // Health symbol - display_draw_text(105, 58, "Y", false); // Keys symbol - updateHud(); - } + display_draw_text(2, 58, "{}", false); + display_draw_text(103, 58, "[]", false); + display_draw_int(12, 58, player.health); + display_draw_int(113, 58, player.ammo); } -// Render values for the HUD -void updateHud(void) +/** + * @brief GAME render text on heads-up display (HUD). + * + */ +void game_render_hud_text(void) { - display_draw_rect(12, 58, 100, 6, false); - display_draw_rect(50, 58, 15, 6, false); - display_draw_rect(58, 58, 70, 6, false); + char text[32]; - if (z == 1) + switch (game_hud_text) { - display_draw_text(31, 58, "FOUND ", false); - display_draw_text(65, 58, " SHELLS", false); + case TEXT_BLANK_SPACE: + break; + + case TEXT_FOUND_AMMO: if (game_difficulty == 1) - { - display_draw_text(57, 58, "13", false); - } + sprintf(text, "FOUND %d AMMO", 13); else if (game_difficulty == 2) - { - display_draw_text(57, 58, "10", false); - } - else - { - display_draw_text(60, 58, "9", false); - } - } + sprintf(text, "FOUND %d AMMO", 10); + else if (game_difficulty == 3) + sprintf(text, "FOUND %d AMMO", 9); + display_draw_text(33, 58, text, TEXT_SPACING); + break; - else if (z == 2) - { - display_draw_text(31, 58, "FOUND A MEDKIT", false); - } - else if (z == 3) - { - display_draw_rect(12, 58, 100, 6, false); - display_draw_rect(1, 58, 100, 6, false); - display_draw_rect(50, 58, 15, 6, false); - display_draw_rect(58, 58, 70, 6, false); - } - else if (z == 4) - { - display_draw_text(38, 58, "GAME OVER", false); - } - else if (z == 5) - { - display_draw_text(44, 58, "YOU WIN", false); - } - else if (z == 6) - { - display_draw_text(33, 58, "GOAL-20 KILLS", false); - } - else if (z == 7) - { - if (game_level == E1M2 && bss == true) - { - display_draw_int(37, 58, enemy_count2); - display_draw_text(52, 58, "OUT OF ", false); - display_draw_int(87, 58, enemy_goal2); - } - else if (game_level == E1M1) - { - display_draw_int(37, 58, enemy_count); - display_draw_text(52, 58, "OUT OF ", false); - display_draw_int(87, 58, enemy_goal); - } - } - else if (z == 8) - { - display_draw_text(35, 58, "SECRET FOUND", false); - } - else if (z == 9) - { - display_draw_text(31, 58, "GOAL-FIND EXIT", false); - } - else if (z == 10) - { - display_draw_text(31, 58, "DEBUG MODE OFF", false); - } - else - { - display_draw_text(32, 58, "DEBUG MODE ON", false); - } + case TEXT_FOUND_MEDKIT: + display_draw_text(33, 58, "FOUND MEDKIT", TEXT_SPACING); + break; - if (debug == false) - { - display_draw_rect(1, 58, 8, 6, false); - display_draw_text(2, 58, "{}", false); - display_draw_text(103, 58, "[]", false); - display_draw_int(12, 58, player.health); - display_draw_int(113, 58, player.ammo); - } - else - { - display_draw_rect(1, 58, 8, 6, false); - display_draw_text(2, 58, "X", false); - display_draw_text(105, 58, "Y", false); - char posx[10]; - char posy[10]; - sprintf(posx, "%f", player.pos.x); - sprintf(posy, "%f", player.pos.y); - display_draw_text(12, 58, posx, false); - display_draw_text(113, 58, posy, false); + case TEXT_FOUND_SECRET: + display_draw_text(33, 58, "FOUND SECRET", TEXT_SPACING); + + case TEXT_GOAL_KILLS: + if (game_level == E1M1) + sprintf(text, "%d OUT OF %d", enemy_count, enemy_goal); + else if ((game_level == E1M2) && (bss == true)) + sprintf(text, "%d OUT OF %d", enemy_count2, enemy_goal2); + display_draw_text(35, 58, text, TEXT_SPACING); + break; + + case TEXT_GOAL_FIND_EXIT: + display_draw_text(33, 58, "FIND THE EXIT", TEXT_SPACING); + break; + + case TEXT_GAME_OVER: + display_draw_text(38, 58, "GAME OVER", TEXT_SPACING); + break; + + case TEXT_YOU_WIN: + display_draw_text(44, 58, "YOU WIN", TEXT_SPACING); + break; + + case TEXT_DEBUG_MODE_ON: + display_draw_text(31, 58, "DEBUG MODE ON", TEXT_SPACING); + break; + + case TEXT_DEBUG_MODE_OFF: + display_draw_text(31, 58, "DEBUG MODE OFF", TEXT_SPACING); + break; + + default: + break; } } -// Debug stats -void renderStats(void) {} - void softReset(void) {} void game_run_story_scene(void) @@ -1637,16 +1592,7 @@ void game_run_level_scene(void) coll = true; if (game_level == E1M1) - { k = player.ammo; - } - - display_draw_rect(1, 58, 100, 2, false); - - updateHud(); - - // Clear only the 3d view - memset(display_buf, 0, SCREEN_WIDTH * (RENDER_HEIGHT / 8)); if (player.pos.x >= 2 && player.pos.x <= 3 && player.pos.y >= 54 && player.pos.y <= 55 && z == 1 && player.secret < 2) @@ -1693,7 +1639,6 @@ void game_run_level_scene(void) player.pos.y = player.pos.y + 12; enemy_count = 0; enemy_count2 = 8; - updateHud(); } } @@ -1864,41 +1809,37 @@ void game_run_level_scene(void) if (enemy_count == enemy_goal && game_level == E1M1) { - z = 3; - updateHud(); - z = 5; - updateHud(); + game_hud_text = TEXT_YOU_WIN; + if (del == 0) { platform_delay(200); del++; } + if (input_fire()) { player.pos.x = 230; player.pos.y = 50; mid = 2; enemy_count = 0; - z = 3; - updateHud(); - game_jump_to_scene(SCENE_STORY); + game_hud_text = SCENE_STORY; } } - game_update_position(game_level, &(player.pos), - player.dir.x * player.velocity * delta_time * vel, - player.dir.y * player.velocity * delta_time * vel, - false); + game_update_position( + game_level, + &(player.pos), + player.dir.x * player.velocity * delta_time * vel, + player.dir.y * player.velocity * delta_time * vel, + false); game_update_entities(game_level); } else { // The player is dead - z = 3; - updateHud(); - z = 4; - updateHud(); + game_hud_text = TEXT_GAME_OVER; if (view_height > -5) view_height--; @@ -1948,7 +1889,6 @@ void game_run_level_scene(void) } // Render stuff - updateHud(); game_render_map(game_level ? game_level : E1M2, view_height); game_render_entities(view_height); game_render_gun(gun_pos, jogging, gun_fired, rc1); @@ -1961,6 +1901,7 @@ void game_run_level_scene(void) return; } game_render_hud(); + game_render_hud_text(); // Flash screen if (flash_screen) From c825f6785a77852804304b4afbb988ed13138b81 Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sat, 29 Jul 2023 21:03:47 +0200 Subject: [PATCH 09/18] add new jump and home controls Signed-off-by: Lorenzo Gualniera --- inc/input.h | 34 ++++++++----- inc/sound.h | 5 -- inc/utils.h | 5 ++ src/game.c | 131 +++++++++++++++++-------------------------------- src/input.c | 24 ++++++++- src/platform.c | 28 ++++++----- src/sound.c | 8 +-- src/utils.c | 30 +++++++++++ 8 files changed, 142 insertions(+), 123 deletions(-) create mode 100644 src/utils.c diff --git a/inc/input.h b/inc/input.h index 3ba528d..1d1979c 100644 --- a/inc/input.h +++ b/inc/input.h @@ -11,18 +11,14 @@ typedef enum { - B = 0x0001, - Y = 0x0002, - SELECT = 0x0004, - START = 0x0008, - UP = 0x0010, - DOWN = 0x0020, - LEFT = 0x0040, - RIGHT = 0x0080, - A = 0x0100, - X = 0x0200, - LB = 0x0400, - RB = 0x0800 + UP = 0b00000001, + DOWN = 0b00000010, + LEFT = 0b00000100, + RIGHT = 0b00001000, + FIRE = 0b00010000, + JUMP = 0b00100000, + HOME = 0b01000000, + EXIT = 0b10000000 } Buttons; /* Function prototypes ------------------------------------------------------ */ @@ -74,6 +70,20 @@ bool input_right(void); */ bool input_fire(void); +/** + * @brief INPUT check if jump button has been pressed. + * + * @return bool button is pressed + */ +bool input_jump(void); + +/** + * @brief INPUT check if home button has been pressed. + * + * @return bool button is pressed + */ +bool input_home(void); + /** * @brief INPUT check if exit button has been pressed. * diff --git a/inc/sound.h b/inc/sound.h index 3069490..93273a6 100644 --- a/inc/sound.h +++ b/inc/sound.h @@ -208,11 +208,6 @@ void sound_play(const uint8_t *snd, uint8_t len); */ uint16_t sound_get_frequency(void); -/* Global variables --------------------------------------------------------- */ - -bool sound; -uint8_t music; - #endif /* SOUND_H */ /* -------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/inc/utils.h b/inc/utils.h index 9aa663b..0436de1 100644 --- a/inc/utils.h +++ b/inc/utils.h @@ -14,6 +14,11 @@ #define READ_BIT(byte, pos) (byte & *(BIT_MASK + pos) ? 1 : 0) #define PI 3.14159265358979323846f +/* Function prototypes ------------------------------------------------------ */ + +uint32_t millis(void); +void delay(uint32_t ms); + #endif /* UTILS_H */ /* -------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/src/game.c b/src/game.c index 4264eda..860c212 100644 --- a/src/game.c +++ b/src/game.c @@ -609,7 +609,8 @@ void game_fire_shootgun(void) if (damage > 0) { - entity[i].health = MAX(0, entity[i].health - damage / game_difficulty); + entity[i].health = MAX( + 0, entity[i].health - damage / game_difficulty); entity[i].state = S_HIT; entity[i].timer = 2; } @@ -654,7 +655,8 @@ void game_update_entities(const uint8_t level[]) while (i < num_entities) { // update distance - entity[i].distance = coords_get_distance(&(player.pos), &(entity[i].pos)); + entity[i].distance = + coords_get_distance(&(player.pos), &(entity[i].pos)); // Run the timer. Works with actual frames. // Todo: use delta_time here. But needs float type and more memory @@ -700,7 +702,6 @@ void game_update_entities(const uint8_t level[]) entity[i].a = true; enemy_count++; - z = 7; if (bss == true) enemy_count2++; @@ -854,7 +855,7 @@ void game_update_entities(const uint8_t level[]) (player.ammo < PLAYER_MAX_AMMO) && (jump_height < 14)) { - // pickup + // Pickup sound_play(get_key_snd, GET_KEY_SND_LEN); entity[i].state = S_HIDDEN; @@ -1098,7 +1099,7 @@ void game_render_entities(float view_height) { uint8_t sprite; if (entity[i].state == S_ALERT) - sprite = (platform_millis() / 500) % 2; // Walking + sprite = (millis() / 500) % 2; // Walking else if (entity[i].state == S_FIRING) sprite = 2; // Fireball else if (entity[i].state == S_HIT) @@ -1175,9 +1176,9 @@ void game_render_entities(float view_height) void game_render_gun(uint8_t pos, float jogging, bool fired, uint8_t reload) { // Jogging - int8_t x = 48 + sinf(platform_millis() * JOGGING_SPEED) * 10 * jogging - 9; + int8_t x = 48 + sinf(millis() * JOGGING_SPEED) * 10 * jogging - 9; int8_t y = RENDER_HEIGHT - pos + - fabsf(cosf(platform_millis() * JOGGING_SPEED)) * 8 * jogging - 3; + fabsf(cosf(millis() * JOGGING_SPEED)) * 8 * jogging - 3; // Gun fire if ((pos > GUN_SHOT_POS - 2) && (player.ammo > 0) && (fired)) @@ -1361,13 +1362,9 @@ void game_run_story_scene(void) { fade_e = true; if (mid < 3) - { game_jump_to_scene(SCENE_LEVEL); - } else - { game_jump_to_scene(SCENE_SCORE); - } } } @@ -1379,17 +1376,11 @@ void game_run_score_scene(void) game_score *= game_difficulty; if (player.secret != 0) - { game_score += 69; - } - if (player.secret2 += 0) - { + if (player.secret2 != 0) game_score += 69; - } - if (player.secret3 += 0) - { + if (player.secret3 != 0) game_score += 69; - } game_score += k; display_draw_rect(1, 1, 127, 63, false); @@ -1399,7 +1390,7 @@ void game_run_score_scene(void) BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, 1); display_draw_text(SCREEN_WIDTH / 2.36 - 52, SCREEN_HEIGHT * .79, - "NANO BRUTALITY", false); + "PICO BRUTALITY", false); display_draw_text(SCREEN_WIDTH / 0.99 - 45, SCREEN_HEIGHT * .2, "YOU WIN", false); if (player.cheats == false) @@ -1415,9 +1406,8 @@ void game_run_score_scene(void) else if (a > game_score) { a = game_score; - display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); m = false; - music = 1; + display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); sound_play(shot_snd, SHOT_SND_LEN); } else @@ -1425,14 +1415,11 @@ void game_run_score_scene(void) display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, "PRESS FIRE", false); + if (input_fire()) { display_draw_rect(1, 1, 127, 63, false); - - music = 99; - platform_delay(1000); fade_e = true; - softReset(); } } } @@ -1446,22 +1433,17 @@ void game_run_score_scene(void) false); display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, "PRESS FIRE", false); + if (input_fire()) { - display_draw_rect(1, 1, 127, 63, false); - - music = 99; - platform_delay(1000); fade_e = true; - softReset(); + display_draw_rect(1, 1, 127, 63, false); } if (mc == false) { m = false; - music = 1; - sound_play(mus_s1_snd, MUS_S1_SND_LEN); - platform_delay(100); mc = true; + sound_play(mus_s1_snd, MUS_S1_SND_LEN); } } @@ -1482,7 +1464,7 @@ void game_run_intro_scene(void) display_draw_text(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * 0.8f, "PRESS FIRE", true); - sound_play(mus_s1_snd, MUS_S1_SND_LEN); + // sound_play(mus_s1_snd, MUS_S1_SND_LEN); if (input_fire()) game_jump_to_scene(SCENE_DIFFICULTY); @@ -1490,8 +1472,6 @@ void game_run_intro_scene(void) void game_run_difficulty_scene(void) { - platform_delay(200); - display_draw_rect(1, 1, 127, 63, false); display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .05, "CHOOSE SKILL LEVEL", false); @@ -1551,7 +1531,6 @@ void game_run_difficulty_scene(void) void game_run_music_scene(void) { fade_e = false; - platform_delay(200); display_draw_rect(1, 1, 127, 63, false); display_draw_text(SCREEN_WIDTH / 2.75 - 25, SCREEN_HEIGHT * .25, "MUSIC", @@ -1594,16 +1573,16 @@ void game_run_level_scene(void) if (game_level == E1M1) k = player.ammo; - if (player.pos.x >= 2 && player.pos.x <= 3 && player.pos.y >= 54 && - player.pos.y <= 55 && z == 1 && player.secret < 2) + if ((player.pos.x >= 2) && (player.pos.x <= 3) && (player.pos.y >= 54) && + (player.pos.y <= 55) && (player.secret < 2)) { game_spawn_entity(E_ENEMY, 1, 51); game_spawn_entity(E_ENEMY, 3, 51); player.secret++; } - if (player.pos.x >= 46 && player.pos.x <= 47 && player.pos.y >= 35 && - player.pos.y <= 36 && game_level == E1M2) + if ((player.pos.x >= 46) && (player.pos.x <= 47) && (player.pos.y >= 35) && + (player.pos.y <= 36) && (game_level == E1M2)) { player.pos.x = 12.5; player.pos.y = 33.5; @@ -1612,8 +1591,8 @@ void game_run_level_scene(void) game_spawn_entity(E_ENEMY, 13, 38); bss = true; } - if (player.pos.y >= 55 && player.pos.y <= 56 && player.pos.x >= 12 && - player.pos.x <= 23 && game_level == E1M2) + if ((player.pos.y >= 55) && (player.pos.y <= 56) && (player.pos.x >= 12) && + (player.pos.x <= 23) && (game_level == E1M2)) { mid = 3; m = false; @@ -1622,13 +1601,14 @@ void game_run_level_scene(void) } if (game_level == E1M2 && bss == true) { - if (enemy_count == 1 || enemy_count == 5 || enemy_count == 9) + if ((enemy_count == 1) || (enemy_count == 5) || (enemy_count == 9)) { game_clear_dead_enemy(); enemy_count++; game_spawn_entity(E_ENEMY, 13, 38); } - else if (enemy_count == 3 || enemy_count == 7 || enemy_count == 11) + else if ((enemy_count == 3) || (enemy_count == 7) || + (enemy_count == 11)) { game_clear_dead_enemy(); enemy_count++; @@ -1642,22 +1622,17 @@ void game_run_level_scene(void) } } - if (m == true) - { - music = 99; - } - // If the player is alive if (player.health > 0) { - if (jump == 1 || jump == 2) + if ((jump == 1) || (jump == 2)) { - if (jump_height > 0 && jump == 2) + if ((jump_height > 0) && (jump == 2)) { view_height -= 4; jump_height -= 4; } - else if (jump_height < 20 && jump == 1) + else if ((jump_height < 20) && (jump == 1)) { view_height += 4; jump_height += 4; @@ -1672,7 +1647,7 @@ void game_run_level_scene(void) if (jump == 0) { view_height = - fabsf(sinf(platform_millis() * JOGGING_SPEED)) * 6 * jogging; + fabsf(sinf(millis() * JOGGING_SPEED)) * 6 * jogging; vel = 1; } @@ -1680,7 +1655,7 @@ void game_run_level_scene(void) if (input_up()) { player.velocity += (MOV_SPEED - player.velocity) * .4; - if (jump == 1 || jump == 2) + if ((jump == 1) || (jump == 2)) { jogging = 0; gun_pos = 22; @@ -1748,7 +1723,7 @@ void game_run_level_scene(void) old_plane_x * sinf(rot_speed) + player.plane.y * cosf(rot_speed); } - if (input_left() && input_right() && jump == 0) + if (input_jump() && jump == 0) { jump = 1; sound_play(jump_snd, JUMP_SND_LEN); @@ -1756,31 +1731,22 @@ void game_run_level_scene(void) if (view_height > 2.95 && jump == 0) { - if (sound == false) + if (walk_sound_toggle) { - if (walk_sound_toggle) - { - sound_play(walk1_snd, WALK1_SND_LEN); - walk_sound_toggle = false; - } - else - { - sound_play(walk2_snd, WALK2_SND_LEN); - walk_sound_toggle = true; - } + sound_play(walk1_snd, WALK1_SND_LEN); + walk_sound_toggle = false; + } + else + { + sound_play(walk2_snd, WALK2_SND_LEN); + walk_sound_toggle = true; } } // Update gun if (gun_pos > GUN_TARGET_POS) - { - // Right after fire - gun_pos -= 2; - } + gun_pos -= 2; // Right after fire else if (gun_pos < GUN_TARGET_POS) - { - // Showing up - gun_pos += 2; - } + gun_pos += 2; // Showing up else if (!gun_fired && input_fire() && player.ammo > 0 && reload1 == false) { @@ -1789,9 +1755,7 @@ void game_run_level_scene(void) gun_fired = true; game_fire_shootgun(); if (debug == false) - { player.ammo--; - } } else if (gun_fired && !input_fire()) { @@ -1813,7 +1777,7 @@ void game_run_level_scene(void) if (del == 0) { - platform_delay(200); + delay(200); del++; } @@ -1857,14 +1821,10 @@ void game_run_level_scene(void) } if (reload1 == true) - { r++; - } if (coll == false) - { r = 7; - } if (r == 1) { @@ -1875,7 +1835,6 @@ void game_run_level_scene(void) rc1 = 2; sound_play(r1_snd, R1_SND_LEN); } - else if (r == 5) { rc1 = 1; @@ -1911,7 +1870,7 @@ void game_run_level_scene(void) } // Exit routine - if (input_exit()) + if (input_home()) game_jump_to_scene(SCENE_INTRO); // Exit routine @@ -1938,7 +1897,7 @@ void game_run_level_scene(void) // player.cheats = true; // } // updateHud(); - // platform_delay(500); + // delay(500); // } } diff --git a/src/input.c b/src/input.c index fea6d5c..6390ad8 100644 --- a/src/input.c +++ b/src/input.c @@ -78,7 +78,27 @@ bool input_right(void) */ bool input_fire(void) { - return input_button & Y; + return input_button & FIRE; +}; + +/** + * @brief INPUT check if jump button has been pressed. + * + * @return bool button is pressed + */ +bool input_jump(void) +{ + return input_button & JUMP; +}; + +/** + * @brief INPUT check if home button has been pressed. + * + * @return bool button is pressed + */ +bool input_home(void) +{ + return input_button & HOME; }; /** @@ -88,7 +108,7 @@ bool input_fire(void) */ bool input_exit(void) { - return input_button & SELECT; + return input_button & EXIT; } /* -------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/src/platform.c b/src/platform.c index e04042b..0e85b06 100644 --- a/src/platform.c +++ b/src/platform.c @@ -153,18 +153,24 @@ void platform_audio_callback(void *buffer, unsigned int frames) */ void platform_input_update(void) { + input_button = 0; + if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) - input_button = UP; - else if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) - input_button = DOWN; - else if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) - input_button = LEFT; - else if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) - input_button = RIGHT; - else if (IsKeyDown(KEY_SPACE)) - input_button = Y; - else if (IsKeyDown(KEY_ESCAPE)) - input_button = SELECT; + input_button |= UP; + if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) + input_button |= DOWN; + if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) + input_button |= LEFT; + if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) + input_button |= RIGHT; + if (IsKeyDown(KEY_SPACE)) + input_button |= FIRE; + if (IsKeyDown(KEY_LEFT_SHIFT)) + input_button |= JUMP; + if (IsKeyDown(KEY_ENTER)) + input_button |= HOME; + if (IsKeyDown(KEY_ESCAPE)) + input_button |= EXIT; } /** diff --git a/src/sound.c b/src/sound.c index c6e3c54..843e7b2 100644 --- a/src/sound.c +++ b/src/sound.c @@ -13,9 +13,6 @@ static uint8_t sound_len; static uint8_t sound_idx; static uint32_t sound_t0; -extern bool sound; -extern uint8_t music; - /* Function definitions ----------------------------------------------------- */ /** @@ -26,9 +23,6 @@ void sound_init(void) { sound_ptr = NULL; sound_len = 0; - - sound = false; - music = 0; } /** @@ -77,7 +71,7 @@ uint16_t sound_get_frequency(void) } // Get frequency value from byte encoding - return 1192030 / (60 * (uint16_t)sound_ptr[sound_idx]); + return 1192030 / (60 * (uint16_t)sound_ptr[0]); } /* -------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..820d376 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,30 @@ +/* Includes ----------------------------------------------------------------- */ + +#include + +#include "utils.h" +#include "platform.h" + +/* Function definitions ----------------------------------------------------- */ + +/** + * @brief UTILS get time in milliseconds from start of execution. + * + * @return uint32_t Start time in milliseconds + */ +uint32_t millis(void) +{ + return platform_millis(); +} + +/** + * @brief UTILS apply blocking delay in milliseconds. + * + * @param ms Delay in milliseconds + */ +void delay(uint32_t ms) +{ + platform_delay(ms); +} + +/* -------------------------------------------------------------------------- */ \ No newline at end of file From 251ed6d35138116f27f4c0752c00204c47f6ae7b Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sat, 29 Jul 2023 21:53:21 +0200 Subject: [PATCH 10/18] fix bug with raylib stream player Signed-off-by: Lorenzo Gualniera --- inc/sound.h | 294 ++++++++++++++++++++++++------------------------- src/platform.c | 28 +++-- src/sound.c | 6 +- 3 files changed, 170 insertions(+), 158 deletions(-) diff --git a/inc/sound.h b/inc/sound.h index 93273a6..9c87142 100644 --- a/inc/sound.h +++ b/inc/sound.h @@ -12,142 +12,142 @@ /* Definitions -------------------------------------------------------------- */ -static const uint8_t MUS_S1_SND_LEN = 38; -static const uint8_t mus_s1_snd[] = { - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P1_SND_LEN = 19; -static const uint8_t mus_p1_snd[] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P2_SND_LEN = 19; -static const uint8_t mus_p2_snd[] = {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P3_SND_LEN = 19; -static const uint8_t mus_p3_snd[] = {0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, - 0x43, 0x43, 0x43, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P4_SND_LEN = 19; -static const uint8_t mus_p4_snd[] = {0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, - 0x58, 0x58, 0x58, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P5_SND_LEN = 19; -static const uint8_t mus_p5_snd[] = {0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, - 0x53, 0x53, 0x53, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P6_SND_LEN = 19; -static const uint8_t mus_p6_snd[] = {0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, - 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P7_SND_LEN = 19; -static const uint8_t mus_p7_snd[] = {0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, - 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, - 0x58, 0x58, 0x58, 0x58, 0x58, 0x58}; - -static const uint8_t MUS_S21_SND_LEN = 38; -static const uint8_t mus_s21_snd[] = { - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P21_SND_LEN = 19; -static const uint8_t mus_p21_snd[] = {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P22_SND_LEN = 19; -static const uint8_t mus_p22_snd[] = {0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P24_SND_LEN = 19; -static const uint8_t mus_p24_snd[] = {0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P26_SND_LEN = 19; -static const uint8_t mus_p26_snd[] = {0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_P27_SND_LEN = 38; -static const uint8_t mus_p27_snd[] = { - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24}; - -static const uint8_t MUS_P28_SND_LEN = 38; -static const uint8_t mus_p28_snd[] = { - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x45, 0x45, 0x45, 0x45, - 0x45, 0x45, 0x45, 0x45, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}; - -static const uint8_t MUS_P29_SND_LEN = 38; -static const uint8_t mus_p29_snd[] = { - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45}; - -static const uint8_t MUS_EP_SND_LEN = 38; -static const uint8_t mus_ep_snd[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t MUS_EP2_SND_LEN = 19; -static const uint8_t mus_ep2_snd[] = {0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x45, 0x45, 0x45, 0x45, 0x45, 0x45}; - -static const uint8_t JUMP_SND_LEN = 19; -static const uint8_t jump_snd[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x25, 0x25, 0x25, 0x25, 0x25}; - -static const uint8_t S_SND_LEN = 38; -static const uint8_t s_snd[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, - 0x60, 0x60, 0x60, 0x60, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}; - -static const uint8_t R1_SND_LEN = 9; -static const uint8_t r1_snd[] = {0x95, 0x95, 0x95}; - -static const uint8_t R2_SND_LEN = 9; -static const uint8_t r2_snd[] = {0x50, 0x50, 0x50}; - -static const uint8_t SHOT_SND_LEN = 44; -static const uint8_t shot_snd[] = { - 0x10, 0x10, 0x10, 0x6e, 0x2a, 0x20, 0x28, 0x28, 0x9b, 0x28, 0x20, - 0x20, 0x21, 0x57, 0x20, 0x20, 0x20, 0x67, 0x20, 0x20, 0x29, 0x20, - 0x73, 0x20, 0x20, 0x20, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static const uint8_t SHOOT_SND_LEN = 27; -static const uint8_t shoot_snd[] = {0x10, 0x10, 0x10, 0x6e, 0x2a, 0x20, 0x28, - 0x28, 0x9b, 0x28, 0x20, 0x20, 0x21, 0x57, - 0x20, 0x20, 0x20, 0x67, 0x20, 0x20, 0x29, - 0x20, 0x73, 0x20, 0x20, 0x20, 0x89}; - -static const uint8_t GET_KEY_SND_LEN = 90; -static const uint8_t get_key_snd[] = { +#define MUS_S1_SND_LEN 40 +static const uint8_t mus_s1_snd[MUS_S1_SND_LEN] = { + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P1_SND_LEN 20 +static const uint8_t mus_p1_snd[MUS_P1_SND_LEN] = { + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P2_SND_LEN 20 +static const uint8_t mus_p2_snd[MUS_P2_SND_LEN] = { + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P3_SND_LEN 20 +static const uint8_t mus_p3_snd[MUS_P3_SND_LEN] = { + 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x43, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P4_SND_LEN 20 +static const uint8_t mus_p4_snd[MUS_P4_SND_LEN] = { + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P5_SND_LEN 20 +static const uint8_t mus_p5_snd[MUS_P5_SND_LEN] = { + 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, + 0x53, 0x53, 0x53, 0x53, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P6_SND_LEN 20 +static const uint8_t mus_p6_snd[MUS_P6_SND_LEN] = { + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P7_SND_LEN 20 +static const uint8_t mus_p7_snd[MUS_P7_SND_LEN] = { + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58}; + +#define MUS_S21_SND_LEN 40 +static const uint8_t mus_s21_snd[MUS_S21_SND_LEN] = { + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x00, 0x00, 0x00, 0x00, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P21_SND_LEN 20 +static const uint8_t mus_p21_snd[MUS_P21_SND_LEN] = { + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P22_SND_LEN 20 +static const uint8_t mus_p22_snd[MUS_P22_SND_LEN] = { + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P24_SND_LEN 20 +static const uint8_t mus_p24_snd[MUS_P24_SND_LEN] = { + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P26_SND_LEN 20 +static const uint8_t mus_p26_snd[MUS_P26_SND_LEN] = { + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x00, 0x00, 0x00, 0x00}; + +#define MUS_P27_SND_LEN 40 +static const uint8_t mus_p27_snd[MUS_P27_SND_LEN] = { + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24}; + +#define MUS_P28_SND_LEN 40 +static const uint8_t mus_p28_snd[MUS_P28_SND_LEN] = { + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10}; + +#define MUS_P29_SND_LEN 40 +static const uint8_t mus_p29_snd[MUS_P29_SND_LEN] = { + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45}; + +#define MUS_EP_SND_LEN 40 +static const uint8_t mus_ep_snd[MUS_EP_SND_LEN] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + +#define MUS_EP2_SND_LEN 20 +static const uint8_t mus_ep2_snd[MUS_EP2_SND_LEN] = { + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45}; + +#define JUMP_SND_LEN 20 +static const uint8_t jump_snd[JUMP_SND_LEN] = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x25, 0x25, 0x25, 0x25, 0x25}; + +#define S_SND_LEN 40 +static const uint8_t s_snd[S_SND_LEN] = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10}; + +#define R1_SND_LEN 6 +static const uint8_t r1_snd[R1_SND_LEN] = {0x95, 0x95, 0x95, 0x95, 0x95, 0x95}; + +#define R2_SND_LEN 6 +static const uint8_t r2_snd[R2_SND_LEN] = {0x50, 0x50, 0x50, 0x50, 0x50, 0x50}; + +#define SHOT_SND_LEN 54 +static const uint8_t shot_snd[SHOT_SND_LEN] = { + 0x10, 0x10, 0x10, 0x6e, 0x2a, 0x20, 0x28, 0x28, 0x9b, 0x28, 0x20, 0x20, + 0x21, 0x57, 0x20, 0x20, 0x20, 0x67, 0x20, 0x20, 0x29, 0x20, 0x73, 0x20, + 0x20, 0x20, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +#define SHOOT_SND_LEN 27 +static const uint8_t shoot_snd[SHOOT_SND_LEN] = { + 0x10, 0x10, 0x10, 0x6e, 0x2a, 0x20, 0x28, 0x28, 0x9b, 0x28, 0x20, 0x20, + 0x21, 0x57, 0x20, 0x20, 0x20, 0x67, 0x20, 0x20, 0x29, 0x20, 0x73, 0x20, + 0x20, 0x20, 0x89}; + +#define GET_KEY_SND_LEN 90 +static const uint8_t get_key_snd[GET_KEY_SND_LEN] = { 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, @@ -157,18 +157,18 @@ static const uint8_t get_key_snd[] = { 0x20, 0x20, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19}; -static const uint8_t HIT_WALL_SND_LEN = 8; -static const uint8_t hit_wall_snd[] = {0x83, 0x83, 0x82, 0x8e, - 0x8a, 0x89, 0x86, 0x84}; +#define HIT_WALL_SND_LEN 8 +static const uint8_t hit_wall_snd[HIT_WALL_SND_LEN] = { + 0x83, 0x83, 0x82, 0x8e, 0x8a, 0x89, 0x86, 0x84}; -static const uint8_t WALK1_SND_LEN = 3; -static const uint8_t walk1_snd[] = {0x8f, 0x8e, 0x8e}; +#define WALK1_SND_LEN 3 +static const uint8_t walk1_snd[WALK1_SND_LEN] = {0x8f, 0x8e, 0x8e}; -static const uint8_t WALK2_SND_LEN = 3; -static const uint8_t walk2_snd[] = {0x84, 0x87, 0x84}; +#define WALK2_SND_LEN 3 +static const uint8_t walk2_snd[WALK2_SND_LEN] = {0x84, 0x87, 0x84}; -static const uint8_t MEDKIT_SND_LEN = 69; -static const uint8_t medkit_snd[] = { +#define MEDKIT_SND_LEN 71 +static const uint8_t medkit_snd[MEDKIT_SND_LEN] = { 0x55, 0x20, 0x3a, 0x3a, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x33, 0x33, 0x33, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x26, 0x26, 0x26, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x16, @@ -176,8 +176,8 @@ static const uint8_t medkit_snd[] = { 0x20, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15}; -static const uint8_t MELEE_SND_LEN = 9; -static const uint8_t melee_snd[] = {0x8f, 0x8e, 0x8e}; +#define MELEE_SND_LEN 3 +static const uint8_t melee_snd[MELEE_SND_LEN] = {0x8f, 0x8e, 0x8e}; /* Function prototypes ------------------------------------------------------ */ diff --git a/src/platform.c b/src/platform.c index 0e85b06..9ec2136 100644 --- a/src/platform.c +++ b/src/platform.c @@ -28,7 +28,7 @@ /* Global variables --------------------------------------------------------- */ static uint32_t clock_t0; -static uint16_t old_frequency; +static bool audio_is_playing; static AudioStream audio_stream; /* Function prototypes ------------------------------------------------------ */ @@ -58,6 +58,7 @@ void platform_init(void) PlayAudioStream(audio_stream); PauseAudioStream(audio_stream); + audio_is_playing = false; clock_t0 = clock(); } @@ -108,7 +109,7 @@ void platform_draw_pixel(uint8_t x, uint8_t y, bool color) */ void platform_audio_play(void) { - old_frequency = 0; + audio_is_playing = true; ResumeAudioStream(audio_stream); } @@ -130,21 +131,27 @@ void platform_audio_callback(void *buffer, unsigned int frames) // End of sound, pause stream if (frequency == 0) { - PauseAudioStream(audio_stream); + if (audio_is_playing) + { + audio_is_playing = false; + PauseAudioStream(audio_stream); + } return; } - - // Same frequency as before, no need to update - if (frequency == old_frequency) - return; + else + { + if (!audio_is_playing) + { + audio_is_playing = true; + ResumeAudioStream(audio_stream); + } + } // Create square wave with given frequency uint16_t wave_length = AUDIO_SAMPLING_RATE / frequency; uint16_t *buf = (uint16_t *)buffer; for (uint16_t i = 0; i < frames; i++) - buf[i] = (i % wave_length) < wave_length / 2 ? SHRT_MAX : SHRT_MIN; - - old_frequency = frequency; + buf[i] = (i % wave_length) < (wave_length / 2) ? SHRT_MAX : SHRT_MIN; } /** @@ -275,6 +282,7 @@ void platform_delay(uint32_t ms) { /* Add definition here */ } + #endif /* USE_RAYLIB */ /* -------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/src/sound.c b/src/sound.c index 843e7b2..4d12b2c 100644 --- a/src/sound.c +++ b/src/sound.c @@ -70,8 +70,12 @@ uint16_t sound_get_frequency(void) sound_t0 = sound_t1; } + // Pause sound + if (sound_ptr[sound_idx] == 0x00) + return 0; + // Get frequency value from byte encoding - return 1192030 / (60 * (uint16_t)sound_ptr[0]); + return 1193181 / (60 * (uint16_t)sound_ptr[sound_idx]); } /* -------------------------------------------------------------------------- */ \ No newline at end of file From 5072760df212cc9022a6b0df7d1fe9be2e9f263f Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 30 Jul 2023 01:04:27 +0200 Subject: [PATCH 11/18] fix game scene displayed text Signed-off-by: Lorenzo Gualniera --- inc/constants.h | 5 + inc/entities.h | 4 +- src/display.c | 4 +- src/game.c | 786 +++++++++++++++++++----------------------------- src/platform.c | 7 +- src/sound.c | 2 +- 6 files changed, 320 insertions(+), 488 deletions(-) diff --git a/inc/constants.h b/inc/constants.h index cb56de8..8069147 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -81,6 +81,11 @@ #define AMMO_NUM_MEDIUM 10 #define AMMO_NUM_HIGH 13 +#define E1M1_ENEMY_GOAL 20 +#define E1M2_ENEMY_GOAL 8 + +#define SCORE_SECRET_ENDING 200 + #define TEXT_SPACING 1 #endif /* CONSTANTS_H */ diff --git a/inc/entities.h b/inc/entities.h index 4418203..c9a405f 100644 --- a/inc/entities.h +++ b/inc/entities.h @@ -59,7 +59,6 @@ typedef struct uint8_t secret2; uint8_t secret3; int16_t score; - bool cheats; } Player; typedef struct @@ -123,8 +122,7 @@ static inline Player entities_create_player(uint8_t x, uint8_t y) .secret = 0, .secret2 = 0, .secret3 = 0, - .score = 0, - .cheats = false}; + .score = 0}; } /** diff --git a/src/display.c b/src/display.c index 4484799..6ad3f37 100644 --- a/src/display.c +++ b/src/display.c @@ -231,9 +231,9 @@ uint8_t display_get_byte(uint8_t x, uint8_t y) */ void display_draw_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, bool color) { - for (uint8_t i = x; i < w; i++) + for (uint8_t i = x; i < x + w; i++) { - for (uint8_t j = y; j < h; j++) + for (uint8_t j = y; j < y + h; j++) display_draw_pixel(i, j, color, false); } } diff --git a/src/game.c b/src/game.c index 860c212..4a1aedf 100644 --- a/src/game.c +++ b/src/game.c @@ -42,26 +42,32 @@ typedef enum TEXT_GOAL_KILLS, TEXT_GOAL_FIND_EXIT, TEXT_GAME_OVER, - TEXT_YOU_WIN, - TEXT_DEBUG_MODE_ON, - TEXT_DEBUG_MODE_OFF + TEXT_YOU_WIN } GameText; typedef enum { DIFFICULTY_EASY, - DIFFICULTY_MEDIUM, + DIFFICULTY_NORMAL, DIFFICULTY_HARD, + DIFFICULTY_VERY_HARD, } GameDifficulty; +typedef enum +{ + CUTSCENE_E1M1, + CUTSCENE_E1M2, + CUTSCENE_END +} GameCutscene; + /* Function prototypes ------------------------------------------------------ */ /* Level */ static void game_init_level_scene(const uint8_t level[]); /* Entities */ -static EntityType game_get_level_entity(const uint8_t level[], uint8_t x, - uint8_t y); +static EntityType game_get_level_entity(const uint8_t level[], int16_t x, + int16_t y); static bool game_is_entity_spawned(EntityUID uid); static bool game_is_static_entity_spawned(EntityUID uid); static void game_spawn_entity(EntityType type, uint8_t x, uint8_t y); @@ -80,6 +86,7 @@ static EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, float rel_y, bool only_walls); static void game_fire_shootgun(void); +static void game_melee_attack(void); EntityType game_get_item_drop(void); /* Graphics */ @@ -104,16 +111,16 @@ static void game_run_score_scene(void); static uint8_t z = 6; static bool coll = false; -static uint8_t jump = 0; +static uint8_t jump_state = 0; static uint8_t jump_height = 0; static uint8_t vel = 1; -static uint8_t game_difficulty = 1; +static uint8_t game_difficulty = DIFFICULTY_EASY; static uint8_t noclip = 0; -static bool m = true; +static bool enable_music = true; static uint8_t rc1 = 0; static int16_t a = 0; static uint8_t enemy_count2 = 0; -static uint8_t enemy_goal2 = 8; +static uint8_t enemy_goal2 = E1M2_ENEMY_GOAL; // game // player and entities static Player player; @@ -124,23 +131,17 @@ static uint8_t num_static_entities = 0; static uint8_t del = 0; static uint8_t enemy_count = 0; -static uint8_t enemy_goal = 20; -static bool fade_e = true; -static bool debug = false; +static uint8_t enemy_goal = E1M1_ENEMY_GOAL; static uint8_t r = 0; static bool reload1 = false; static int16_t game_score; -static uint8_t k; -static int8_t mid = 1; +static int8_t story_cutscene = CUTSCENE_E1M1; static bool bss = false; static bool mc = false; // init static bool gun_fired = false; static bool walk_sound_toggle = false; static uint8_t gun_pos = 0; -static float rot_speed; -static float old_dir_x; -static float old_plane_x; static float view_height; static float jogging; @@ -204,11 +205,8 @@ void game_init_level_scene(const uint8_t level[]) gun_fired = false; walk_sound_toggle = false; gun_pos = 0; - rot_speed; - old_dir_x; - old_plane_x; - view_height; - jogging; + view_height = 0.0f; + jogging = 0.0f; fade_screen = GRADIENT_COUNT - 1; mc = false; @@ -251,7 +249,7 @@ void game_init_level_scene(const uint8_t level[]) * @param y Y coordinate * @return EntityType Entity type */ -EntityType game_get_level_entity(const uint8_t level[], uint8_t x, uint8_t y) +EntityType game_get_level_entity(const uint8_t level[], int16_t x, int16_t y) { if ((x < 0) || (x >= LEVEL_WIDTH) || (y < 0) || (y >= LEVEL_HEIGHT)) return E_FLOOR; @@ -350,8 +348,8 @@ void game_spawn_fireball(float x, float y) return; // Calculate direction. 32 angles - int16_t dir = FIREBALL_ANGLES * - ((atan2f(y - player.pos.y, x - player.pos.x) / PI) + 1); + int16_t dir = ((atan2f(y - player.pos.y, x - player.pos.x) / PI) + 1) * + FIREBALL_ANGLES; if (dir < 0) dir += FIREBALL_ANGLES * 2; @@ -397,7 +395,7 @@ void game_remove_static_entity(EntityUID uid) while (i < num_static_entities) { - if (!found && static_entity[i].uid == uid) + if ((!found) && (static_entity[i].uid == uid)) { found = true; num_static_entities--; @@ -439,15 +437,15 @@ void game_clear_dead_enemy(void) * @param only_walls Check only walls collisions * @return EntityUID Entity UID number */ -EntityUID game_detect_collision(const uint8_t level[], Coords *pos, float rel_x, - float rel_y, bool only_walls) +EntityUID game_detect_collision(const uint8_t level[], Coords *pos, + float rel_x, float rel_y, bool only_walls) { // Wall collision uint8_t round_x = pos->x + rel_x; uint8_t round_y = pos->y + rel_y; uint8_t block = game_get_level_entity(level, round_x, round_y); - if ((block == E_WALL) & (debug == false)) + if (block == E_WALL) { sound_play(hit_wall_snd, HIT_WALL_SND_LEN); return entities_get_uid(block, round_x, round_y); @@ -533,41 +531,86 @@ EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, */ void game_fire_shootgun(void) { - if (player.ammo != 0) + sound_play(shoot_snd, SHOOT_SND_LEN); + for (uint8_t i = 0; i < num_entities; i++) + { + // Shoot only ALIVE enemies + if ((entities_get_type(entity[i].uid) != E_ENEMY) || + (entity[i].state == S_DEAD) || + (entity[i].state == S_HIDDEN)) + continue; + + Coords transform = game_translate_into_view(&(entity[i].pos)); + if ((fabsf(transform.x) < 20.0f) && (transform.y > 0)) + { + uint8_t damage = MIN( + GUN_MAX_DAMAGE, + (GUN_MAX_DAMAGE / + (fabsf(transform.x) * entity[i].distance) / 5.0f)); + + if (jump_state) + damage /= 3; + + /** TODO: check if difficulty is easy->1, medium->2 etc..*/ + if (game_difficulty == 1) + damage *= 1.5f; + else if (game_difficulty == 2) + damage = damage; + else + damage *= 0.7f; + + if (damage > 0) + { + /** TODO: change this equation so that game difficulty only + * appears in damage calculation + */ + entity[i].health = MAX( + 0, entity[i].health - damage / game_difficulty); + entity[i].state = S_HIT; + entity[i].timer = 2; + } + } + } +} + +/** + * @brief GAME player perform melee attack and compute damage. + * + */ +void game_melee_attack(void) +{ + sound_play(melee_snd, MELEE_SND_LEN); + for (uint8_t i = 0; i < num_entities; i++) { - sound_play(shoot_snd, SHOOT_SND_LEN); - for (uint8_t i = 0; i < num_entities; i++) + if (entity[i].distance <= ENEMY_MELEE_DIST) { - // Shoot only ALIVE enemies + // Attack only ALIVE enemies if ((entities_get_type(entity[i].uid) != E_ENEMY) || (entity[i].state == S_DEAD) || (entity[i].state == S_HIDDEN)) continue; Coords transform = game_translate_into_view(&(entity[i].pos)); - if ((fabsf(transform.x) < 20.0f) && (transform.y > 0)) + if (fabsf(transform.x) < 20 && transform.y > 0) { uint8_t damage = MIN( GUN_MAX_DAMAGE, GUN_MAX_DAMAGE / - (fabsf(transform.x) * entity[i].distance) / 5.0f); + (fabsf(transform.x) * entity[i].distance) / 5); - if ((jump == 1) || (jump == 2)) + if (jump_state) damage = damage / 3; - /** TODO: check if difficulty is easy->1, medium->2 etc..*/ + /** TODO: sort out difficulty damage calculation */ if (game_difficulty == 1) - damage *= 1.5f; + damage = damage + damage / 4.0; else if (game_difficulty == 2) - damage = damage; + damage = damage - damage * 0.1; else - damage *= 0.7f; + damage = damage * 0.60; if (damage > 0) { - /** TODO: change this equation so that game difficulty only - * appears in damage calculation - */ entity[i].health = MAX( 0, entity[i].health - damage / game_difficulty); entity[i].state = S_HIT; @@ -576,51 +619,6 @@ void game_fire_shootgun(void) } } } - else - { - sound_play(melee_snd, MELEE_SND_LEN); - for (uint8_t i = 0; i < num_entities; i++) - { - if (entity[i].distance <= ENEMY_MELEE_DIST) - { - // Shoot only ALIVE enemies - if ((entities_get_type(entity[i].uid) != E_ENEMY) || - (entity[i].state == S_DEAD) || - (entity[i].state == S_HIDDEN)) - continue; - - Coords transform = game_translate_into_view(&(entity[i].pos)); - if (fabsf(transform.x) < 20 && transform.y > 0) - { - uint8_t damage = MIN( - GUN_MAX_DAMAGE, - GUN_MAX_DAMAGE / - (fabsf(transform.x) * entity[i].distance) / 5); - - /** TODO: why is it different now? cut down duplication */ - if ((jump == 1) || (jump == 2)) - damage = damage / 3; - if (game_difficulty == 1) - damage = damage + damage / 4.0; - else if (game_difficulty == 2) - damage = damage - damage * 0.1; - else - damage = damage * 0.60; - - if (damage > 0) - { - entity[i].health = MAX( - 0, entity[i].health - damage / game_difficulty); - entity[i].state = S_HIT; - entity[i].timer = 2; - } - } - } - } - } - - // Clear last HUD text after shooting - game_hud_text = TEXT_BLANK_SPACE; } /** @@ -773,11 +771,8 @@ void game_update_entities(const uint8_t level[]) else if (entity[i].timer == 0) { // Melee attack - if (!debug) - { - uint8_t damage = ENEMY_MELEE_DAMAGE * game_difficulty; - player.health = MAX(0, player.health - damage); - } + uint8_t damage = ENEMY_MELEE_DAMAGE * game_difficulty; + player.health = MAX(0, player.health - damage); entity[i].timer = 14; flash_screen = true; } @@ -793,11 +788,8 @@ void game_update_entities(const uint8_t level[]) if (entity[i].distance < FIREBALL_COLLIDER_DIST) { // Hit the player and disappear - if (!debug) - { - uint8_t damage = ENEMY_MELEE_DAMAGE * game_difficulty; - player.health = MAX(0, player.health - damage); - } + uint8_t damage = ENEMY_MELEE_DAMAGE * game_difficulty; + player.health = MAX(0, player.health - damage); flash_screen = true; game_remove_entity(entity[i].uid); continue; @@ -1274,181 +1266,97 @@ void game_render_hud_text(void) display_draw_text(44, 58, "YOU WIN", TEXT_SPACING); break; - case TEXT_DEBUG_MODE_ON: - display_draw_text(31, 58, "DEBUG MODE ON", TEXT_SPACING); - break; - - case TEXT_DEBUG_MODE_OFF: - display_draw_text(31, 58, "DEBUG MODE OFF", TEXT_SPACING); - break; - default: break; } } -void softReset(void) {} - +/** + * @brief GAME run story scene. + * + */ void game_run_story_scene(void) { - display_draw_rect(1, 1, 127, 63, false); - - if (mid == 1) + if (story_cutscene == CUTSCENE_E1M1) { - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, - "YEAR 2027. HUMANS REACHED", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, - "OTHER PLANETS, BUT WE ARE", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, - "NOT ALONE, THERE IS ALSO", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, - "HOSTILE ALIENS HERE. YOU", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, - "ARE AN UNKNOWN MARINE,", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, - "WHO FIGHT IN OLD LAB FOR", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, - "REMNANTS OF EARTH. RESIST", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, - "ALIENS TO ESCAPE.", false); + display_draw_text(0, 0, "YEAR 2027. HUMANS REACHED", TEXT_SPACING); + display_draw_text(0, 6, "OTHER PLANETS, BUT WE ARE", TEXT_SPACING); + display_draw_text(0, 12, "NOT ALONE, THERE IS ALSO", TEXT_SPACING); + display_draw_text(0, 18, "HOSTILE ALIENS HERE. YOU", TEXT_SPACING); + display_draw_text(0, 24, "ARE AN UNKNOWN MARINE,", TEXT_SPACING); + display_draw_text(0, 30, "WHO FIGHT IN OLD LAB FOR", TEXT_SPACING); + display_draw_text(0, 36, "REMNANTS OF EARTH. RESIST", TEXT_SPACING); + display_draw_text(0, 42, "ALIENS TO ESCAPE.", TEXT_SPACING); } - else if (mid == 2) + else if (story_cutscene == CUTSCENE_E1M2) { - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, - "AFTER KILLING BUNCH OF ", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, - "ALIENS, LIGHTS TURNED OFF", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, - "AND THE FLOOR COLLAPSED", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, - "UNDER YOUR FEET AND YOU ", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, - "FELL INTO THE UTILITY", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, - "ROOMS. YOU HAVE NO CHOICE", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, - "BUT TO START LOOKING FOR ", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, - "EXIT, WHILE FIGHT ALIENS.", false); - - // Go to next level - game_level = E1M2; + display_draw_text(0, 0, "AFTER KILLING BUNCH OF ", TEXT_SPACING); + display_draw_text(0, 6, "ALIENS, LIGHTS TURNED OFF", TEXT_SPACING); + display_draw_text(0, 12, "AND THE FLOOR COLLAPSED", TEXT_SPACING); + display_draw_text(0, 18, "UNDER YOUR FEET AND YOU ", TEXT_SPACING); + display_draw_text(0, 24, "FELL INTO THE UTILITY", TEXT_SPACING); + display_draw_text(0, 30, "ROOMS. YOU HAVE NO CHOICE", TEXT_SPACING); + display_draw_text(0, 36, "BUT TO START LOOKING FOR ", TEXT_SPACING); + display_draw_text(0, 42, "EXIT, WHILE FIGHT ALIENS.", TEXT_SPACING); } - else + else if (story_cutscene == CUTSCENE_END) { - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .14, - "AFTER HARD FIGHT YOU WENT", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .23, - "TO EXIT. AND AS SOON AS", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .32, - "YOU STEP OUT, AN ALIEN", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .42, - "ATTACKS YOU FROM BEHIND", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .51, - "AND KILLS YOU. YOU DIDNT", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .60, - "EXPECT THIS. YOUR FIGHT", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .70, - "CAN NOT END LIKE THIS...", false); - display_draw_text(SCREEN_WIDTH / 4.6 - 26, SCREEN_HEIGHT * .80, - "THE END (MAYBE...)", false); + display_draw_text(0, 0, "AFTER HARD FIGHT YOU WENT", TEXT_SPACING); + display_draw_text(0, 6, "TO EXIT. AND AS SOON AS", TEXT_SPACING); + display_draw_text(0, 12, "YOU STEP OUT, AN ALIEN", TEXT_SPACING); + display_draw_text(0, 18, "ATTACKS YOU FROM BEHIND", TEXT_SPACING); + display_draw_text(0, 24, "AND KILLS YOU. YOU DIDNT", TEXT_SPACING); + display_draw_text(0, 30, "EXPECT THIS. YOUR FIGHT", TEXT_SPACING); + display_draw_text(0, 36, "CAN NOT END LIKE THIS...", TEXT_SPACING); + display_draw_text(0, 42, "THE END (MAYBE...)", TEXT_SPACING); } - display_draw_text(SCREEN_WIDTH / 2.1 - 24, SCREEN_HEIGHT * .01, "THE STORY", - false); - display_draw_text(SCREEN_WIDTH / 2 - 27, SCREEN_HEIGHT * .91, "PRESS FIRE", - false); + display_draw_text(39, 53, "PRESS FIRE", TEXT_SPACING); if (input_fire()) { - fade_e = true; - if (mid < 3) + if (story_cutscene != CUTSCENE_END) game_jump_to_scene(SCENE_LEVEL); else game_jump_to_scene(SCENE_SCORE); } + + delay(100); } +/** + * @brief GAME run game over scene. + * + */ void game_run_score_scene(void) { - game_score = player.ammo / 2; + // Compute game score + game_score = (player.ammo / 2); game_score += player.health; - game_score *= 43; - game_score *= game_difficulty; - - if (player.secret != 0) - game_score += 69; - if (player.secret2 != 0) - game_score += 69; - if (player.secret3 != 0) - game_score += 69; - game_score += k; - - display_draw_rect(1, 1, 127, 63, false); - - display_draw_bitmap((SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2 - 27, - (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 6, bmp_logo_bits, - BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, 1); - - display_draw_text(SCREEN_WIDTH / 2.36 - 52, SCREEN_HEIGHT * .79, - "PICO BRUTALITY", false); - display_draw_text(SCREEN_WIDTH / 0.99 - 45, SCREEN_HEIGHT * .2, "YOU WIN", - false); - if (player.cheats == false) - { - display_draw_text(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .4, - "SCENE_SCORE", false); - if (a < game_score) - { - a += 155; - display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); - sound_play(walk1_snd, WALK1_SND_LEN); - } - else if (a > game_score) - { - a = game_score; - m = false; - display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); - sound_play(shot_snd, SHOT_SND_LEN); - } - else - { - display_draw_int(SCREEN_WIDTH / 0.99 - 40, SCREEN_HEIGHT * .5, a); - display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, - "PRESS FIRE", false); + game_score *= (game_difficulty + 1); + if (player.secret > 0) + game_score += 100; + if (player.secret2 > 0) + game_score += 100; + if (player.secret3 > 0) + game_score += 100; + + display_draw_bitmap( + 8, 8, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, true); + display_draw_text(34, 48, "PICO", TEXT_SPACING); + display_draw_text(88, 8, "YOU WIN", TEXT_SPACING); + display_draw_rect(88, 26, 34, 1, true); + display_draw_text(88, 38, "SCORE:", TEXT_SPACING); + display_draw_int(88, 48, game_score); + + if (game_score > SCORE_SECRET_ENDING) + sound_play(walk1_snd, WALK1_SND_LEN); + else + sound_play(shot_snd, SHOT_SND_LEN); - if (input_fire()) - { - display_draw_rect(1, 1, 127, 63, false); - fade_e = true; - } - } - } - else if (player.cheats == true) - { - display_draw_text(SCREEN_WIDTH / 0.99 - 49, SCREEN_HEIGHT * .4, - "NO SCENE_SCORE", false); - display_draw_text(SCREEN_WIDTH / 0.99 - 37, SCREEN_HEIGHT * .5, "FOR", - false); - display_draw_text(SCREEN_WIDTH / 0.99 - 49, SCREEN_HEIGHT * .6, "CHEATERS", - false); - display_draw_text(SCREEN_WIDTH / 0.99 - 52, SCREEN_HEIGHT * .91, - "PRESS FIRE", false); - - if (input_fire()) - { - fade_e = true; - display_draw_rect(1, 1, 127, 63, false); - } - if (mc == false) - { - m = false; - mc = true; - sound_play(mus_s1_snd, MUS_S1_SND_LEN); - } - } + if (input_fire()) + game_jump_to_scene(SCENE_INTRO); - fade_e = false; - game_jump_to_scene(SCENE_SCORE); + delay(100); } /** @@ -1457,112 +1365,92 @@ void game_run_score_scene(void) */ void game_run_intro_scene(void) { + sound_play(mus_s1_snd, MUS_S1_SND_LEN); + display_draw_bitmap((SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, - (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, bmp_logo_bits, - BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, true); + (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, + bmp_logo_bits, + BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, + true); display_draw_text(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * 0.8f, "PRESS FIRE", - true); - - // sound_play(mus_s1_snd, MUS_S1_SND_LEN); + TEXT_SPACING); if (input_fire()) game_jump_to_scene(SCENE_DIFFICULTY); + + delay(100); } +/** + * @brief GAME run difficulty selection scene. + * + */ void game_run_difficulty_scene(void) { - display_draw_rect(1, 1, 127, 63, false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .05, - "CHOOSE SKILL LEVEL", false); - display_draw_text(SCREEN_WIDTH / 2.75 - 25, SCREEN_HEIGHT * .3, "I", false); - display_draw_text(SCREEN_WIDTH / 2.4 - 25, SCREEN_HEIGHT * .3, - "M TOO YOUNG TO DIE.", false); - display_draw_text(SCREEN_WIDTH / 2.6 - 25, SCREEN_HEIGHT * .26, ",", false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .43, - "HURT ME PLENTY.", false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .56, "NIGHTMARE.", - false); - display_draw_text(SCREEN_WIDTH / 3.32 - 25, SCREEN_HEIGHT * .77, - "NOTE - BUTTONS OUTSIDE", false); - display_draw_text(SCREEN_WIDTH / 4.1 - 25, SCREEN_HEIGHT * .9, - "GAMEPLAY WORK AS U THINK", false); - - if (game_difficulty == 2) - { - display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .43, "#", false); - } - else if (game_difficulty == 1) - { - display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .3, "#", false); - } - else - { - display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .56, "#", false); - } + display_draw_text(7, 5, "CHOOSE YOUR SKILL LEVEL", TEXT_SPACING); + display_draw_text(16, 20, "I M TOO YOUNG TO DIE", TEXT_SPACING); + display_draw_text(20, 17, ",", TEXT_SPACING); + display_draw_text(18, 30, "HURT ME PLENTY", TEXT_SPACING); + display_draw_text(18, 40, "ULTRA VIOLENCE", TEXT_SPACING); + display_draw_text(18, 50, "NIGHTMARE", TEXT_SPACING); + display_draw_text(7, game_difficulty * 10 + 20, "#", TEXT_SPACING); if (input_down()) { - game_difficulty++; - if (game_difficulty == 4) - { - game_difficulty = 1; - } - fade_e = false; - game_jump_to_scene(SCENE_DIFFICULTY); + if (game_difficulty == DIFFICULTY_VERY_HARD) + game_difficulty = DIFFICULTY_EASY; + else + game_difficulty++; } else if (input_up()) { - game_difficulty--; - if (game_difficulty == 0) - { - game_difficulty = 3; - } - fade_e = false; - game_jump_to_scene(SCENE_DIFFICULTY); + if (game_difficulty == DIFFICULTY_EASY) + game_difficulty = DIFFICULTY_VERY_HARD; + else + game_difficulty--; } else if (input_fire()) - { - fade_e = true; game_jump_to_scene(SCENE_MUSIC); - } + + delay(100); } +/** + * @brief GAME run music settings scene. + * + */ void game_run_music_scene(void) { - fade_e = false; - - display_draw_rect(1, 1, 127, 63, false); - display_draw_text(SCREEN_WIDTH / 2.75 - 25, SCREEN_HEIGHT * .25, "MUSIC", - false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .39, "OFF", - false); - display_draw_text(SCREEN_WIDTH / 2.66 - 25, SCREEN_HEIGHT * .50, - "ON (NOT RECOMENDED)", false); - - if (m == false) - { - display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .50, "#", false); - } - else if (m == true) - { - display_draw_text(SCREEN_WIDTH / 3 - 25, SCREEN_HEIGHT * .39, "#", false); - } + display_draw_text(7, 5, "MUSIC SETTINGS", TEXT_SPACING); + display_draw_text(18, 20, "ENABLE", TEXT_SPACING); + display_draw_text(18, 30, "DISABLE", TEXT_SPACING); + display_draw_text(7, enable_music * 10 + 20, "#", TEXT_SPACING); if (input_down() || input_up()) { - m = !m; + enable_music = !enable_music; game_jump_to_scene(SCENE_MUSIC); } else if (input_fire()) - { - fade_e = true; game_jump_to_scene(SCENE_STORY); - } + + delay(100); } +/** + * @brief GAME run level scene. + * + */ void game_run_level_scene(void) { + bool up_pressed = input_up(); + bool down_pressed = input_down(); + bool left_pressed = input_left(); + bool right_pressed = input_right(); + bool fire_pressed = input_fire(); + bool jump_pressed = input_jump(); + display_get_fps(); if (player.ammo == 0) @@ -1570,19 +1458,18 @@ void game_run_level_scene(void) else coll = true; - if (game_level == E1M1) - k = player.ammo; - - if ((player.pos.x >= 2) && (player.pos.x <= 3) && (player.pos.y >= 54) && - (player.pos.y <= 55) && (player.secret < 2)) + if ((player.pos.x >= 2.0f) && (player.pos.x <= 3.0f) && + (player.pos.y >= 54.0f) && (player.pos.y <= 55.0f) && + (player.secret < 2.0f)) { game_spawn_entity(E_ENEMY, 1, 51); game_spawn_entity(E_ENEMY, 3, 51); player.secret++; } - if ((player.pos.x >= 46) && (player.pos.x <= 47) && (player.pos.y >= 35) && - (player.pos.y <= 36) && (game_level == E1M2)) + if ((player.pos.x >= 46.0f) && (player.pos.x <= 47.0f) && + (player.pos.y >= 35.0f) && (player.pos.y <= 36.0f) && + (game_level == E1M2)) { player.pos.x = 12.5; player.pos.y = 33.5; @@ -1591,15 +1478,16 @@ void game_run_level_scene(void) game_spawn_entity(E_ENEMY, 13, 38); bss = true; } - if ((player.pos.y >= 55) && (player.pos.y <= 56) && (player.pos.x >= 12) && - (player.pos.x <= 23) && (game_level == E1M2)) + if ((player.pos.y >= 55.0f) && (player.pos.y <= 56.0f) && + (player.pos.x >= 12.0f) && (player.pos.x <= 23.0f) && + (game_level == E1M2)) { - mid = 3; - m = false; + story_cutscene = CUTSCENE_END; + enable_music = false; sound_play(mus_s1_snd, MUS_S1_SND_LEN); game_jump_to_scene(SCENE_STORY); } - if (game_level == E1M2 && bss == true) + if ((game_level == E1M2) && (bss)) { if ((enemy_count == 1) || (enemy_count == 5) || (enemy_count == 9)) { @@ -1625,111 +1513,85 @@ void game_run_level_scene(void) // If the player is alive if (player.health > 0) { - if ((jump == 1) || (jump == 2)) - { - if ((jump_height > 0) && (jump == 2)) - { - view_height -= 4; - jump_height -= 4; - } - else if ((jump_height < 20) && (jump == 1)) - { - view_height += 4; - jump_height += 4; - } - else if (jump_height == 20) - jump = 2; - else if (jump_height == 0) - jump = 0; - - vel = 2; - } - if (jump == 0) + // Player speed + if (up_pressed || down_pressed) { - view_height = - fabsf(sinf(millis() * JOGGING_SPEED)) * 6 * jogging; - vel = 1; + if (up_pressed) + player.velocity += (MOV_SPEED - player.velocity) * 0.4f; + else + player.velocity += (-MOV_SPEED - player.velocity) * 0.4f; + jogging = fabsf(player.velocity) * GUN_SPEED * 2.0f; } + else + player.velocity *= 0.5f; - // Player speed - if (input_up()) + // Player rotation + if (left_pressed || right_pressed) { - player.velocity += (MOV_SPEED - player.velocity) * .4; - if ((jump == 1) || (jump == 2)) + float old_dir_x = player.dir.x; + float old_plane_x = player.plane.x; + float rot_speed = ROT_SPEED * delta_time; + + if (left_pressed) { - jogging = 0; - gun_pos = 22; + player.dir.x = (player.dir.x * cosf(rot_speed)) - + (player.dir.y * sinf(rot_speed)); + player.dir.y = (old_dir_x * sinf(rot_speed)) + + (player.dir.y * cosf(rot_speed)); + player.plane.x = (player.plane.x * cosf(rot_speed)) - + (player.plane.y * sinf(rot_speed)); + player.plane.y = (old_plane_x * sinf(rot_speed)) + + (player.plane.y * cosf(rot_speed)); } else { - jogging = fabsf(player.velocity) * GUN_SPEED * 2; + player.dir.x = (player.dir.x * cosf(-rot_speed)) - + (player.dir.y * sinf(-rot_speed)); + player.dir.y = (old_dir_x * sinf(-rot_speed)) + + (player.dir.y * cosf(-rot_speed)); + player.plane.x = (player.plane.x * cosf(-rot_speed)) - + (player.plane.y * sinf(-rot_speed)); + player.plane.y = (old_plane_x * sinf(-rot_speed)) + + (player.plane.y * cosf(-rot_speed)); } } - else if (input_down()) + + // Player jump + if (jump_state) { - jogging = fabsf(player.velocity) * GUN_SPEED * 2; - player.velocity += (-MOV_SPEED - player.velocity) * .4; - if (jump == 1 || jump == 2) + if ((jump_height > 0) && (jump_state == 2)) { - jogging = 0; - gun_pos = 22; + view_height -= 4; + jump_height -= 4; } - else + else if ((jump_height < 20) && (jump_state == 1)) { - jogging = fabsf(player.velocity) * GUN_SPEED * 2; + view_height += 4; + jump_height += 4; } + else if (jump_height == 20) + jump_state = 2; + else if (jump_height == 0) + jump_state = 0; + + vel = 2; } else { - if (jump == 1 || jump == 2) + view_height = fabsf(sinf(millis() * JOGGING_SPEED)) * 6 * jogging; + vel = 1; + + if (jump_pressed) { - jogging = 0; + jump_state = 1; + jogging = 0.0f; gun_pos = 22; + sound_play(jump_snd, JUMP_SND_LEN); } - else - { - jogging = fabsf(player.velocity) * GUN_SPEED * 2; - } - player.velocity *= .5; - } - - // Player rotation - if (input_right()) - { - rot_speed = ROT_SPEED * delta_time; - old_dir_x = player.dir.x; - player.dir.x = - player.dir.x * cosf(-rot_speed) - player.dir.y * sinf(-rot_speed); - player.dir.y = - old_dir_x * sinf(-rot_speed) + player.dir.y * cosf(-rot_speed); - old_plane_x = player.plane.x; - player.plane.x = - player.plane.x * cosf(-rot_speed) - player.plane.y * sinf(-rot_speed); - player.plane.y = - old_plane_x * sinf(-rot_speed) + player.plane.y * cosf(-rot_speed); - } - else if (input_left()) - { - rot_speed = ROT_SPEED * delta_time; - old_dir_x = player.dir.x; - player.dir.x = - player.dir.x * cosf(rot_speed) - player.dir.y * sinf(rot_speed); - player.dir.y = - old_dir_x * sinf(rot_speed) + player.dir.y * cosf(rot_speed); - old_plane_x = player.plane.x; - player.plane.x = - player.plane.x * cosf(rot_speed) - player.plane.y * sinf(rot_speed); - player.plane.y = - old_plane_x * sinf(rot_speed) + player.plane.y * cosf(rot_speed); - } - - if (input_jump() && jump == 0) - { - jump = 1; - sound_play(jump_snd, JUMP_SND_LEN); } - if (view_height > 2.95 && jump == 0) + // Player walking sound + if ((view_height > 2.95f) && (jump_state == 0)) { if (walk_sound_toggle) { @@ -1742,52 +1604,47 @@ void game_run_level_scene(void) walk_sound_toggle = true; } } + // Update gun + bool press_fire = input_fire(); if (gun_pos > GUN_TARGET_POS) gun_pos -= 2; // Right after fire else if (gun_pos < GUN_TARGET_POS) gun_pos += 2; // Showing up - else if (!gun_fired && input_fire() && player.ammo > 0 && - reload1 == false) + else if (press_fire && !gun_fired && !reload1) { - // ready to fire and fire pressed + // Ready to fire and fire pressed gun_pos = GUN_SHOT_POS; gun_fired = true; - game_fire_shootgun(); - if (debug == false) + if (player.ammo > 0) + { player.ammo--; + game_fire_shootgun(); + } + else + game_melee_attack(); + + // Clear last HUD text after shooting / melee attack + game_hud_text = TEXT_BLANK_SPACE; } - else if (gun_fired && !input_fire()) + else if (!press_fire && gun_fired) { // Just fired and restored position gun_fired = false; reload1 = true; } - else if (!gun_fired && input_fire() && player.ammo == 0 && - reload1 == false) - { - gun_pos = GUN_SHOT_POS; - gun_fired = true; - game_fire_shootgun(); - } - if (enemy_count == enemy_goal && game_level == E1M1) + if ((enemy_count == enemy_goal) && (game_level == E1M1)) { game_hud_text = TEXT_YOU_WIN; - - if (del == 0) - { - delay(200); - del++; - } - - if (input_fire()) + if (press_fire) { + game_hud_text = TEXT_BLANK_SPACE; player.pos.x = 230; player.pos.y = 50; - mid = 2; enemy_count = 0; - game_hud_text = SCENE_STORY; + story_cutscene = CUTSCENE_E1M2; + game_level = E1M2; } } @@ -1805,31 +1662,26 @@ void game_run_level_scene(void) // The player is dead game_hud_text = TEXT_GAME_OVER; - if (view_height > -5) + if (view_height > -5.0f) view_height--; - - else if (input_fire()) - { + else if (fire_pressed) game_jump_to_scene(SCENE_INTRO); - } + if (gun_pos > 0) gun_pos -= 2; else - { rc1 = 3; - } } - if (reload1 == true) + /** TODO: what is r, rc1? */ + if (reload1) r++; - if (coll == false) + if (!coll) r = 7; if (r == 1) - { rc1 = 1; - } else if (r == 3) { rc1 = 2; @@ -1843,12 +1695,12 @@ void game_run_level_scene(void) else if (r == 7) { r = 0; - reload1 = false; rc1 = 0; + reload1 = false; } // Render stuff - game_render_map(game_level ? game_level : E1M2, view_height); + game_render_map(game_level, view_height); game_render_entities(view_height); game_render_gun(gun_pos, jogging, gun_fired, rc1); @@ -1872,33 +1724,6 @@ void game_run_level_scene(void) // Exit routine if (input_home()) game_jump_to_scene(SCENE_INTRO); - - // Exit routine - // if (input_left() && input_right() && input_up() && input_down() && - // input_fire()) - // { - // z = 3; - // updateHud(); - // if (debug == true) - // { - // z = 3; - // updateHud(); - // z = 10; - // debug = false; - // updateHud(); - // } - // else - // { - // z = 3; - // updateHud(); - // z = 11; - // debug = true; - // updateHud(); - // player.cheats = true; - // } - // updateHud(); - // delay(500); - // } } void main(void) @@ -1910,6 +1735,8 @@ void main(void) input_init(); game_run_scene = game_run_intro_scene; + /** TODO: fix bug with running animation */ + while (!input_exit()) { /* Start drawing */ @@ -1921,15 +1748,14 @@ void main(void) /* Run current game scene */ game_run_scene(); - printf("vel: %f\thp: %d\tammo: %d\ts: %d\ts1: %d\ts2: %d\tscore: %d\tcheats: %d\n", + printf("vel: %f\thp: %d\tammo: %d\ts: %d\ts1: %d\ts2: %d\tscore: %d\n", player.velocity, player.health, player.ammo, player.secret, player.secret2, player.secret3, - player.score, - player.cheats); + player.score); /* Stop drawing */ display_draw_stop(); diff --git a/src/platform.c b/src/platform.c index 9ec2136..ec377ff 100644 --- a/src/platform.c +++ b/src/platform.c @@ -109,8 +109,11 @@ void platform_draw_pixel(uint8_t x, uint8_t y, bool color) */ void platform_audio_play(void) { - audio_is_playing = true; - ResumeAudioStream(audio_stream); + if (!audio_is_playing) + { + audio_is_playing = true; + ResumeAudioStream(audio_stream); + } } /** diff --git a/src/sound.c b/src/sound.c index 4d12b2c..e661407 100644 --- a/src/sound.c +++ b/src/sound.c @@ -42,7 +42,7 @@ void sound_play(const uint8_t *snd, uint8_t len) sound_t0 = platform_millis(); // Execute platform audio player - platform_audio_play(); + // platform_audio_play(); } /** From 5a2018109caab217732190a74417e8f69987bcdc Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 30 Jul 2023 11:30:58 +0200 Subject: [PATCH 12/18] parametrize game stats based on difficulty Signed-off-by: Lorenzo Gualniera --- inc/constants.h | 24 ++++--- src/game.c | 177 ++++++++++++++++++++++-------------------------- 2 files changed, 97 insertions(+), 104 deletions(-) diff --git a/inc/constants.h b/inc/constants.h index 8069147..a7360dc 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -54,7 +54,7 @@ #define JOGGING_SPEED 0.005f #define ENEMY_SPEED 0.04f #define FIREBALL_SPEED 0.2f -#define FIREBALL_ANGLES 45 +#define FIREBALL_ANGLES 45.0f #define MAX_ENTITIES 12 #define MAX_STATIC_ENTITIES 24 @@ -67,19 +67,27 @@ #define ENEMY_MELEE_DIST 9 #define WALL_COLLIDER_DIST 0.2f -#define ENEMY_MELEE_DAMAGE 18 -#define ENEMY_FIREBALL_DAMAGE 25 -#define GUN_MAX_DAMAGE 80 +#define ENEMY_MELEE_DAMAGE_LOW 18 +#define ENEMY_MELEE_DAMAGE_MED 27 +#define ENEMY_MELEE_DAMAGE_HIGH 36 + +#define ENEMY_FIREBALL_DAMAGE_LOW 25 +#define ENEMY_FIREBALL_DAMAGE_MED 50 +#define ENEMY_FIREBALL_DAMAGE_HIGH 75 + +#define GUN_MAX_DAMAGE_HIGH 80 +#define GUN_MAX_DAMAGE_MED 60 +#define GUN_MAX_DAMAGE_LOW 40 #define PLAYER_MAX_HEALTH 100 #define MEDKIT_HEAL_LOW 25 -#define MEDKIT_HEAL_MEDIUM 50 +#define MEDKIT_HEAL_MED 50 #define MEDKIT_HEAL_HIGH 65 #define PLAYER_MAX_AMMO 255 -#define AMMO_NUM_LOW 9 -#define AMMO_NUM_MEDIUM 10 -#define AMMO_NUM_HIGH 13 +#define AMMO_PICKUP_LOW 9 +#define AMMO_PICKUP_MED 10 +#define AMMO_PICKUP_HIGH 13 #define E1M1_ENEMY_GOAL 20 #define E1M2_ENEMY_GOAL 8 diff --git a/src/game.c b/src/game.c index 4a1aedf..0b09841 100644 --- a/src/game.c +++ b/src/game.c @@ -114,7 +114,6 @@ static bool coll = false; static uint8_t jump_state = 0; static uint8_t jump_height = 0; static uint8_t vel = 1; -static uint8_t game_difficulty = DIFFICULTY_EASY; static uint8_t noclip = 0; static bool enable_music = true; static uint8_t rc1 = 0; @@ -135,7 +134,6 @@ static uint8_t enemy_goal = E1M1_ENEMY_GOAL; static uint8_t r = 0; static bool reload1 = false; static int16_t game_score; -static int8_t story_cutscene = CUTSCENE_E1M1; static bool bss = false; static bool mc = false; // init @@ -148,6 +146,13 @@ static float jogging; static bool flash_screen = false; static uint8_t fade_screen = GRADIENT_COUNT - 1; +static uint8_t enemy_melee_damage = ENEMY_MELEE_DAMAGE_LOW; +static uint8_t enemy_fireball_damage = ENEMY_FIREBALL_DAMAGE_LOW; +static uint8_t player_max_damage = GUN_MAX_DAMAGE_HIGH; +static uint8_t medkit_heal_value = MEDKIT_HEAL_HIGH; +static uint8_t ammo_pickup_value = AMMO_PICKUP_HIGH; +static GameCutscene game_cutscene = CUTSCENE_E1M1; +static GameDifficulty game_difficulty = DIFFICULTY_EASY; static GameText game_hud_text = TEXT_GOAL_KILLS; static const uint8_t *game_level = E1M1; static void (*game_run_scene)(void); @@ -541,34 +546,17 @@ void game_fire_shootgun(void) continue; Coords transform = game_translate_into_view(&(entity[i].pos)); - if ((fabsf(transform.x) < 20.0f) && (transform.y > 0)) + if ((fabsf(transform.x) < 20.0f) && (transform.y > 0.0f)) { + // Damage decrease with distance uint8_t damage = MIN( - GUN_MAX_DAMAGE, - (GUN_MAX_DAMAGE / + player_max_damage, + (player_max_damage / (fabsf(transform.x) * entity[i].distance) / 5.0f)); - if (jump_state) - damage /= 3; - - /** TODO: check if difficulty is easy->1, medium->2 etc..*/ - if (game_difficulty == 1) - damage *= 1.5f; - else if (game_difficulty == 2) - damage = damage; - else - damage *= 0.7f; - - if (damage > 0) - { - /** TODO: change this equation so that game difficulty only - * appears in damage calculation - */ - entity[i].health = MAX( - 0, entity[i].health - damage / game_difficulty); - entity[i].state = S_HIT; - entity[i].timer = 2; - } + entity[i].health = MAX(0, entity[i].health - damage); + entity[i].state = S_HIT; + entity[i].timer = 2; } } } @@ -591,31 +579,17 @@ void game_melee_attack(void) continue; Coords transform = game_translate_into_view(&(entity[i].pos)); - if (fabsf(transform.x) < 20 && transform.y > 0) + if ((fabsf(transform.x) < 20.0f) && (transform.y > 0.0f)) { + // Damage decrease with distance uint8_t damage = MIN( - GUN_MAX_DAMAGE, - GUN_MAX_DAMAGE / - (fabsf(transform.x) * entity[i].distance) / 5); - - if (jump_state) - damage = damage / 3; - - /** TODO: sort out difficulty damage calculation */ - if (game_difficulty == 1) - damage = damage + damage / 4.0; - else if (game_difficulty == 2) - damage = damage - damage * 0.1; - else - damage = damage * 0.60; + player_max_damage, + (player_max_damage / + (fabsf(transform.x) * entity[i].distance) / 5.0f)); - if (damage > 0) - { - entity[i].health = MAX( - 0, entity[i].health - damage / game_difficulty); - entity[i].state = S_HIT; - entity[i].timer = 2; - } + entity[i].health = MAX(0, entity[i].health - damage); + entity[i].state = S_HIT; + entity[i].timer = 2; } } } @@ -657,7 +631,7 @@ void game_update_entities(const uint8_t level[]) coords_get_distance(&(player.pos), &(entity[i].pos)); // Run the timer. Works with actual frames. - // Todo: use delta_time here. But needs float type and more memory + // TODO: use delta_time here. But needs float type and more memory if (entity[i].timer > 0) entity[i].timer--; @@ -665,7 +639,7 @@ void game_update_entities(const uint8_t level[]) if (entity[i].distance > MAX_ENTITY_DISTANCE) { game_remove_entity(entity[i].uid); - // don't increase 'i', since current one has been removed + // Don't increase 'i', since current one has been removed continue; } // bypass render if hidden @@ -675,9 +649,7 @@ void game_update_entities(const uint8_t level[]) continue; } - uint8_t type = entities_get_type(entity[i].uid); - - switch (type) + switch (entities_get_type(entity[i].uid)) { /** TODO: move enemy AI to separate function */ case E_ENEMY: @@ -752,10 +724,10 @@ void game_update_entities(const uint8_t level[]) game_update_position( level, &(entity[i].pos), - SIGN(player.pos.x, entity[i].pos.x) * - ENEMY_SPEED * delta_time, - SIGN(player.pos.y, entity[i].pos.y) * - ENEMY_SPEED * delta_time, + (SIGN(player.pos.x, entity[i].pos.x) * + ENEMY_SPEED * delta_time), + (SIGN(player.pos.y, entity[i].pos.y) * + ENEMY_SPEED * delta_time), true); } } @@ -771,8 +743,8 @@ void game_update_entities(const uint8_t level[]) else if (entity[i].timer == 0) { // Melee attack - uint8_t damage = ENEMY_MELEE_DAMAGE * game_difficulty; - player.health = MAX(0, player.health - damage); + player.health = + MAX(0, player.health - enemy_melee_damage); entity[i].timer = 14; flash_screen = true; } @@ -788,8 +760,7 @@ void game_update_entities(const uint8_t level[]) if (entity[i].distance < FIREBALL_COLLIDER_DIST) { // Hit the player and disappear - uint8_t damage = ENEMY_MELEE_DAMAGE * game_difficulty; - player.health = MAX(0, player.health - damage); + player.health = MAX(0, player.health - enemy_fireball_damage); flash_screen = true; game_remove_entity(entity[i].uid); continue; @@ -801,10 +772,10 @@ void game_update_entities(const uint8_t level[]) EntityUID collided = game_update_position( level, &(entity[i].pos), - cosf((float)entity[i].health / FIREBALL_ANGLES * PI) * - FIREBALL_SPEED, - sinf((float)entity[i].health / FIREBALL_ANGLES * PI) * - FIREBALL_SPEED, + (cosf(entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED), + (sinf(entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED), true); if (collided) @@ -826,15 +797,8 @@ void game_update_entities(const uint8_t level[]) sound_play(medkit_snd, MEDKIT_SND_LEN); entity[i].state = S_HIDDEN; - uint16_t health; - if (game_difficulty == 1) - health = player.health + MEDKIT_HEAL_HIGH; - else if (game_difficulty == 2) - health = player.health + MEDKIT_HEAL_MEDIUM; - else - health = player.health + MEDKIT_HEAL_LOW; - - player.health = MIN(PLAYER_MAX_HEALTH, health); + player.health = + MIN(PLAYER_MAX_HEALTH, player.health + medkit_heal_value); flash_screen = true; game_hud_text = TEXT_FOUND_MEDKIT; } @@ -850,16 +814,8 @@ void game_update_entities(const uint8_t level[]) // Pickup sound_play(get_key_snd, GET_KEY_SND_LEN); entity[i].state = S_HIDDEN; - - uint16_t ammo; - if (game_difficulty == 1) - ammo = player.ammo + AMMO_NUM_HIGH; - else if (game_difficulty == 2) - ammo = player.ammo + AMMO_NUM_MEDIUM; - else - ammo = player.ammo + AMMO_NUM_LOW; - - player.ammo = MIN(PLAYER_MAX_AMMO, ammo); + player.ammo = + MIN(PLAYER_MAX_AMMO, player.ammo + ammo_pickup_value); game_hud_text = TEXT_FOUND_AMMO; } break; @@ -1230,12 +1186,7 @@ void game_render_hud_text(void) break; case TEXT_FOUND_AMMO: - if (game_difficulty == 1) - sprintf(text, "FOUND %d AMMO", 13); - else if (game_difficulty == 2) - sprintf(text, "FOUND %d AMMO", 10); - else if (game_difficulty == 3) - sprintf(text, "FOUND %d AMMO", 9); + sprintf(text, "FOUND %d AMMO", ammo_pickup_value); display_draw_text(33, 58, text, TEXT_SPACING); break; @@ -1277,7 +1228,7 @@ void game_render_hud_text(void) */ void game_run_story_scene(void) { - if (story_cutscene == CUTSCENE_E1M1) + if (game_cutscene == CUTSCENE_E1M1) { display_draw_text(0, 0, "YEAR 2027. HUMANS REACHED", TEXT_SPACING); display_draw_text(0, 6, "OTHER PLANETS, BUT WE ARE", TEXT_SPACING); @@ -1288,7 +1239,7 @@ void game_run_story_scene(void) display_draw_text(0, 36, "REMNANTS OF EARTH. RESIST", TEXT_SPACING); display_draw_text(0, 42, "ALIENS TO ESCAPE.", TEXT_SPACING); } - else if (story_cutscene == CUTSCENE_E1M2) + else if (game_cutscene == CUTSCENE_E1M2) { display_draw_text(0, 0, "AFTER KILLING BUNCH OF ", TEXT_SPACING); display_draw_text(0, 6, "ALIENS, LIGHTS TURNED OFF", TEXT_SPACING); @@ -1299,7 +1250,7 @@ void game_run_story_scene(void) display_draw_text(0, 36, "BUT TO START LOOKING FOR ", TEXT_SPACING); display_draw_text(0, 42, "EXIT, WHILE FIGHT ALIENS.", TEXT_SPACING); } - else if (story_cutscene == CUTSCENE_END) + else if (game_cutscene == CUTSCENE_END) { display_draw_text(0, 0, "AFTER HARD FIGHT YOU WENT", TEXT_SPACING); display_draw_text(0, 6, "TO EXIT. AND AS SOON AS", TEXT_SPACING); @@ -1314,7 +1265,7 @@ void game_run_story_scene(void) if (input_fire()) { - if (story_cutscene != CUTSCENE_END) + if (game_cutscene != CUTSCENE_END) game_jump_to_scene(SCENE_LEVEL); else game_jump_to_scene(SCENE_SCORE); @@ -1411,7 +1362,41 @@ void game_run_difficulty_scene(void) game_difficulty--; } else if (input_fire()) + { + // Adjust game settings based on difficulty + switch (game_difficulty) + { + case DIFFICULTY_EASY: + medkit_heal_value = MEDKIT_HEAL_HIGH; + ammo_pickup_value = AMMO_PICKUP_HIGH; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_LOW; + player_max_damage = GUN_MAX_DAMAGE_HIGH; + break; + + case DIFFICULTY_NORMAL: + medkit_heal_value = MEDKIT_HEAL_MED; + ammo_pickup_value = AMMO_PICKUP_MED; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_MED; + player_max_damage = GUN_MAX_DAMAGE_MED; + break; + + case DIFFICULTY_HARD: + medkit_heal_value = MEDKIT_HEAL_LOW; + ammo_pickup_value = AMMO_PICKUP_LOW; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_HIGH; + player_max_damage = GUN_MAX_DAMAGE_LOW; + break; + + /** TODO: increase difficulty for very hard mode */ + case DIFFICULTY_VERY_HARD: + medkit_heal_value = MEDKIT_HEAL_LOW; + ammo_pickup_value = AMMO_PICKUP_LOW; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_HIGH; + player_max_damage = GUN_MAX_DAMAGE_LOW; + break; + } game_jump_to_scene(SCENE_MUSIC); + } delay(100); } @@ -1482,7 +1467,7 @@ void game_run_level_scene(void) (player.pos.x >= 12.0f) && (player.pos.x <= 23.0f) && (game_level == E1M2)) { - story_cutscene = CUTSCENE_END; + game_cutscene = CUTSCENE_END; enable_music = false; sound_play(mus_s1_snd, MUS_S1_SND_LEN); game_jump_to_scene(SCENE_STORY); @@ -1643,7 +1628,7 @@ void game_run_level_scene(void) player.pos.x = 230; player.pos.y = 50; enemy_count = 0; - story_cutscene = CUTSCENE_E1M2; + game_cutscene = CUTSCENE_E1M2; game_level = E1M2; } } From ef1780d6fc039acf92ae263b3c209f6f3fc9df6c Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 30 Jul 2023 13:57:38 +0200 Subject: [PATCH 13/18] fix menu selection selection bug Signed-off-by: Lorenzo Gualniera --- inc/constants.h | 12 +- src/game.c | 709 +++++++++++++++++++++++++----------------------- 2 files changed, 374 insertions(+), 347 deletions(-) diff --git a/inc/constants.h b/inc/constants.h index a7360dc..c29b32e 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -33,11 +33,12 @@ /* Display */ #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 -#define HALF_WIDTH (SCREEN_WIDTH / 2) -#define HALF_HEIGHT (SCREEN_HEIGHT / 2) #define RENDER_HEIGHT 58 #define HUD_HEIGHT 6 +#define COLOR_BLACK 0 +#define COLOR_WHITE 1 + /* Level */ #define LEVEL_WIDTH_BASE 6 #define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) @@ -58,7 +59,6 @@ #define MAX_ENTITIES 12 #define MAX_STATIC_ENTITIES 24 - #define MAX_ENTITY_DISTANCE 200 #define MAX_ENEMY_VIEW 90 #define ITEM_COLLIDER_DIST 6 @@ -89,12 +89,12 @@ #define AMMO_PICKUP_MED 10 #define AMMO_PICKUP_HIGH 13 -#define E1M1_ENEMY_GOAL 20 -#define E1M2_ENEMY_GOAL 8 +#define ENEMY_GOAL1 20 +#define ENEMY_GOAL2 8 #define SCORE_SECRET_ENDING 200 -#define TEXT_SPACING 1 +#define BUTTON_PRESS_WAIT 200 #endif /* CONSTANTS_H */ diff --git a/src/game.c b/src/game.c index 0b09841..4a523d3 100644 --- a/src/game.c +++ b/src/game.c @@ -28,7 +28,9 @@ typedef enum SCENE_INTRO, SCENE_DIFFICULTY, SCENE_MUSIC, - SCENE_STORY, + SCENE_STORY_INTRO, + SCENE_STORY_MID, + SCENE_STORY_END, SCENE_LEVEL, SCENE_SCORE } GameScene; @@ -55,8 +57,8 @@ typedef enum typedef enum { - CUTSCENE_E1M1, - CUTSCENE_E1M2, + CUTSCENE_INTRO, + CUTSCENE_MID, CUTSCENE_END } GameCutscene; @@ -109,17 +111,12 @@ static void game_run_score_scene(void); /* Global variables --------------------------------------------------------- */ -static uint8_t z = 6; static bool coll = false; static uint8_t jump_state = 0; static uint8_t jump_height = 0; -static uint8_t vel = 1; static uint8_t noclip = 0; -static bool enable_music = true; -static uint8_t rc1 = 0; +static bool music_enable = false; static int16_t a = 0; -static uint8_t enemy_count2 = 0; -static uint8_t enemy_goal2 = E1M2_ENEMY_GOAL; // game // player and entities static Player player; @@ -130,28 +127,30 @@ static uint8_t num_static_entities = 0; static uint8_t del = 0; static uint8_t enemy_count = 0; -static uint8_t enemy_goal = E1M1_ENEMY_GOAL; -static uint8_t r = 0; -static bool reload1 = false; +static uint8_t enemy_goal = ENEMY_GOAL1; static int16_t game_score; -static bool bss = false; -static bool mc = false; +static bool game_boss_fight = false; // init static bool gun_fired = false; -static bool walk_sound_toggle = false; -static uint8_t gun_pos = 0; -static float view_height; -static float jogging; +static bool gun_reload = false; +static uint8_t gun_reload_state = 0; +static uint8_t gun_reload_animation = 0; -static bool flash_screen = false; -static uint8_t fade_screen = GRADIENT_COUNT - 1; +static bool player_walk_sound = false; +static uint8_t gun_position = 0; +static float player_view_height; +static float player_jogging; + +static bool screen_flash = false; +static uint8_t screen_fade = GRADIENT_COUNT - 1; +static uint32_t button_press_time = 0; static uint8_t enemy_melee_damage = ENEMY_MELEE_DAMAGE_LOW; static uint8_t enemy_fireball_damage = ENEMY_FIREBALL_DAMAGE_LOW; static uint8_t player_max_damage = GUN_MAX_DAMAGE_HIGH; static uint8_t medkit_heal_value = MEDKIT_HEAL_HIGH; static uint8_t ammo_pickup_value = AMMO_PICKUP_HIGH; -static GameCutscene game_cutscene = CUTSCENE_E1M1; +static GameCutscene game_cutscene = CUTSCENE_INTRO; static GameDifficulty game_difficulty = DIFFICULTY_EASY; static GameText game_hud_text = TEXT_GOAL_KILLS; static const uint8_t *game_level = E1M1; @@ -172,19 +171,26 @@ void game_jump_to_scene(GameScene scene) game_run_scene = game_run_intro_scene; break; - case SCENE_SCORE: - game_run_scene = game_run_score_scene; + case SCENE_DIFFICULTY: + game_run_scene = game_run_difficulty_scene; break; case SCENE_MUSIC: game_run_scene = game_run_music_scene; break; - case SCENE_DIFFICULTY: - game_run_scene = game_run_difficulty_scene; + case SCENE_STORY_INTRO: + game_cutscene = CUTSCENE_INTRO; + game_run_scene = game_run_story_scene; + break; + + case SCENE_STORY_MID: + game_cutscene = CUTSCENE_MID; + game_run_scene = game_run_story_scene; break; - case SCENE_STORY: + case SCENE_STORY_END: + game_cutscene = CUTSCENE_END; game_run_scene = game_run_story_scene; break; @@ -193,10 +199,17 @@ void game_jump_to_scene(GameScene scene) game_run_scene = game_run_level_scene; break; + case SCENE_SCORE: + game_run_scene = game_run_score_scene; + break; + default: game_run_scene = game_run_intro_scene; break; } + + // Reset button press time + button_press_time = millis(); } /** @@ -207,13 +220,17 @@ void game_jump_to_scene(GameScene scene) void game_init_level_scene(const uint8_t level[]) { /** TODO: move this stuff somewhere else */ + gun_position = 0; gun_fired = false; - walk_sound_toggle = false; - gun_pos = 0; - view_height = 0.0f; - jogging = 0.0f; - fade_screen = GRADIENT_COUNT - 1; - mc = false; + gun_reload = false; + gun_reload_state = 0; + gun_reload_animation = 0; + + player_walk_sound = false; + player_view_height = 0.0f; + player_jogging = 0.0f; + + screen_fade = GRADIENT_COUNT - 1; // Initialize game entities memset(entity, 0x00, sizeof(Entity) * MAX_ENTITIES); @@ -222,11 +239,11 @@ void game_init_level_scene(const uint8_t level[]) num_static_entities = 0; // Initialize screen effects - flash_screen = false; - fade_screen = GRADIENT_COUNT - 1; + screen_flash = false; + screen_fade = GRADIENT_COUNT - 1; // Initialize audio effects - walk_sound_toggle = false; + player_walk_sound = false; // Find player in the map and create instance for (uint8_t y = LEVEL_HEIGHT - 1; y >= 0; y--) @@ -517,10 +534,10 @@ EntityUID game_detect_collision(const uint8_t level[], Coords *pos, EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, float rel_y, bool only_walls) { - EntityUID collide_x = - game_detect_collision(level, pos, rel_x, 0.0f, only_walls); - EntityUID collide_y = - game_detect_collision(level, pos, 0.0f, rel_y, only_walls); + EntityUID collide_x = game_detect_collision( + level, pos, rel_x, 0.0f, only_walls); + EntityUID collide_y = game_detect_collision( + level, pos, 0.0f, rel_y, only_walls); if (!collide_x) pos->x += rel_x; @@ -627,8 +644,8 @@ void game_update_entities(const uint8_t level[]) while (i < num_entities) { // update distance - entity[i].distance = - coords_get_distance(&(player.pos), &(entity[i].pos)); + entity[i].distance = coords_get_distance(&(player.pos), + &(entity[i].pos)); // Run the timer. Works with actual frames. // TODO: use delta_time here. But needs float type and more memory @@ -672,14 +689,6 @@ void game_update_entities(const uint8_t level[]) entity[i].a = true; enemy_count++; - - if (bss == true) - enemy_count2++; - } - - /** TODO: why is this here? */ - if (bss == true && enemy_count > 2) - { } } else if (entity[i].state == S_HIT) @@ -743,10 +752,10 @@ void game_update_entities(const uint8_t level[]) else if (entity[i].timer == 0) { // Melee attack - player.health = - MAX(0, player.health - enemy_melee_damage); + player.health = MAX( + 0, player.health - enemy_melee_damage); entity[i].timer = 14; - flash_screen = true; + screen_flash = true; } } else @@ -761,7 +770,7 @@ void game_update_entities(const uint8_t level[]) { // Hit the player and disappear player.health = MAX(0, player.health - enemy_fireball_damage); - flash_screen = true; + screen_flash = true; game_remove_entity(entity[i].uid); continue; } @@ -797,9 +806,9 @@ void game_update_entities(const uint8_t level[]) sound_play(medkit_snd, MEDKIT_SND_LEN); entity[i].state = S_HIDDEN; - player.health = - MIN(PLAYER_MAX_HEALTH, player.health + medkit_heal_value); - flash_screen = true; + player.health = MIN( + PLAYER_MAX_HEALTH, player.health + medkit_heal_value); + screen_flash = true; game_hud_text = TEXT_FOUND_MEDKIT; } break; @@ -814,8 +823,8 @@ void game_update_entities(const uint8_t level[]) // Pickup sound_play(get_key_snd, GET_KEY_SND_LEN); entity[i].state = S_HIDDEN; - player.ammo = - MIN(PLAYER_MAX_AMMO, player.ammo + ammo_pickup_value); + player.ammo = MIN( + PLAYER_MAX_AMMO, player.ammo + ammo_pickup_value); game_hud_text = TEXT_FOUND_AMMO; } break; @@ -839,7 +848,7 @@ void game_render_map(const uint8_t level[], float view_height) for (uint8_t x = 0; x < SCREEN_WIDTH; x += RES_DIVIDER) { - float camera_x = 2 * (float)x / SCREEN_WIDTH - 1; + float camera_x = 2.0f * (float)x / SCREEN_WIDTH - 1.0f; float ray_x = player.dir.x + player.plane.x * camera_x; float ray_y = player.dir.y + player.plane.y * camera_x; uint8_t map_x = (uint8_t)(player.pos.x); @@ -853,7 +862,7 @@ void game_render_map(const uint8_t level[], float view_height) float side_x; float side_y; - if (ray_x < 0) + if (ray_x < 0.0f) { step_x = -1; side_x = (player.pos.x - map_x) * delta_x; @@ -864,7 +873,7 @@ void game_render_map(const uint8_t level[], float view_height) side_x = (map_x + 1.0f - player.pos.x) * delta_x; } - if (ray_y < 0) + if (ray_y < 0.0f) { step_y = -1; side_y = (player.pos.y - map_y) * delta_y; @@ -878,8 +887,8 @@ void game_render_map(const uint8_t level[], float view_height) // Wall detection uint8_t depth = 0; bool hit = false; - bool side; bool coll = false; + bool side; while ((!hit) && (depth < MAX_RENDER_DEPTH)) { if (side_x < side_y) @@ -896,7 +905,6 @@ void game_render_map(const uint8_t level[], float view_height) } uint8_t block = game_get_level_entity(level, map_x, map_y); - if ((block == E_WALL) || (block == E_DOOR) || (block == E_DOOR2) || (block == E_DOOR3) || (block == E_COLL)) { @@ -931,13 +939,12 @@ void game_render_map(const uint8_t level[], float view_height) if (hit) { float distance; - if (side) - distance = - MAX(1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); + distance = MAX( + 1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); else - distance = - MAX(1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); + distance = MAX( + 1, (map_x - player.pos.x + (1 - step_x) / 2) / ray_x); // Store zbuffer value for the column zbuffer[x / Z_RES_DIVIDER] = @@ -947,11 +954,12 @@ void game_render_map(const uint8_t level[], float view_height) uint8_t line_height = RENDER_HEIGHT / distance - 1; display_draw_vline( x, - view_height / distance - line_height / 2 + RENDER_HEIGHT / 2 + - (-17 ? coll : 0), - view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, - GRADIENT_COUNT - (side * 2) - - (distance / MAX_RENDER_DEPTH * GRADIENT_COUNT)); + ((view_height / distance) - (line_height / 2) + + (RENDER_HEIGHT / 2) + (-17 ? coll : 0)), + ((view_height / distance) + (line_height / 2) + + (RENDER_HEIGHT / 2)), + ((GRADIENT_COUNT - (side * 2)) - + (distance / MAX_RENDER_DEPTH * GRADIENT_COUNT))); } } } @@ -999,12 +1007,12 @@ Coords game_translate_into_view(Coords *pos) float sprite_y = pos->y - player.pos.y; // Required for correct matrix multiplication - float inv_det = - 1.0f / (player.plane.x * player.dir.y - player.dir.x * player.plane.y); - float transform_x = - inv_det * (player.dir.y * sprite_x - player.dir.x * sprite_y); - float transform_y = - inv_det * (-player.plane.y * sprite_x + player.plane.x * sprite_y); + float inv_det = 1.0f / (player.plane.x * player.dir.y - + player.dir.x * player.plane.y); + float transform_x = inv_det * (player.dir.y * sprite_x - + player.dir.x * sprite_y); + float transform_y = inv_det * (-player.plane.y * sprite_x + + player.plane.x * sprite_y); return (Coords){transform_x, transform_y}; } @@ -1029,16 +1037,16 @@ void game_render_entities(float view_height) if ((transform.y <= 0.1f) || (transform.y > MAX_SPRITE_DEPTH)) continue; - int16_t sprite_screen_x = - HALF_WIDTH * (1.0f + (transform.x / transform.y)); - int8_t sprite_screen_y = - (RENDER_HEIGHT / 2) + (view_height / transform.y); + int16_t sprite_screen_x = (SCREEN_WIDTH / 2) * + (1.0f + (transform.x / transform.y)); + int8_t sprite_screen_y = (RENDER_HEIGHT / 2) + + (view_height / transform.y); // Don't try to render if outside of screen // doing this pre-shortcut due int16 -> int8 conversion // makes out-of-screen values fit into the screen space - if ((sprite_screen_x < -HALF_WIDTH) || - (sprite_screen_x > SCREEN_WIDTH + HALF_WIDTH)) + if ((sprite_screen_x < -(SCREEN_WIDTH / 2)) || + (sprite_screen_x > SCREEN_WIDTH + (SCREEN_WIDTH / 2))) continue; switch (entities_get_type(entity[i].uid)) @@ -1061,7 +1069,7 @@ void game_render_entities(float view_height) display_draw_sprite( sprite_screen_x - BMP_IMP_WIDTH * 0.5f / transform.y, - sprite_screen_y - 8 / transform.y, bmp_imp_bits, + sprite_screen_y - 8.0f / transform.y, bmp_imp_bits, bmp_imp_mask, BMP_IMP_WIDTH, BMP_IMP_HEIGHT, @@ -1073,8 +1081,8 @@ void game_render_entities(float view_height) case E_FIREBALL: { display_draw_sprite( - sprite_screen_x - BMP_FIREBALL_WIDTH / 2 / transform.y, - sprite_screen_y - BMP_FIREBALL_HEIGHT / 2 / transform.y, + sprite_screen_x - BMP_FIREBALL_WIDTH / 2.0f / transform.y, + sprite_screen_y - BMP_FIREBALL_HEIGHT / 2.0f / transform.y, bmp_fireball_bits, bmp_fireball_mask, BMP_FIREBALL_WIDTH, @@ -1087,8 +1095,8 @@ void game_render_entities(float view_height) case E_MEDKIT: { display_draw_sprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, + sprite_screen_x - BMP_ITEMS_WIDTH / 2.0f / transform.y, + sprite_screen_y + 5.0f / transform.y, bmp_items_bits, bmp_items_mask, BMP_ITEMS_WIDTH, @@ -1101,8 +1109,8 @@ void game_render_entities(float view_height) case E_AMMO: { display_draw_sprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, + sprite_screen_x - BMP_ITEMS_WIDTH / 2.0f / transform.y, + sprite_screen_y + 5.0f / transform.y, bmp_items_bits, bmp_items_mask, BMP_ITEMS_WIDTH, @@ -1125,13 +1133,13 @@ void game_render_gun(uint8_t pos, float jogging, bool fired, uint8_t reload) { // Jogging int8_t x = 48 + sinf(millis() * JOGGING_SPEED) * 10 * jogging - 9; - int8_t y = RENDER_HEIGHT - pos + - fabsf(cosf(millis() * JOGGING_SPEED)) * 8 * jogging - 3; + int8_t y = fabsf(cosf(millis() * JOGGING_SPEED)) * 8 * jogging - 3 - pos + + RENDER_HEIGHT; // Gun fire if ((pos > GUN_SHOT_POS - 2) && (player.ammo > 0) && (fired)) display_draw_bitmap(x + 14, y - 11, bmp_fire_bits, BMP_FIRE_WIDTH, - BMP_FIRE_HEIGHT, 1); + BMP_FIRE_HEIGHT, COLOR_WHITE); // Reload animation uint8_t clip_height; @@ -1140,22 +1148,24 @@ void game_render_gun(uint8_t pos, float jogging, bool fired, uint8_t reload) case 1: clip_height = MAX(0, MIN(y + BMP_RE1_HEIGHT, RENDER_HEIGHT) - y + 22); display_draw_bitmap(x - 10, y - 22, bmp_re1_mask, BMP_RE1_WIDTH, - clip_height, 0); + clip_height, COLOR_BLACK); display_draw_bitmap(x - 10, y - 22, bmp_re1_bits, BMP_RE1_WIDTH, - clip_height, 1); + clip_height, COLOR_WHITE); break; case 2: clip_height = MAX(0, MIN(y + BMP_RE2_HEIGHT, RENDER_HEIGHT) - y + 22); display_draw_bitmap(x - 10, y - 22, bmp_re2_mask, BMP_RE2_WIDTH, - clip_height, 0); + clip_height, COLOR_BLACK); display_draw_bitmap(x - 10, y - 22, bmp_re2_bits, BMP_RE2_WIDTH, - clip_height, 1); + clip_height, COLOR_WHITE); default: clip_height = MAX(0, MIN(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); - display_draw_bitmap(x, y, bmp_gun_mask, BMP_GUN_WIDTH, clip_height, 0); - display_draw_bitmap(x, y, bmp_gun_bits, BMP_GUN_WIDTH, clip_height, 1); + display_draw_bitmap(x, y, bmp_gun_mask, BMP_GUN_WIDTH, clip_height, + COLOR_BLACK); + display_draw_bitmap(x, y, bmp_gun_bits, BMP_GUN_WIDTH, clip_height, + COLOR_WHITE); break; } } @@ -1166,8 +1176,8 @@ void game_render_gun(uint8_t pos, float jogging, bool fired, uint8_t reload) */ void game_render_hud(void) { - display_draw_text(2, 58, "{}", false); - display_draw_text(103, 58, "[]", false); + display_draw_text(2, 58, "{}", 0); + display_draw_text(103, 58, "[]", 0); display_draw_int(12, 58, player.health); display_draw_int(113, 58, player.ammo); } @@ -1187,34 +1197,31 @@ void game_render_hud_text(void) case TEXT_FOUND_AMMO: sprintf(text, "FOUND %d AMMO", ammo_pickup_value); - display_draw_text(33, 58, text, TEXT_SPACING); + display_draw_text(33, 58, text, 1); break; case TEXT_FOUND_MEDKIT: - display_draw_text(33, 58, "FOUND MEDKIT", TEXT_SPACING); + display_draw_text(33, 58, "FOUND MEDKIT", 1); break; case TEXT_FOUND_SECRET: - display_draw_text(33, 58, "FOUND SECRET", TEXT_SPACING); + display_draw_text(33, 58, "FOUND SECRET", 1); case TEXT_GOAL_KILLS: - if (game_level == E1M1) - sprintf(text, "%d OUT OF %d", enemy_count, enemy_goal); - else if ((game_level == E1M2) && (bss == true)) - sprintf(text, "%d OUT OF %d", enemy_count2, enemy_goal2); - display_draw_text(35, 58, text, TEXT_SPACING); + sprintf(text, "%d OUT OF %d", enemy_count, enemy_goal); + display_draw_text(35, 58, text, 1); break; case TEXT_GOAL_FIND_EXIT: - display_draw_text(33, 58, "FIND THE EXIT", TEXT_SPACING); + display_draw_text(33, 58, "FIND THE EXIT", 1); break; case TEXT_GAME_OVER: - display_draw_text(38, 58, "GAME OVER", TEXT_SPACING); + display_draw_text(38, 58, "GAME OVER", 1); break; case TEXT_YOU_WIN: - display_draw_text(44, 58, "YOU WIN", TEXT_SPACING); + display_draw_text(44, 58, "YOU WIN", 1); break; default: @@ -1223,204 +1230,178 @@ void game_render_hud_text(void) } /** - * @brief GAME run story scene. + * @brief GAME run intro scene. * */ -void game_run_story_scene(void) +void game_run_intro_scene(void) { - if (game_cutscene == CUTSCENE_E1M1) - { - display_draw_text(0, 0, "YEAR 2027. HUMANS REACHED", TEXT_SPACING); - display_draw_text(0, 6, "OTHER PLANETS, BUT WE ARE", TEXT_SPACING); - display_draw_text(0, 12, "NOT ALONE, THERE IS ALSO", TEXT_SPACING); - display_draw_text(0, 18, "HOSTILE ALIENS HERE. YOU", TEXT_SPACING); - display_draw_text(0, 24, "ARE AN UNKNOWN MARINE,", TEXT_SPACING); - display_draw_text(0, 30, "WHO FIGHT IN OLD LAB FOR", TEXT_SPACING); - display_draw_text(0, 36, "REMNANTS OF EARTH. RESIST", TEXT_SPACING); - display_draw_text(0, 42, "ALIENS TO ESCAPE.", TEXT_SPACING); - } - else if (game_cutscene == CUTSCENE_E1M2) - { - display_draw_text(0, 0, "AFTER KILLING BUNCH OF ", TEXT_SPACING); - display_draw_text(0, 6, "ALIENS, LIGHTS TURNED OFF", TEXT_SPACING); - display_draw_text(0, 12, "AND THE FLOOR COLLAPSED", TEXT_SPACING); - display_draw_text(0, 18, "UNDER YOUR FEET AND YOU ", TEXT_SPACING); - display_draw_text(0, 24, "FELL INTO THE UTILITY", TEXT_SPACING); - display_draw_text(0, 30, "ROOMS. YOU HAVE NO CHOICE", TEXT_SPACING); - display_draw_text(0, 36, "BUT TO START LOOKING FOR ", TEXT_SPACING); - display_draw_text(0, 42, "EXIT, WHILE FIGHT ALIENS.", TEXT_SPACING); - } - else if (game_cutscene == CUTSCENE_END) - { - display_draw_text(0, 0, "AFTER HARD FIGHT YOU WENT", TEXT_SPACING); - display_draw_text(0, 6, "TO EXIT. AND AS SOON AS", TEXT_SPACING); - display_draw_text(0, 12, "YOU STEP OUT, AN ALIEN", TEXT_SPACING); - display_draw_text(0, 18, "ATTACKS YOU FROM BEHIND", TEXT_SPACING); - display_draw_text(0, 24, "AND KILLS YOU. YOU DIDNT", TEXT_SPACING); - display_draw_text(0, 30, "EXPECT THIS. YOUR FIGHT", TEXT_SPACING); - display_draw_text(0, 36, "CAN NOT END LIKE THIS...", TEXT_SPACING); - display_draw_text(0, 42, "THE END (MAYBE...)", TEXT_SPACING); - } - display_draw_text(39, 53, "PRESS FIRE", TEXT_SPACING); + sound_play(mus_s1_snd, MUS_S1_SND_LEN); - if (input_fire()) - { - if (game_cutscene != CUTSCENE_END) - game_jump_to_scene(SCENE_LEVEL); - else - game_jump_to_scene(SCENE_SCORE); - } + display_draw_bitmap(28, 6, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, + COLOR_WHITE); + display_draw_text(38, 51, "PRESS FIRE", 1); - delay(100); + if (input_fire()) + game_jump_to_scene(SCENE_DIFFICULTY); } /** - * @brief GAME run game over scene. + * @brief GAME run difficulty selection scene. * */ -void game_run_score_scene(void) +void game_run_difficulty_scene(void) { - // Compute game score - game_score = (player.ammo / 2); - game_score += player.health; - game_score *= (game_difficulty + 1); - if (player.secret > 0) - game_score += 100; - if (player.secret2 > 0) - game_score += 100; - if (player.secret3 > 0) - game_score += 100; + display_draw_text(7, 5, "CHOOSE YOUR SKILL LEVEL", 1); + display_draw_text(16, 20, "I M TOO YOUNG TO DIE", 1); + display_draw_text(20, 17, ",", 1); + display_draw_text(18, 30, "HURT ME PLENTY", 1); + display_draw_text(18, 40, "ULTRA VIOLENCE", 1); + display_draw_text(18, 50, "NIGHTMARE", 1); + display_draw_text(7, game_difficulty * 10 + 20, "#", 1); + + uint32_t time = millis(); + if ((time - button_press_time) > BUTTON_PRESS_WAIT) + { + bool up_pressed = input_up(); + bool down_pressed = input_down(); + bool fire_pressed = input_fire(); - display_draw_bitmap( - 8, 8, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, true); - display_draw_text(34, 48, "PICO", TEXT_SPACING); - display_draw_text(88, 8, "YOU WIN", TEXT_SPACING); - display_draw_rect(88, 26, 34, 1, true); - display_draw_text(88, 38, "SCORE:", TEXT_SPACING); - display_draw_int(88, 48, game_score); + if (up_pressed || down_pressed || fire_pressed) + button_press_time = time; - if (game_score > SCORE_SECRET_ENDING) - sound_play(walk1_snd, WALK1_SND_LEN); - else - sound_play(shot_snd, SHOT_SND_LEN); - - if (input_fire()) - game_jump_to_scene(SCENE_INTRO); - - delay(100); + if (down_pressed) + { + if (game_difficulty == DIFFICULTY_VERY_HARD) + game_difficulty = DIFFICULTY_EASY; + else + game_difficulty++; + } + else if (up_pressed) + { + if (game_difficulty == DIFFICULTY_EASY) + game_difficulty = DIFFICULTY_VERY_HARD; + else + game_difficulty--; + } + else if (fire_pressed) + { + // Adjust game settings based on difficulty + switch (game_difficulty) + { + case DIFFICULTY_EASY: + medkit_heal_value = MEDKIT_HEAL_HIGH; + ammo_pickup_value = AMMO_PICKUP_HIGH; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_LOW; + player_max_damage = GUN_MAX_DAMAGE_HIGH; + break; + + case DIFFICULTY_NORMAL: + medkit_heal_value = MEDKIT_HEAL_MED; + ammo_pickup_value = AMMO_PICKUP_MED; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_MED; + player_max_damage = GUN_MAX_DAMAGE_MED; + break; + + case DIFFICULTY_HARD: + medkit_heal_value = MEDKIT_HEAL_LOW; + ammo_pickup_value = AMMO_PICKUP_LOW; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_HIGH; + player_max_damage = GUN_MAX_DAMAGE_LOW; + break; + + /** TODO: increase difficulty for very hard mode */ + case DIFFICULTY_VERY_HARD: + medkit_heal_value = MEDKIT_HEAL_LOW; + ammo_pickup_value = AMMO_PICKUP_LOW; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_HIGH; + player_max_damage = GUN_MAX_DAMAGE_LOW; + break; + } + game_jump_to_scene(SCENE_MUSIC); + } + } } /** - * @brief GAME run intro scene. + * @brief GAME run music settings scene. * */ -void game_run_intro_scene(void) +void game_run_music_scene(void) { - sound_play(mus_s1_snd, MUS_S1_SND_LEN); - - display_draw_bitmap((SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, - (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, - bmp_logo_bits, - BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, - true); - - display_draw_text(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * 0.8f, "PRESS FIRE", - TEXT_SPACING); + display_draw_text(7, 5, "MUSIC SETTINGS", 1); + display_draw_text(18, 20, "DISABLE", 1); + display_draw_text(18, 30, "ENABLE", 1); + display_draw_text(7, music_enable * 10 + 20, "#", 1); - if (input_fire()) - game_jump_to_scene(SCENE_DIFFICULTY); + uint32_t time = millis(); + if ((time - button_press_time) > BUTTON_PRESS_WAIT) + { + bool up_pressed = input_up(); + bool down_pressed = input_down(); + bool fire_pressed = input_fire(); - delay(100); + if (up_pressed || down_pressed) + { + button_press_time = time; + music_enable = !music_enable; + } + else if (fire_pressed) + game_jump_to_scene(SCENE_STORY_INTRO); + } } /** - * @brief GAME run difficulty selection scene. + * @brief GAME run story scene. * */ -void game_run_difficulty_scene(void) +void game_run_story_scene(void) { - display_draw_text(7, 5, "CHOOSE YOUR SKILL LEVEL", TEXT_SPACING); - display_draw_text(16, 20, "I M TOO YOUNG TO DIE", TEXT_SPACING); - display_draw_text(20, 17, ",", TEXT_SPACING); - display_draw_text(18, 30, "HURT ME PLENTY", TEXT_SPACING); - display_draw_text(18, 40, "ULTRA VIOLENCE", TEXT_SPACING); - display_draw_text(18, 50, "NIGHTMARE", TEXT_SPACING); - display_draw_text(7, game_difficulty * 10 + 20, "#", TEXT_SPACING); - - if (input_down()) + if (game_cutscene == CUTSCENE_INTRO) { - if (game_difficulty == DIFFICULTY_VERY_HARD) - game_difficulty = DIFFICULTY_EASY; - else - game_difficulty++; + display_draw_text(0, 0, "YEAR 2027. HUMANS REACHED", 1); + display_draw_text(0, 6, "OTHER PLANETS, BUT WE ARE", 1); + display_draw_text(0, 12, "NOT ALONE, THERE IS ALSO", 1); + display_draw_text(0, 18, "HOSTILE ALIENS HERE. YOU", 1); + display_draw_text(0, 24, "ARE AN UNKNOWN MARINE,", 1); + display_draw_text(0, 30, "WHO FIGHT IN OLD LAB FOR", 1); + display_draw_text(0, 36, "REMNANTS OF EARTH. RESIST", 1); + display_draw_text(0, 42, "ALIENS TO ESCAPE.", 1); } - else if (input_up()) + else if (game_cutscene == CUTSCENE_MID) { - if (game_difficulty == DIFFICULTY_EASY) - game_difficulty = DIFFICULTY_VERY_HARD; - else - game_difficulty--; + display_draw_text(0, 0, "AFTER KILLING BUNCH OF ", 1); + display_draw_text(0, 6, "ALIENS, LIGHTS TURNED OFF", 1); + display_draw_text(0, 12, "AND THE FLOOR COLLAPSED", 1); + display_draw_text(0, 18, "UNDER YOUR FEET AND YOU ", 1); + display_draw_text(0, 24, "FELL INTO THE UTILITY", 1); + display_draw_text(0, 30, "ROOMS. YOU HAVE NO CHOICE", 1); + display_draw_text(0, 36, "BUT TO START LOOKING FOR ", 1); + display_draw_text(0, 42, "EXIT, WHILE FIGHT ALIENS.", 1); } - else if (input_fire()) + else if (game_cutscene == CUTSCENE_END) { - // Adjust game settings based on difficulty - switch (game_difficulty) - { - case DIFFICULTY_EASY: - medkit_heal_value = MEDKIT_HEAL_HIGH; - ammo_pickup_value = AMMO_PICKUP_HIGH; - enemy_melee_damage = ENEMY_MELEE_DAMAGE_LOW; - player_max_damage = GUN_MAX_DAMAGE_HIGH; - break; - - case DIFFICULTY_NORMAL: - medkit_heal_value = MEDKIT_HEAL_MED; - ammo_pickup_value = AMMO_PICKUP_MED; - enemy_melee_damage = ENEMY_MELEE_DAMAGE_MED; - player_max_damage = GUN_MAX_DAMAGE_MED; - break; - - case DIFFICULTY_HARD: - medkit_heal_value = MEDKIT_HEAL_LOW; - ammo_pickup_value = AMMO_PICKUP_LOW; - enemy_melee_damage = ENEMY_MELEE_DAMAGE_HIGH; - player_max_damage = GUN_MAX_DAMAGE_LOW; - break; - - /** TODO: increase difficulty for very hard mode */ - case DIFFICULTY_VERY_HARD: - medkit_heal_value = MEDKIT_HEAL_LOW; - ammo_pickup_value = AMMO_PICKUP_LOW; - enemy_melee_damage = ENEMY_MELEE_DAMAGE_HIGH; - player_max_damage = GUN_MAX_DAMAGE_LOW; - break; - } - game_jump_to_scene(SCENE_MUSIC); + display_draw_text(0, 0, "AFTER HARD FIGHT YOU WENT", 1); + display_draw_text(0, 6, "TO EXIT. AND AS SOON AS", 1); + display_draw_text(0, 12, "YOU STEP OUT, AN ALIEN", 1); + display_draw_text(0, 18, "ATTACKS YOU FROM BEHIND", 1); + display_draw_text(0, 24, "AND KILLS YOU. YOU DIDNT", 1); + display_draw_text(0, 30, "EXPECT THIS. YOUR FIGHT", 1); + display_draw_text(0, 36, "CAN NOT END LIKE THIS...", 1); + display_draw_text(0, 42, "THE END (MAYBE...)", 1); } + display_draw_text(39, 53, "PRESS FIRE", 1); - delay(100); -} - -/** - * @brief GAME run music settings scene. - * - */ -void game_run_music_scene(void) -{ - display_draw_text(7, 5, "MUSIC SETTINGS", TEXT_SPACING); - display_draw_text(18, 20, "ENABLE", TEXT_SPACING); - display_draw_text(18, 30, "DISABLE", TEXT_SPACING); - display_draw_text(7, enable_music * 10 + 20, "#", TEXT_SPACING); - - if (input_down() || input_up()) + uint32_t time = millis(); + if ((time - button_press_time) > BUTTON_PRESS_WAIT) { - enable_music = !enable_music; - game_jump_to_scene(SCENE_MUSIC); + if (input_fire()) + { + if (game_cutscene != CUTSCENE_END) + game_jump_to_scene(SCENE_LEVEL); + else + game_jump_to_scene(SCENE_SCORE); + } } - else if (input_fire()) - game_jump_to_scene(SCENE_STORY); - - delay(100); } /** @@ -1443,6 +1424,7 @@ void game_run_level_scene(void) else coll = true; + // Check if player found secret room if ((player.pos.x >= 2.0f) && (player.pos.x <= 3.0f) && (player.pos.y >= 54.0f) && (player.pos.y <= 55.0f) && (player.secret < 2.0f)) @@ -1452,6 +1434,7 @@ void game_run_level_scene(void) player.secret++; } + // Check if player found the exit in E1M2 if ((player.pos.x >= 46.0f) && (player.pos.x <= 47.0f) && (player.pos.y >= 35.0f) && (player.pos.y <= 36.0f) && (game_level == E1M2)) @@ -1459,20 +1442,23 @@ void game_run_level_scene(void) player.pos.x = 12.5; player.pos.y = 33.5; enemy_count = 0; + enemy_goal = ENEMY_GOAL2; + game_boss_fight = true; game_spawn_entity(E_ENEMY, 10, 38); game_spawn_entity(E_ENEMY, 13, 38); - bss = true; } + + // Check if player got to the end of E1M2 level if ((player.pos.y >= 55.0f) && (player.pos.y <= 56.0f) && (player.pos.x >= 12.0f) && (player.pos.x <= 23.0f) && (game_level == E1M2)) { - game_cutscene = CUTSCENE_END; - enable_music = false; sound_play(mus_s1_snd, MUS_S1_SND_LEN); - game_jump_to_scene(SCENE_STORY); + game_jump_to_scene(SCENE_STORY_END); } - if ((game_level == E1M2) && (bss)) + + /** TODO: what is this for? */ + if ((game_level == E1M2) && (game_boss_fight)) { if ((enemy_count == 1) || (enemy_count == 5) || (enemy_count == 9)) { @@ -1491,7 +1477,6 @@ void game_run_level_scene(void) { player.pos.y = player.pos.y + 12; enemy_count = 0; - enemy_count2 = 8; } } @@ -1505,7 +1490,7 @@ void game_run_level_scene(void) player.velocity += (MOV_SPEED - player.velocity) * 0.4f; else player.velocity += (-MOV_SPEED - player.velocity) * 0.4f; - jogging = fabsf(player.velocity) * GUN_SPEED * 2.0f; + player_jogging = fabsf(player.velocity) * GUN_SPEED * 2.0f; } else player.velocity *= 0.5f; @@ -1546,60 +1531,58 @@ void game_run_level_scene(void) { if ((jump_height > 0) && (jump_state == 2)) { - view_height -= 4; + player_view_height -= 4; jump_height -= 4; } else if ((jump_height < 20) && (jump_state == 1)) { - view_height += 4; + player_view_height += 4; jump_height += 4; } else if (jump_height == 20) jump_state = 2; else if (jump_height == 0) jump_state = 0; - - vel = 2; } else { - view_height = fabsf(sinf(millis() * JOGGING_SPEED)) * 6 * jogging; - vel = 1; + player_view_height = fabsf(sinf(millis() * JOGGING_SPEED)) * 6 * + player_jogging; if (jump_pressed) { jump_state = 1; - jogging = 0.0f; - gun_pos = 22; + player_jogging = 0.0f; + gun_position = 22; sound_play(jump_snd, JUMP_SND_LEN); } } // Player walking sound - if ((view_height > 2.95f) && (jump_state == 0)) + if ((player_view_height > 2.95f) && (jump_state == 0)) { - if (walk_sound_toggle) + if (player_walk_sound) { sound_play(walk1_snd, WALK1_SND_LEN); - walk_sound_toggle = false; + player_walk_sound = false; } else { sound_play(walk2_snd, WALK2_SND_LEN); - walk_sound_toggle = true; + player_walk_sound = true; } } // Update gun bool press_fire = input_fire(); - if (gun_pos > GUN_TARGET_POS) - gun_pos -= 2; // Right after fire - else if (gun_pos < GUN_TARGET_POS) - gun_pos += 2; // Showing up - else if (press_fire && !gun_fired && !reload1) + if (gun_position > GUN_TARGET_POS) + gun_position -= 2; // Right after fire + else if (gun_position < GUN_TARGET_POS) + gun_position += 2; // Showing up + else if (press_fire && !gun_fired && !gun_reload) { // Ready to fire and fire pressed - gun_pos = GUN_SHOT_POS; + gun_position = GUN_SHOT_POS; gun_fired = true; if (player.ammo > 0) { @@ -1616,7 +1599,7 @@ void game_run_level_scene(void) { // Just fired and restored position gun_fired = false; - reload1 = true; + gun_reload = true; } if ((enemy_count == enemy_goal) && (game_level == E1M1)) @@ -1624,20 +1607,20 @@ void game_run_level_scene(void) game_hud_text = TEXT_YOU_WIN; if (press_fire) { - game_hud_text = TEXT_BLANK_SPACE; player.pos.x = 230; player.pos.y = 50; enemy_count = 0; - game_cutscene = CUTSCENE_E1M2; game_level = E1M2; + game_hud_text = TEXT_BLANK_SPACE; + game_jump_to_scene(SCENE_STORY_MID); } } game_update_position( game_level, &(player.pos), - player.dir.x * player.velocity * delta_time * vel, - player.dir.y * player.velocity * delta_time * vel, + player.dir.x * player.velocity * delta_time, + player.dir.y * player.velocity * delta_time, false); game_update_entities(game_level); @@ -1647,63 +1630,73 @@ void game_run_level_scene(void) // The player is dead game_hud_text = TEXT_GAME_OVER; - if (view_height > -5.0f) - view_height--; + if (player_view_height > -5.0f) + player_view_height--; else if (fire_pressed) game_jump_to_scene(SCENE_INTRO); - if (gun_pos > 0) - gun_pos -= 2; + if (gun_position > 0) + gun_position -= 2; else - rc1 = 3; + gun_reload_animation = 3; } - /** TODO: what is r, rc1? */ - if (reload1) - r++; + // Play reload animation and sound + if (gun_reload) + { + if (player.ammo == 0) + gun_reload_state = 7; + else + gun_reload_state++; - if (!coll) - r = 7; + switch (gun_reload_state) + { + case 1: + gun_reload_animation = 1; + break; - if (r == 1) - rc1 = 1; - else if (r == 3) - { - rc1 = 2; - sound_play(r1_snd, R1_SND_LEN); - } - else if (r == 5) - { - rc1 = 1; - sound_play(r2_snd, R2_SND_LEN); - } - else if (r == 7) - { - r = 0; - rc1 = 0; - reload1 = false; + case 3: + gun_reload_animation = 2; + sound_play(r1_snd, R1_SND_LEN); + break; + + case 5: + gun_reload_animation = 1; + sound_play(r2_snd, R2_SND_LEN); + break; + + case 7: + gun_reload_state = 0; + gun_reload_animation = 0; + gun_reload = false; + break; + + default: + break; + } } // Render stuff - game_render_map(game_level, view_height); - game_render_entities(view_height); - game_render_gun(gun_pos, jogging, gun_fired, rc1); + game_render_map(game_level, player_view_height); + game_render_entities(player_view_height); + game_render_gun(gun_position, player_jogging, gun_fired, + gun_reload_animation); // Fade in effect - if (fade_screen > 0) + if (screen_fade > 0) { - display_fade(fade_screen, false); - fade_screen--; + display_fade(screen_fade, COLOR_BLACK); + screen_fade--; return; } game_render_hud(); game_render_hud_text(); // Flash screen - if (flash_screen) + if (screen_flash) { display_invert(); - flash_screen = false; + screen_flash = false; } // Exit routine @@ -1711,6 +1704,40 @@ void game_run_level_scene(void) game_jump_to_scene(SCENE_INTRO); } +/** + * @brief GAME run score scene. + * + */ +void game_run_score_scene(void) +{ + // Compute game score + game_score = (player.ammo / 2); + game_score += player.health; + game_score *= (game_difficulty + 1); + if (player.secret > 0) + game_score += 100; + if (player.secret2 > 0) + game_score += 100; + if (player.secret3 > 0) + game_score += 100; + + display_draw_bitmap(8, 8, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, + COLOR_WHITE); + display_draw_text(34, 48, "PICO", 1); + display_draw_text(88, 8, "YOU WIN", 1); + display_draw_rect(88, 26, 34, 1, COLOR_WHITE); + display_draw_text(88, 38, "SCORE:", 1); + display_draw_int(88, 48, game_score); + + if (game_score > SCORE_SECRET_ENDING) + sound_play(walk1_snd, WALK1_SND_LEN); + else + sound_play(shot_snd, SHOT_SND_LEN); + + if (input_fire()) + game_jump_to_scene(SCENE_INTRO); +} + void main(void) { /* Initialize game */ From e5f9b3917d0952328df8b152d325bf6f503bb642 Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 30 Jul 2023 14:42:48 +0200 Subject: [PATCH 14/18] enable music on/off selection Signed-off-by: Lorenzo Gualniera --- inc/constants.h | 102 +++++++++++++++++++++++---------------------- inc/entities.h | 15 +++---- inc/sound.h | 7 ++-- src/game.c | 107 +++++++++++++++++++++++------------------------- src/sound.c | 12 ++++-- 5 files changed, 122 insertions(+), 121 deletions(-) diff --git a/inc/constants.h b/inc/constants.h index c29b32e..1b6b825 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -21,8 +21,8 @@ * precision taking care of keep numbers inside the type range. * Max is 256 / MAX_RENDER_DEPTH */ #define DISTANCE_MULTIPLIER 20 -#define MAX_RENDER_DEPTH 12 -#define MAX_SPRITE_DEPTH 8 +#define MAX_RENDER_DEPTH 12 +#define MAX_SPRITE_DEPTH 8 /* Faster rendering of vertical lines */ #define OPTIMIZE_RAYCASTING 1 @@ -31,69 +31,75 @@ #define ZBUFFER_SIZE ((SCREEN_WIDTH / Z_RES_DIVIDER) + 4) /* Display */ -#define SCREEN_WIDTH 128 +#define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define RENDER_HEIGHT 58 -#define HUD_HEIGHT 6 +#define HUD_HEIGHT 6 #define COLOR_BLACK 0 #define COLOR_WHITE 1 /* Level */ #define LEVEL_WIDTH_BASE 6 -#define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) -#define LEVEL_HEIGHT 57 -#define LEVEL_SIZE ((LEVEL_WIDTH / 2) * LEVEL_HEIGHT) +#define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) +#define LEVEL_HEIGHT 57 +#define LEVEL_SIZE ((LEVEL_WIDTH / 2) * LEVEL_HEIGHT) /* Game */ #define GUN_TARGET_POS 18 -#define GUN_SHOT_POS (GUN_TARGET_POS + 8) - -#define ROT_SPEED 0.05f -#define MOV_SPEED 0.1f -#define GUN_SPEED 2.5f -#define JOGGING_SPEED 0.005f -#define ENEMY_SPEED 0.04f -#define FIREBALL_SPEED 0.2f +#define GUN_SHOT_POS (GUN_TARGET_POS + 8) + +#define ROT_SPEED 0.05f +#define MOV_SPEED 0.1f +#define GUN_SPEED 2.5f +#define JOGGING_SPEED 0.005f +#define ENEMY_SPEED 0.04f +#define FIREBALL_SPEED 0.2f #define FIREBALL_ANGLES 45.0f -#define MAX_ENTITIES 12 -#define MAX_STATIC_ENTITIES 24 -#define MAX_ENTITY_DISTANCE 200 -#define MAX_ENEMY_VIEW 90 -#define ITEM_COLLIDER_DIST 6 -#define ENEMY_COLLIDER_DIST 4 +#define MAX_ENTITIES 12 +#define MAX_STATIC_ENTITIES 24 +#define MAX_ENTITY_DISTANCE 200 +#define MAX_ENEMY_VIEW 90 +#define ITEM_COLLIDER_DIST 6 +#define ENEMY_COLLIDER_DIST 4 #define FIREBALL_COLLIDER_DIST 3 -#define ENEMY_MELEE_DIST 9 -#define WALL_COLLIDER_DIST 0.2f - -#define ENEMY_MELEE_DAMAGE_LOW 18 -#define ENEMY_MELEE_DAMAGE_MED 27 -#define ENEMY_MELEE_DAMAGE_HIGH 36 - -#define ENEMY_FIREBALL_DAMAGE_LOW 25 -#define ENEMY_FIREBALL_DAMAGE_MED 50 -#define ENEMY_FIREBALL_DAMAGE_HIGH 75 - -#define GUN_MAX_DAMAGE_HIGH 80 -#define GUN_MAX_DAMAGE_MED 60 -#define GUN_MAX_DAMAGE_LOW 40 - -#define PLAYER_MAX_HEALTH 100 -#define MEDKIT_HEAL_LOW 25 -#define MEDKIT_HEAL_MED 50 -#define MEDKIT_HEAL_HIGH 65 - -#define PLAYER_MAX_AMMO 255 -#define AMMO_PICKUP_LOW 9 -#define AMMO_PICKUP_MED 10 -#define AMMO_PICKUP_HIGH 13 - -#define ENEMY_GOAL1 20 -#define ENEMY_GOAL2 8 +#define ENEMY_MELEE_DIST 9 +#define WALL_COLLIDER_DIST 0.2f + +#define ENEMY_MELEE_DAMAGE_EASY 20 +#define ENEMY_MELEE_DAMAGE_NORMAL 30 +#define ENEMY_MELEE_DAMAGE_HARD 40 +#define ENEMY_MELEE_DAMAGE_VERY_HARD 50 + +#define ENEMY_FIREBALL_DAMAGE_EASY 25 +#define ENEMY_FIREBALL_DAMAGE_NORMAL 40 +#define ENEMY_FIREBALL_DAMAGE_HARD 60 +#define ENEMY_FIREBALL_DAMAGE_VERY_HARD 80 + +#define GUN_MAX_DAMAGE_EASY 80 +#define GUN_MAX_DAMAGE_NORMAL 60 +#define GUN_MAX_DAMAGE_HARD 40 +#define GUN_MAX_DAMAGE_VERY_HARD 20 + +#define PLAYER_MAX_HEALTH 100 +#define MEDKIT_HEAL_EASY 100 +#define MEDKIT_HEAL_NORMAL 80 +#define MEDKIT_HEAL_HARD 50 +#define MEDKIT_HEAL_VERY_HARD 30 + +#define PLAYER_MAX_AMMO 255 +#define AMMO_PICKUP_EASY 13 +#define AMMO_PICKUP_NORMAL 10 +#define AMMO_PICKUP_HARD 9 +#define AMMO_PICKUP_VERY_HARD 5 + +#define ENEMY_KILL_GOAL1 20 +#define ENEMY_KILL_GOAL2 8 #define SCORE_SECRET_ENDING 200 +/* Settings */ #define BUTTON_PRESS_WAIT 200 #endif /* CONSTANTS_H */ diff --git a/inc/entities.h b/inc/entities.h index c9a405f..d3a1963 100644 --- a/inc/entities.h +++ b/inc/entities.h @@ -69,8 +69,7 @@ typedef struct uint8_t health; uint8_t distance; uint8_t timer; - bool a; - bool b; + bool drop_item; } Entity; typedef struct @@ -141,8 +140,7 @@ static inline Entity entities_create_enemy(uint8_t x, uint8_t y) .health = 100, .distance = 0, .timer = 0, - .a = false, - .b = false}; + .drop_item = true}; } /** @@ -161,8 +159,7 @@ static inline Entity entities_create_medkit(uint8_t x, uint8_t y) .health = 100, .distance = 0, .timer = 0, - .a = false, - .b = false}; + .drop_item = true}; } /** @@ -181,8 +178,7 @@ static inline Entity entities_create_key(uint8_t x, uint8_t y) .health = 100, .distance = 0, .timer = 0, - .a = false, - .b = false}; + .drop_item = true}; } /** @@ -202,8 +198,7 @@ static inline Entity entities_create_fireball(uint8_t x, uint8_t y, uint8_t dir) .health = dir, .distance = 0, .timer = 0, - .a = false, - .b = false}; + .drop_item = true}; } #endif /* ENTITIES_H */ diff --git a/inc/sound.h b/inc/sound.h index 9c87142..bc99347 100644 --- a/inc/sound.h +++ b/inc/sound.h @@ -190,10 +190,11 @@ void sound_init(void); /** * @brief SOUND update sound and execute platform audio player. * - * @param snd Sound byte array - * @param len Byte length of sound + * @param snd Sound byte array + * @param len Byte length of sound + * @param enable Enable speakers */ -void sound_play(const uint8_t *snd, uint8_t len); +void sound_play(const uint8_t *snd, uint8_t len, bool enable); /** * @brief SOUND get a new frequency from current sound every (1/140)s period, diff --git a/src/game.c b/src/game.c index 4a523d3..9392070 100644 --- a/src/game.c +++ b/src/game.c @@ -127,7 +127,7 @@ static uint8_t num_static_entities = 0; static uint8_t del = 0; static uint8_t enemy_count = 0; -static uint8_t enemy_goal = ENEMY_GOAL1; +static uint8_t enemy_goal = ENEMY_KILL_GOAL1; static int16_t game_score; static bool game_boss_fight = false; // init @@ -145,11 +145,11 @@ static bool screen_flash = false; static uint8_t screen_fade = GRADIENT_COUNT - 1; static uint32_t button_press_time = 0; -static uint8_t enemy_melee_damage = ENEMY_MELEE_DAMAGE_LOW; -static uint8_t enemy_fireball_damage = ENEMY_FIREBALL_DAMAGE_LOW; -static uint8_t player_max_damage = GUN_MAX_DAMAGE_HIGH; -static uint8_t medkit_heal_value = MEDKIT_HEAL_HIGH; -static uint8_t ammo_pickup_value = AMMO_PICKUP_HIGH; +static uint8_t enemy_melee_damage = ENEMY_MELEE_DAMAGE_EASY; +static uint8_t enemy_fireball_damage = ENEMY_FIREBALL_DAMAGE_EASY; +static uint8_t player_max_damage = GUN_MAX_DAMAGE_EASY; +static uint8_t medkit_heal_value = MEDKIT_HEAL_EASY; +static uint8_t ammo_pickup_value = AMMO_PICKUP_EASY; static GameCutscene game_cutscene = CUTSCENE_INTRO; static GameDifficulty game_difficulty = DIFFICULTY_EASY; static GameText game_hud_text = TEXT_GOAL_KILLS; @@ -469,26 +469,26 @@ EntityUID game_detect_collision(const uint8_t level[], Coords *pos, if (block == E_WALL) { - sound_play(hit_wall_snd, HIT_WALL_SND_LEN); + sound_play(hit_wall_snd, HIT_WALL_SND_LEN, music_enable); return entities_get_uid(block, round_x, round_y); } else if ((block == E_DOOR) && (player.secret == false)) { player.secret = true; game_hud_text = TEXT_FOUND_SECRET; - sound_play(s_snd, S_SND_LEN); + sound_play(s_snd, S_SND_LEN, music_enable); } else if ((block == E_DOOR2) && (player.secret2 == false)) { player.secret2 = true; game_hud_text = TEXT_FOUND_SECRET; - sound_play(s_snd, S_SND_LEN); + sound_play(s_snd, S_SND_LEN, music_enable); } else if ((block == E_DOOR3) && (player.secret3 == false)) { player.secret3 = true; game_hud_text = TEXT_FOUND_SECRET; - sound_play(s_snd, S_SND_LEN); + sound_play(s_snd, S_SND_LEN, music_enable); } if (only_walls) @@ -553,7 +553,7 @@ EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, */ void game_fire_shootgun(void) { - sound_play(shoot_snd, SHOOT_SND_LEN); + sound_play(shoot_snd, SHOOT_SND_LEN, music_enable); for (uint8_t i = 0; i < num_entities; i++) { // Shoot only ALIVE enemies @@ -584,7 +584,7 @@ void game_fire_shootgun(void) */ void game_melee_attack(void) { - sound_play(melee_snd, MELEE_SND_LEN); + sound_play(melee_snd, MELEE_SND_LEN, music_enable); for (uint8_t i = 0; i < num_entities; i++) { if (entity[i].distance <= ENEMY_MELEE_DIST) @@ -681,13 +681,12 @@ void game_update_entities(const uint8_t level[]) entity[i].timer = 6; } - /** TODO: what is .a property? */ - if (entity[i].a == false) + if (entity[i].drop_item == true) { EntityType item = game_get_item_drop(); game_spawn_entity(item, entity[i].pos.x, entity[i].pos.y); - entity[i].a = true; + entity[i].drop_item = false; enemy_count++; } } @@ -803,7 +802,7 @@ void game_update_entities(const uint8_t level[]) (jump_height < 14)) { // Pickup - sound_play(medkit_snd, MEDKIT_SND_LEN); + sound_play(medkit_snd, MEDKIT_SND_LEN, music_enable); entity[i].state = S_HIDDEN; player.health = MIN( @@ -821,7 +820,7 @@ void game_update_entities(const uint8_t level[]) (jump_height < 14)) { // Pickup - sound_play(get_key_snd, GET_KEY_SND_LEN); + sound_play(get_key_snd, GET_KEY_SND_LEN, music_enable); entity[i].state = S_HIDDEN; player.ammo = MIN( PLAYER_MAX_AMMO, player.ammo + ammo_pickup_value); @@ -1235,8 +1234,6 @@ void game_render_hud_text(void) */ void game_run_intro_scene(void) { - sound_play(mus_s1_snd, MUS_S1_SND_LEN); - display_draw_bitmap(28, 6, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, COLOR_WHITE); display_draw_text(38, 51, "PRESS FIRE", 1); @@ -1289,34 +1286,34 @@ void game_run_difficulty_scene(void) switch (game_difficulty) { case DIFFICULTY_EASY: - medkit_heal_value = MEDKIT_HEAL_HIGH; - ammo_pickup_value = AMMO_PICKUP_HIGH; - enemy_melee_damage = ENEMY_MELEE_DAMAGE_LOW; - player_max_damage = GUN_MAX_DAMAGE_HIGH; + medkit_heal_value = MEDKIT_HEAL_EASY; + ammo_pickup_value = AMMO_PICKUP_EASY; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_EASY; + player_max_damage = GUN_MAX_DAMAGE_EASY; break; case DIFFICULTY_NORMAL: - medkit_heal_value = MEDKIT_HEAL_MED; - ammo_pickup_value = AMMO_PICKUP_MED; - enemy_melee_damage = ENEMY_MELEE_DAMAGE_MED; - player_max_damage = GUN_MAX_DAMAGE_MED; + medkit_heal_value = MEDKIT_HEAL_NORMAL; + ammo_pickup_value = AMMO_PICKUP_NORMAL; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_NORMAL; + player_max_damage = GUN_MAX_DAMAGE_NORMAL; break; case DIFFICULTY_HARD: - medkit_heal_value = MEDKIT_HEAL_LOW; - ammo_pickup_value = AMMO_PICKUP_LOW; - enemy_melee_damage = ENEMY_MELEE_DAMAGE_HIGH; - player_max_damage = GUN_MAX_DAMAGE_LOW; + medkit_heal_value = MEDKIT_HEAL_HARD; + ammo_pickup_value = AMMO_PICKUP_HARD; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_HARD; + player_max_damage = GUN_MAX_DAMAGE_HARD; break; - /** TODO: increase difficulty for very hard mode */ case DIFFICULTY_VERY_HARD: - medkit_heal_value = MEDKIT_HEAL_LOW; - ammo_pickup_value = AMMO_PICKUP_LOW; - enemy_melee_damage = ENEMY_MELEE_DAMAGE_HIGH; - player_max_damage = GUN_MAX_DAMAGE_LOW; + medkit_heal_value = MEDKIT_HEAL_VERY_HARD; + ammo_pickup_value = AMMO_PICKUP_VERY_HARD; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_HARD; + player_max_damage = GUN_MAX_DAMAGE_VERY_HARD; break; } + game_jump_to_scene(SCENE_MUSIC); } } @@ -1417,8 +1414,6 @@ void game_run_level_scene(void) bool fire_pressed = input_fire(); bool jump_pressed = input_jump(); - display_get_fps(); - if (player.ammo == 0) coll = false; else @@ -1439,10 +1434,10 @@ void game_run_level_scene(void) (player.pos.y >= 35.0f) && (player.pos.y <= 36.0f) && (game_level == E1M2)) { - player.pos.x = 12.5; - player.pos.y = 33.5; + player.pos.x = 12.5f; + player.pos.y = 33.5f; enemy_count = 0; - enemy_goal = ENEMY_GOAL2; + enemy_goal = ENEMY_KILL_GOAL2; game_boss_fight = true; game_spawn_entity(E_ENEMY, 10, 38); game_spawn_entity(E_ENEMY, 13, 38); @@ -1453,7 +1448,7 @@ void game_run_level_scene(void) (player.pos.x >= 12.0f) && (player.pos.x <= 23.0f) && (game_level == E1M2)) { - sound_play(mus_s1_snd, MUS_S1_SND_LEN); + sound_play(mus_s1_snd, MUS_S1_SND_LEN, music_enable); game_jump_to_scene(SCENE_STORY_END); } @@ -1483,18 +1478,20 @@ void game_run_level_scene(void) // If the player is alive if (player.health > 0) { - // Player speed + // Player movement speed if (up_pressed || down_pressed) { if (up_pressed) player.velocity += (MOV_SPEED - player.velocity) * 0.4f; else player.velocity += (-MOV_SPEED - player.velocity) * 0.4f; - player_jogging = fabsf(player.velocity) * GUN_SPEED * 2.0f; } else player.velocity *= 0.5f; + // Player jogging speed animation + player_jogging = fabsf(player.velocity) * GUN_SPEED * 2.0f; + // Player rotation if (left_pressed || right_pressed) { @@ -1548,13 +1545,12 @@ void game_run_level_scene(void) { player_view_height = fabsf(sinf(millis() * JOGGING_SPEED)) * 6 * player_jogging; - if (jump_pressed) { jump_state = 1; player_jogging = 0.0f; gun_position = 22; - sound_play(jump_snd, JUMP_SND_LEN); + sound_play(jump_snd, JUMP_SND_LEN, music_enable); } } @@ -1563,23 +1559,22 @@ void game_run_level_scene(void) { if (player_walk_sound) { - sound_play(walk1_snd, WALK1_SND_LEN); + sound_play(walk1_snd, WALK1_SND_LEN, music_enable); player_walk_sound = false; } else { - sound_play(walk2_snd, WALK2_SND_LEN); + sound_play(walk2_snd, WALK2_SND_LEN, music_enable); player_walk_sound = true; } } // Update gun - bool press_fire = input_fire(); if (gun_position > GUN_TARGET_POS) gun_position -= 2; // Right after fire else if (gun_position < GUN_TARGET_POS) gun_position += 2; // Showing up - else if (press_fire && !gun_fired && !gun_reload) + else if (fire_pressed && !gun_fired && !gun_reload) { // Ready to fire and fire pressed gun_position = GUN_SHOT_POS; @@ -1595,7 +1590,7 @@ void game_run_level_scene(void) // Clear last HUD text after shooting / melee attack game_hud_text = TEXT_BLANK_SPACE; } - else if (!press_fire && gun_fired) + else if (!fire_pressed && gun_fired) { // Just fired and restored position gun_fired = false; @@ -1605,7 +1600,7 @@ void game_run_level_scene(void) if ((enemy_count == enemy_goal) && (game_level == E1M1)) { game_hud_text = TEXT_YOU_WIN; - if (press_fire) + if (fire_pressed) { player.pos.x = 230; player.pos.y = 50; @@ -1657,12 +1652,12 @@ void game_run_level_scene(void) case 3: gun_reload_animation = 2; - sound_play(r1_snd, R1_SND_LEN); + sound_play(r1_snd, R1_SND_LEN, music_enable); break; case 5: gun_reload_animation = 1; - sound_play(r2_snd, R2_SND_LEN); + sound_play(r2_snd, R2_SND_LEN, music_enable); break; case 7: @@ -1730,9 +1725,9 @@ void game_run_score_scene(void) display_draw_int(88, 48, game_score); if (game_score > SCORE_SECRET_ENDING) - sound_play(walk1_snd, WALK1_SND_LEN); + sound_play(walk1_snd, WALK1_SND_LEN, music_enable); else - sound_play(shot_snd, SHOT_SND_LEN); + sound_play(shot_snd, SHOT_SND_LEN, music_enable); if (input_fire()) game_jump_to_scene(SCENE_INTRO); diff --git a/src/sound.c b/src/sound.c index e661407..6f8cf64 100644 --- a/src/sound.c +++ b/src/sound.c @@ -28,11 +28,15 @@ void sound_init(void) /** * @brief SOUND update sound and execute platform audio player. * - * @param snd Sound byte array - * @param len Byte length of sound + * @param snd Sound byte array + * @param len Byte length of sound + * @param enable Enable speakers */ -void sound_play(const uint8_t *snd, uint8_t len) +void sound_play(const uint8_t *snd, uint8_t len, bool enable) { + if (!enable) + return; + // Assign new sound effect sound_ptr = (uint8_t *)snd; sound_len = len; @@ -42,7 +46,7 @@ void sound_play(const uint8_t *snd, uint8_t len) sound_t0 = platform_millis(); // Execute platform audio player - // platform_audio_play(); + platform_audio_play(); } /** From 34a67b22eac5eaadb3ab83488f28ccbfdcf7b087 Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 30 Jul 2023 15:06:21 +0200 Subject: [PATCH 15/18] add scene transition animation Signed-off-by: Lorenzo Gualniera --- inc/entities.h | 4 +- src/game.c | 218 +++++++++++++++++++++++++++++-------------------- 2 files changed, 130 insertions(+), 92 deletions(-) diff --git a/inc/entities.h b/inc/entities.h index d3a1963..52a6e50 100644 --- a/inc/entities.h +++ b/inc/entities.h @@ -58,7 +58,6 @@ typedef struct uint8_t secret; uint8_t secret2; uint8_t secret3; - int16_t score; } Player; typedef struct @@ -120,8 +119,7 @@ static inline Player entities_create_player(uint8_t x, uint8_t y) .ammo = 10, .secret = 0, .secret2 = 0, - .secret3 = 0, - .score = 0}; + .secret3 = 0}; } /** diff --git a/src/game.c b/src/game.c index 9392070..9032b18 100644 --- a/src/game.c +++ b/src/game.c @@ -102,6 +102,7 @@ static void game_render_hud_text(void); /* Scenes */ static void game_jump_to_scene(GameScene scene); +static bool game_scene_transition(void); static void game_run_intro_scene(void); static void game_run_difficulty_scene(void); static void game_run_music_scene(void); @@ -126,8 +127,8 @@ static StaticEntity static_entity[MAX_STATIC_ENTITIES]; static uint8_t num_static_entities = 0; static uint8_t del = 0; -static uint8_t enemy_count = 0; -static uint8_t enemy_goal = ENEMY_KILL_GOAL1; +static uint8_t game_kill_count = 0; +static uint8_t game_kill_goal = ENEMY_KILL_GOAL1; static int16_t game_score; static bool game_boss_fight = false; // init @@ -158,60 +159,6 @@ static void (*game_run_scene)(void); /* Function definitions ----------------------------------------------------- */ -/** - * @brief GAME jump to another scene at the end of the current frame. - * - * @param scene Game scene - */ -void game_jump_to_scene(GameScene scene) -{ - switch (scene) - { - case SCENE_INTRO: - game_run_scene = game_run_intro_scene; - break; - - case SCENE_DIFFICULTY: - game_run_scene = game_run_difficulty_scene; - break; - - case SCENE_MUSIC: - game_run_scene = game_run_music_scene; - break; - - case SCENE_STORY_INTRO: - game_cutscene = CUTSCENE_INTRO; - game_run_scene = game_run_story_scene; - break; - - case SCENE_STORY_MID: - game_cutscene = CUTSCENE_MID; - game_run_scene = game_run_story_scene; - break; - - case SCENE_STORY_END: - game_cutscene = CUTSCENE_END; - game_run_scene = game_run_story_scene; - break; - - case SCENE_LEVEL: - game_init_level_scene(game_level); - game_run_scene = game_run_level_scene; - break; - - case SCENE_SCORE: - game_run_scene = game_run_score_scene; - break; - - default: - game_run_scene = game_run_intro_scene; - break; - } - - // Reset button press time - button_press_time = millis(); -} - /** * @brief GAME initialize level state. * @@ -230,8 +177,6 @@ void game_init_level_scene(const uint8_t level[]) player_view_height = 0.0f; player_jogging = 0.0f; - screen_fade = GRADIENT_COUNT - 1; - // Initialize game entities memset(entity, 0x00, sizeof(Entity) * MAX_ENTITIES); memset(static_entity, 0x00, sizeof(StaticEntity) * MAX_STATIC_ENTITIES); @@ -240,7 +185,6 @@ void game_init_level_scene(const uint8_t level[]) // Initialize screen effects screen_flash = false; - screen_fade = GRADIENT_COUNT - 1; // Initialize audio effects player_walk_sound = false; @@ -348,6 +292,9 @@ void game_spawn_entity(EntityType type, uint8_t x, uint8_t y) entity[num_entities] = entities_create_medkit(x, y); num_entities++; break; + + default: + break; } } @@ -687,7 +634,7 @@ void game_update_entities(const uint8_t level[]) game_spawn_entity(item, entity[i].pos.x, entity[i].pos.y); entity[i].drop_item = false; - enemy_count++; + game_kill_count++; } } else if (entity[i].state == S_HIT) @@ -828,6 +775,9 @@ void game_update_entities(const uint8_t level[]) } break; } + + default: + break; } i++; @@ -1118,6 +1068,9 @@ void game_render_entities(float view_height) transform.y); break; } + + default: + break; } } } @@ -1207,7 +1160,7 @@ void game_render_hud_text(void) display_draw_text(33, 58, "FOUND SECRET", 1); case TEXT_GOAL_KILLS: - sprintf(text, "%d OUT OF %d", enemy_count, enemy_goal); + sprintf(text, "%d OUT OF %d", game_kill_count, game_kill_goal); display_draw_text(35, 58, text, 1); break; @@ -1228,6 +1181,80 @@ void game_render_hud_text(void) } } +/** + * @brief GAME jump to another scene at the end of the current frame. + * + * @param scene Game scene + */ +void game_jump_to_scene(GameScene scene) +{ + switch (scene) + { + case SCENE_INTRO: + game_run_scene = game_run_intro_scene; + break; + + case SCENE_DIFFICULTY: + game_run_scene = game_run_difficulty_scene; + break; + + case SCENE_MUSIC: + game_run_scene = game_run_music_scene; + break; + + case SCENE_STORY_INTRO: + game_cutscene = CUTSCENE_INTRO; + game_run_scene = game_run_story_scene; + break; + + case SCENE_STORY_MID: + game_cutscene = CUTSCENE_MID; + game_run_scene = game_run_story_scene; + break; + + case SCENE_STORY_END: + game_cutscene = CUTSCENE_END; + game_run_scene = game_run_story_scene; + break; + + case SCENE_LEVEL: + game_init_level_scene(game_level); + game_run_scene = game_run_level_scene; + break; + + case SCENE_SCORE: + game_run_scene = game_run_score_scene; + break; + + default: + game_run_scene = game_run_intro_scene; + break; + } + + // Reset button press time + button_press_time = millis(); + + // Reset screen fase animation + screen_fade = GRADIENT_COUNT - 1; +} + +/** + * @brief GAME fade display between scene transitions. + * + * @return Transition animation done + */ +bool game_scene_transition(void) +{ + if (screen_fade > 0) + { + display_fade(screen_fade, COLOR_BLACK); + screen_fade--; + return false; + } + + return true; +} + /** * @brief GAME run intro scene. * @@ -1236,6 +1263,11 @@ void game_run_intro_scene(void) { display_draw_bitmap(28, 6, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, COLOR_WHITE); + + // Wait for transition animation + if (!game_scene_transition()) + return; + display_draw_text(38, 51, "PRESS FIRE", 1); if (input_fire()) @@ -1256,6 +1288,10 @@ void game_run_difficulty_scene(void) display_draw_text(18, 50, "NIGHTMARE", 1); display_draw_text(7, game_difficulty * 10 + 20, "#", 1); + // Wait for transition animation + if (!game_scene_transition()) + return; + uint32_t time = millis(); if ((time - button_press_time) > BUTTON_PRESS_WAIT) { @@ -1312,6 +1348,9 @@ void game_run_difficulty_scene(void) enemy_melee_damage = ENEMY_MELEE_DAMAGE_HARD; player_max_damage = GUN_MAX_DAMAGE_VERY_HARD; break; + + default: + break; } game_jump_to_scene(SCENE_MUSIC); @@ -1330,6 +1369,10 @@ void game_run_music_scene(void) display_draw_text(18, 30, "ENABLE", 1); display_draw_text(7, music_enable * 10 + 20, "#", 1); + // Wait for transition animation + if (!game_scene_transition()) + return; + uint32_t time = millis(); if ((time - button_press_time) > BUTTON_PRESS_WAIT) { @@ -1386,6 +1429,11 @@ void game_run_story_scene(void) display_draw_text(0, 36, "CAN NOT END LIKE THIS...", 1); display_draw_text(0, 42, "THE END (MAYBE...)", 1); } + + // Wait for transition animation + if (!game_scene_transition()) + return; + display_draw_text(39, 53, "PRESS FIRE", 1); uint32_t time = millis(); @@ -1436,8 +1484,8 @@ void game_run_level_scene(void) { player.pos.x = 12.5f; player.pos.y = 33.5f; - enemy_count = 0; - enemy_goal = ENEMY_KILL_GOAL2; + game_kill_count = 0; + game_kill_goal = ENEMY_KILL_GOAL2; game_boss_fight = true; game_spawn_entity(E_ENEMY, 10, 38); game_spawn_entity(E_ENEMY, 13, 38); @@ -1455,23 +1503,23 @@ void game_run_level_scene(void) /** TODO: what is this for? */ if ((game_level == E1M2) && (game_boss_fight)) { - if ((enemy_count == 1) || (enemy_count == 5) || (enemy_count == 9)) + if ((game_kill_count == 1) || (game_kill_count == 5) || (game_kill_count == 9)) { game_clear_dead_enemy(); - enemy_count++; + game_kill_count++; game_spawn_entity(E_ENEMY, 13, 38); } - else if ((enemy_count == 3) || (enemy_count == 7) || - (enemy_count == 11)) + else if ((game_kill_count == 3) || (game_kill_count == 7) || + (game_kill_count == 11)) { game_clear_dead_enemy(); - enemy_count++; + game_kill_count++; game_spawn_entity(E_ENEMY, 10, 38); } - else if (enemy_count == 13) + else if (game_kill_count == 13) { player.pos.y = player.pos.y + 12; - enemy_count = 0; + game_kill_count = 0; } } @@ -1597,14 +1645,14 @@ void game_run_level_scene(void) gun_reload = true; } - if ((enemy_count == enemy_goal) && (game_level == E1M1)) + if ((game_kill_count == game_kill_goal) && (game_level == E1M1)) { game_hud_text = TEXT_YOU_WIN; if (fire_pressed) { player.pos.x = 230; player.pos.y = 50; - enemy_count = 0; + game_kill_count = 0; game_level = E1M2; game_hud_text = TEXT_BLANK_SPACE; game_jump_to_scene(SCENE_STORY_MID); @@ -1677,13 +1725,10 @@ void game_run_level_scene(void) game_render_gun(gun_position, player_jogging, gun_fired, gun_reload_animation); - // Fade in effect - if (screen_fade > 0) - { - display_fade(screen_fade, COLOR_BLACK); - screen_fade--; + // Wait for transition animation + if (!game_scene_transition()) return; - } + game_render_hud(); game_render_hud_text(); @@ -1733,6 +1778,10 @@ void game_run_score_scene(void) game_jump_to_scene(SCENE_INTRO); } +/** + * @brief GAME main function. + * + */ void main(void) { /* Initialize game */ @@ -1742,8 +1791,6 @@ void main(void) input_init(); game_run_scene = game_run_intro_scene; - /** TODO: fix bug with running animation */ - while (!input_exit()) { /* Start drawing */ @@ -1755,16 +1802,9 @@ void main(void) /* Run current game scene */ game_run_scene(); - printf("vel: %f\thp: %d\tammo: %d\ts: %d\ts1: %d\ts2: %d\tscore: %d\n", - player.velocity, - player.health, - player.ammo, - player.secret, - player.secret2, - player.secret3, - player.score); - /* Stop drawing */ display_draw_stop(); } } + +/* -------------------------------------------------------------------------- */ \ No newline at end of file From 3f257f5c0d0cbeb97a41e182760a907feab17c60 Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 30 Jul 2023 15:08:26 +0200 Subject: [PATCH 16/18] fix make run target, avoid running clean Signed-off-by: Lorenzo Gualniera --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 20dbe7f..7e922c3 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,6 @@ $(RAYLIB_DIR): .PHONY: run run: $(RAYLIB_DIR) - $(MAKE) clean $(MAKE) USE_RAYLIB=1 ./$(BIN_DIR)/$(TARGET_EXEC) From d8209261ea913cb41ade5d740d4edda3ce15cb2b Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 30 Jul 2023 15:30:58 +0200 Subject: [PATCH 17/18] change compiled objects bin folder Signed-off-by: Lorenzo Gualniera --- .gitignore | 5 +++-- Makefile | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 76749f2..30e7c7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -.vscode bin -raylib \ No newline at end of file +raylib +doom_pico* +.vscode \ No newline at end of file diff --git a/Makefile b/Makefile index 7e922c3..296bd83 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,8 @@ INC_DIR := inc BIN_DIR := bin RAYLIB_DIR := raylib -SRCS := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s") -OBJS := $(SRCS:%=$(BIN_DIR)/%.o) +SRCS := $(shell find $(SRC_DIR) -name "*.c") +OBJS := $(patsubst $(SRC_DIR)/%,$(BIN_DIR)/%.o,$(SRCS)) DEPS := $(OBJS:.o=.d) CFLAGS := -I$(INC_DIR) -MMD -MP -g @@ -28,10 +28,10 @@ ifeq ($(USE_RAYLIB), 1) endif endif -$(BIN_DIR)/$(TARGET_EXEC): $(OBJS) +$(TARGET_EXEC): $(OBJS) $(CC) $(OBJS) -o $@ $(LDFLAGS) -$(BIN_DIR)/%.c.o: %.c +$(BIN_DIR)/%.c.o: $(SRC_DIR)/%.c $(MKDIR) $(dir $@) $(CC) $(CFLAGS) -c $< -o $@ @@ -41,7 +41,7 @@ $(RAYLIB_DIR): .PHONY: run run: $(RAYLIB_DIR) $(MAKE) USE_RAYLIB=1 - ./$(BIN_DIR)/$(TARGET_EXEC) + ./$(TARGET_EXEC) .PHONY: clean clean: From c857f11ac7ec1ef2d42afa3c70c41718d733bbcc Mon Sep 17 00:00:00 2001 From: Lorenzo Gualniera Date: Sun, 30 Jul 2023 17:51:57 +0200 Subject: [PATCH 18/18] full doom nano brutality refactoring completed Signed-off-by: Lorenzo Gualniera --- inc/constants.h | 7 +- inc/entities.h | 12 +- inc/level.h | 13 +- inc/sprites.h | 2 +- src/entities.c | 2 +- src/game.c | 876 ++++++++++++++++++++++++------------------------ 6 files changed, 460 insertions(+), 452 deletions(-) diff --git a/inc/constants.h b/inc/constants.h index 1b6b825..2ef7b00 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -36,15 +36,10 @@ #define RENDER_HEIGHT 58 #define HUD_HEIGHT 6 +/* Display colors */ #define COLOR_BLACK 0 #define COLOR_WHITE 1 -/* Level */ -#define LEVEL_WIDTH_BASE 6 -#define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) -#define LEVEL_HEIGHT 57 -#define LEVEL_SIZE ((LEVEL_WIDTH / 2) * LEVEL_HEIGHT) - /* Game */ #define GUN_TARGET_POS 18 #define GUN_SHOT_POS (GUN_TARGET_POS + 8) diff --git a/inc/entities.h b/inc/entities.h index 52a6e50..6f74ccc 100644 --- a/inc/entities.h +++ b/inc/entities.h @@ -55,9 +55,9 @@ typedef struct float velocity; uint8_t health; uint8_t ammo; - uint8_t secret; - uint8_t secret2; - uint8_t secret3; + bool secret; + bool secret2; + bool secret3; } Player; typedef struct @@ -117,9 +117,9 @@ static inline Player entities_create_player(uint8_t x, uint8_t y) .velocity = 0.0f, .health = 100, .ammo = 10, - .secret = 0, - .secret2 = 0, - .secret3 = 0}; + .secret = false, + .secret2 = false, + .secret3 = false}; } /** diff --git a/inc/level.h b/inc/level.h index be76121..a946abe 100644 --- a/inc/level.h +++ b/inc/level.h @@ -9,7 +9,12 @@ /* Definitions -------------------------------------------------------------- */ -static const uint8_t E1M1[LEVEL_SIZE] = { +#define LEVEL_WIDTH_BASE 6 +#define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) +#define LEVEL_HEIGHT 57 +#define LEVEL_SIZE ((LEVEL_WIDTH / 2) * LEVEL_HEIGHT) + +static const uint8_t level_e1m1[LEVEL_SIZE] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, @@ -163,7 +168,7 @@ static const uint8_t E1M1[LEVEL_SIZE] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; -static const uint8_t E1M2[LEVEL_SIZE] = { +static const uint8_t level_e1m2[LEVEL_SIZE] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -313,7 +318,9 @@ static const uint8_t E1M2[LEVEL_SIZE] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF}; + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; #endif /* LEVEL_H */ diff --git a/inc/sprites.h b/inc/sprites.h index ee29acf..9567eeb 100644 --- a/inc/sprites.h +++ b/inc/sprites.h @@ -9,7 +9,7 @@ /* Definitions -------------------------------------------------------------- */ -#define bmp_font_width 24 // in bytes +#define bmp_font_width 24 #define bmp_font_height 6 #define CHAR_MAP " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.,-_(){}[]#" #define CHAR_WIDTH 4 diff --git a/src/entities.c b/src/entities.c index 7a32e62..55be372 100644 --- a/src/entities.c +++ b/src/entities.c @@ -3,7 +3,7 @@ #include #include "entities.h" -#include "constants.h" +#include "level.h" /* Function definitions ----------------------------------------------------- */ diff --git a/src/game.c b/src/game.c index 9032b18..cde205e 100644 --- a/src/game.c +++ b/src/game.c @@ -19,8 +19,6 @@ #include "sprites.h" #include "utils.h" -/** TODO: verify if using pointers instead of returning struct is faster */ - /* Data types --------------------------------------------------------------- */ typedef enum @@ -76,7 +74,7 @@ static void game_spawn_entity(EntityType type, uint8_t x, uint8_t y); static void game_spawn_fireball(float x, float y); static void game_remove_entity(EntityUID uid); static void game_remove_static_entity(EntityUID uid); -static void game_clear_dead_enemy(void); +static void game_remove_dead_enemy(void); static void game_update_entities(const uint8_t level[]); static void game_sort_entities(void); @@ -112,50 +110,50 @@ static void game_run_score_scene(void); /* Global variables --------------------------------------------------------- */ -static bool coll = false; -static uint8_t jump_state = 0; -static uint8_t jump_height = 0; -static uint8_t noclip = 0; -static bool music_enable = false; -static int16_t a = 0; -// game -// player and entities +/* Player */ static Player player; +static bool player_walk_sound = false; +static float player_view_height = 0.0f; +static float player_jogging = 0.0f; +static uint8_t player_jump_state = 0; +static uint8_t player_jump_height = 0; + +/* Entities */ static Entity entity[MAX_ENTITIES]; static uint8_t num_entities = 0; static StaticEntity static_entity[MAX_STATIC_ENTITIES]; static uint8_t num_static_entities = 0; -static uint8_t del = 0; -static uint8_t game_kill_count = 0; -static uint8_t game_kill_goal = ENEMY_KILL_GOAL1; -static int16_t game_score; -static bool game_boss_fight = false; -// init +/* Gun */ static bool gun_fired = false; static bool gun_reload = false; +static uint8_t gun_position = 0; static uint8_t gun_reload_state = 0; static uint8_t gun_reload_animation = 0; -static bool player_walk_sound = false; -static uint8_t gun_position = 0; -static float player_view_height; -static float player_jogging; - +/* Display */ static bool screen_flash = false; static uint8_t screen_fade = GRADIENT_COUNT - 1; -static uint32_t button_press_time = 0; + +/* Game */ +static uint32_t game_button_time = 0; +static bool game_music_enable = false; +static GameCutscene game_cutscene = CUTSCENE_INTRO; +static GameDifficulty game_difficulty = DIFFICULTY_EASY; +static GameText game_hud_text = TEXT_BLANK_SPACE; +static const uint8_t *game_level = level_e1m1; +static void (*game_run_scene)(void) = game_run_intro_scene; + +static int16_t game_score = 0; +static uint8_t game_kill_count = 0; +static uint8_t game_kill_goal = ENEMY_KILL_GOAL1; +static bool game_boss_fight = false; static uint8_t enemy_melee_damage = ENEMY_MELEE_DAMAGE_EASY; static uint8_t enemy_fireball_damage = ENEMY_FIREBALL_DAMAGE_EASY; static uint8_t player_max_damage = GUN_MAX_DAMAGE_EASY; static uint8_t medkit_heal_value = MEDKIT_HEAL_EASY; static uint8_t ammo_pickup_value = AMMO_PICKUP_EASY; -static GameCutscene game_cutscene = CUTSCENE_INTRO; -static GameDifficulty game_difficulty = DIFFICULTY_EASY; -static GameText game_hud_text = TEXT_GOAL_KILLS; -static const uint8_t *game_level = E1M1; -static void (*game_run_scene)(void); /* Function definitions ----------------------------------------------------- */ @@ -166,28 +164,33 @@ static void (*game_run_scene)(void); */ void game_init_level_scene(const uint8_t level[]) { - /** TODO: move this stuff somewhere else */ - gun_position = 0; - gun_fired = false; - gun_reload = false; - gun_reload_state = 0; - gun_reload_animation = 0; - + /* Player */ player_walk_sound = false; player_view_height = 0.0f; player_jogging = 0.0f; + player_jump_state = 0; + player_jump_height = 0; - // Initialize game entities + /* Entities */ memset(entity, 0x00, sizeof(Entity) * MAX_ENTITIES); - memset(static_entity, 0x00, sizeof(StaticEntity) * MAX_STATIC_ENTITIES); num_entities = 0; + memset(static_entity, 0x00, sizeof(StaticEntity) * MAX_STATIC_ENTITIES); num_static_entities = 0; - // Initialize screen effects - screen_flash = false; + /* Gun */ + gun_position = 0; + gun_fired = false; + gun_reload = false; + gun_reload_state = 0; + gun_reload_animation = 0; - // Initialize audio effects - player_walk_sound = false; + /* Game */ + game_kill_count = 0; + game_boss_fight = false; + if (game_level == level_e1m1) + game_hud_text = TEXT_GOAL_KILLS; + else if ((game_level == level_e1m2) && (!game_boss_fight)) + game_hud_text = TEXT_GOAL_FIND_EXIT; // Find player in the map and create instance for (uint8_t y = LEVEL_HEIGHT - 1; y >= 0; y--) @@ -195,10 +198,13 @@ void game_init_level_scene(const uint8_t level[]) for (uint8_t x = 0; x < LEVEL_WIDTH; x++) { uint8_t block = game_get_level_entity(level, x, y); - if (block == E_PLAYER) { player = entities_create_player(x, y); + player.pos.y = 55.0f; + player.pos.x = 12.0f; + game_level = level_e1m2; + game_boss_fight=true; return; } @@ -381,7 +387,7 @@ void game_remove_static_entity(EntityUID uid) * @brief GAME clear farthest dead enemy entity. * */ -void game_clear_dead_enemy(void) +void game_remove_dead_enemy(void) { uint8_t i = num_entities - 1; while (i >= 0) @@ -396,190 +402,6 @@ void game_clear_dead_enemy(void) } } -/** - * @brief GAME detect collision between entities and level blocks. - * - * @param level Level byte map - * @param pos Position to be checked - * @param rel_x X relative direction - * @param rel_y Y relative direction - * @param only_walls Check only walls collisions - * @return EntityUID Entity UID number - */ -EntityUID game_detect_collision(const uint8_t level[], Coords *pos, - float rel_x, float rel_y, bool only_walls) -{ - // Wall collision - uint8_t round_x = pos->x + rel_x; - uint8_t round_y = pos->y + rel_y; - uint8_t block = game_get_level_entity(level, round_x, round_y); - - if (block == E_WALL) - { - sound_play(hit_wall_snd, HIT_WALL_SND_LEN, music_enable); - return entities_get_uid(block, round_x, round_y); - } - else if ((block == E_DOOR) && (player.secret == false)) - { - player.secret = true; - game_hud_text = TEXT_FOUND_SECRET; - sound_play(s_snd, S_SND_LEN, music_enable); - } - else if ((block == E_DOOR2) && (player.secret2 == false)) - { - player.secret2 = true; - game_hud_text = TEXT_FOUND_SECRET; - sound_play(s_snd, S_SND_LEN, music_enable); - } - else if ((block == E_DOOR3) && (player.secret3 == false)) - { - player.secret3 = true; - game_hud_text = TEXT_FOUND_SECRET; - sound_play(s_snd, S_SND_LEN, music_enable); - } - - if (only_walls) - return UID_NULL; - - // Entity collision - for (uint8_t i = 0; i < num_entities; i++) - { - // Don't collide with itself - if (&(entity[i].pos) == pos) - continue; - - EntityType type = entities_get_type(entity[i].uid); - - // Only ALIVE enemy collision - if ((type != E_ENEMY) || - (entity[i].state == S_DEAD) || - (entity[i].state == S_HIDDEN)) - continue; - - Coords new_coords = {entity[i].pos.x - rel_x, entity[i].pos.y - rel_y}; - uint8_t distance = coords_get_distance(pos, &new_coords); - - // Check distance and if it's getting closer - if ((distance < ENEMY_COLLIDER_DIST) && - (distance < entity[i].distance)) - return entity[i].uid; - } - - return UID_NULL; -} - -/** - * @brief GAME update position if possible, otherwise return collided uid. - * - * @param level Level byte map - * @param pos Position to be checked - * @param rel_x X relative direction - * @param rel_y Y relative direction - * @param only_walls Check only walls collisions - * @return EntityUID Entity UID number - */ -EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, - float rel_y, bool only_walls) -{ - EntityUID collide_x = game_detect_collision( - level, pos, rel_x, 0.0f, only_walls); - EntityUID collide_y = game_detect_collision( - level, pos, 0.0f, rel_y, only_walls); - - if (!collide_x) - pos->x += rel_x; - if (!collide_y) - pos->y += rel_y; - - return (collide_x || collide_y || UID_NULL); -} - -/** - * @brief GAME player fire shootgun and compute damage. - * - */ -void game_fire_shootgun(void) -{ - sound_play(shoot_snd, SHOOT_SND_LEN, music_enable); - for (uint8_t i = 0; i < num_entities; i++) - { - // Shoot only ALIVE enemies - if ((entities_get_type(entity[i].uid) != E_ENEMY) || - (entity[i].state == S_DEAD) || - (entity[i].state == S_HIDDEN)) - continue; - - Coords transform = game_translate_into_view(&(entity[i].pos)); - if ((fabsf(transform.x) < 20.0f) && (transform.y > 0.0f)) - { - // Damage decrease with distance - uint8_t damage = MIN( - player_max_damage, - (player_max_damage / - (fabsf(transform.x) * entity[i].distance) / 5.0f)); - - entity[i].health = MAX(0, entity[i].health - damage); - entity[i].state = S_HIT; - entity[i].timer = 2; - } - } -} - -/** - * @brief GAME player perform melee attack and compute damage. - * - */ -void game_melee_attack(void) -{ - sound_play(melee_snd, MELEE_SND_LEN, music_enable); - for (uint8_t i = 0; i < num_entities; i++) - { - if (entity[i].distance <= ENEMY_MELEE_DIST) - { - // Attack only ALIVE enemies - if ((entities_get_type(entity[i].uid) != E_ENEMY) || - (entity[i].state == S_DEAD) || - (entity[i].state == S_HIDDEN)) - continue; - - Coords transform = game_translate_into_view(&(entity[i].pos)); - if ((fabsf(transform.x) < 20.0f) && (transform.y > 0.0f)) - { - // Damage decrease with distance - uint8_t damage = MIN( - player_max_damage, - (player_max_damage / - (fabsf(transform.x) * entity[i].distance) / 5.0f)); - - entity[i].health = MAX(0, entity[i].health - damage); - entity[i].state = S_HIT; - entity[i].timer = 2; - } - } - } -} - -/** - * @brief GAME get random item drop. - * - * @return EntityType Random item between ammo, medkit, or nothing - */ -EntityType game_get_item_drop(void) -{ - EntityType item = 0; - - uint8_t random_item = rand() % 4; - if (random_item > 0) - { - if (random_item < 3) - item = E_AMMO; - else - item = E_MEDKIT; - } - - return item; -} - /** * @brief GAME execute entities AI logic. * @@ -590,23 +412,27 @@ void game_update_entities(const uint8_t level[]) uint8_t i = 0; while (i < num_entities) { - // update distance + // Update distance entity[i].distance = coords_get_distance(&(player.pos), &(entity[i].pos)); // Run the timer. Works with actual frames. - // TODO: use delta_time here. But needs float type and more memory if (entity[i].timer > 0) entity[i].timer--; - // too far away. put it in doze mode + // Keep dead entities number under control + if (num_entities > MAX_ENTITIES) + game_remove_dead_enemy(); + + // Too far away. put it in doze mode if (entity[i].distance > MAX_ENTITY_DISTANCE) { game_remove_entity(entity[i].uid); // Don't increase 'i', since current one has been removed continue; } - // bypass render if hidden + + // Bypass render if hidden if (entity[i].state == S_HIDDEN) { i++; @@ -615,7 +441,6 @@ void game_update_entities(const uint8_t level[]) switch (entities_get_type(entity[i].uid)) { - /** TODO: move enemy AI to separate function */ case E_ENEMY: { // Enemy "IA" @@ -623,7 +448,8 @@ void game_update_entities(const uint8_t level[]) { if (entity[i].state != S_DEAD) { - game_hud_text = TEXT_GOAL_KILLS; + if (game_level == level_e1m1) + game_hud_text = TEXT_GOAL_KILLS; entity[i].state = S_DEAD; entity[i].timer = 6; } @@ -710,78 +536,315 @@ void game_update_entities(const uint8_t level[]) break; } - case E_FIREBALL: - { - if (entity[i].distance < FIREBALL_COLLIDER_DIST) - { - // Hit the player and disappear - player.health = MAX(0, player.health - enemy_fireball_damage); - screen_flash = true; - game_remove_entity(entity[i].uid); - continue; - } - else - { - // Move. Only collide with walls. - // Note: using health to store the angle of the movement - EntityUID collided = game_update_position( - level, - &(entity[i].pos), - (cosf(entity[i].health / FIREBALL_ANGLES * PI) * - FIREBALL_SPEED), - (sinf(entity[i].health / FIREBALL_ANGLES * PI) * - FIREBALL_SPEED), - true); + case E_FIREBALL: + { + if (entity[i].distance < FIREBALL_COLLIDER_DIST) + { + // Hit the player and disappear + player.health = MAX(0, player.health - enemy_fireball_damage); + screen_flash = true; + game_remove_entity(entity[i].uid); + continue; + } + else + { + // Move. Only collide with walls. + // Note: using health to store the angle of the movement + EntityUID collided = game_update_position( + level, + &(entity[i].pos), + (cosf(entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED), + (sinf(entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED), + true); + + if (collided) + { + game_remove_entity(entity[i].uid); + continue; + } + } + break; + } + + case E_MEDKIT: + { + if ((entity[i].distance < ITEM_COLLIDER_DIST) && + (player.health != PLAYER_MAX_HEALTH) && + (player_jump_height < 14)) + { + // Pickup + sound_play(medkit_snd, MEDKIT_SND_LEN, game_music_enable); + entity[i].state = S_HIDDEN; + + player.health = MIN( + PLAYER_MAX_HEALTH, player.health + medkit_heal_value); + screen_flash = true; + game_hud_text = TEXT_FOUND_MEDKIT; + } + break; + } + + case E_AMMO: + { + if ((entity[i].distance < ITEM_COLLIDER_DIST) && + (player.ammo < PLAYER_MAX_AMMO) && + (player_jump_height < 14)) + { + // Pickup + sound_play(get_key_snd, GET_KEY_SND_LEN, game_music_enable); + entity[i].state = S_HIDDEN; + player.ammo = MIN( + PLAYER_MAX_AMMO, player.ammo + ammo_pickup_value); + game_hud_text = TEXT_FOUND_AMMO; + } + break; + } + + default: + break; + } + + i++; + } +} + +/** + * @brief GAME sort entities from far to close. + * + */ +void game_sort_entities(void) +{ + uint8_t gap = num_entities; + bool swapped = false; + while ((gap > 1) || (swapped)) + { + // shrink factor 1.3 + gap = (gap * 10) / 13; + if ((gap == 9) || (gap == 10)) + gap = 11; + if (gap < 1) + gap = 1; + + swapped = false; + for (uint8_t i = 0; i < num_entities - gap; i++) + { + uint8_t j = i + gap; + if (entity[i].distance < entity[j].distance) + { + SWAP(entity[i], entity[j]); + swapped = true; + } + } + } +} + +/** + * @brief GAME detect collision between entities and level blocks. + * + * @param level Level byte map + * @param pos Position to be checked + * @param rel_x X relative direction + * @param rel_y Y relative direction + * @param only_walls Check only walls collisions + * @return EntityUID Entity UID number + */ +EntityUID game_detect_collision(const uint8_t level[], Coords *pos, + float rel_x, float rel_y, bool only_walls) +{ + // Wall collision + uint8_t round_x = pos->x + rel_x; + uint8_t round_y = pos->y + rel_y; + uint8_t block = game_get_level_entity(level, round_x, round_y); + + if (block == E_WALL) + { + sound_play(hit_wall_snd, HIT_WALL_SND_LEN, game_music_enable); + return entities_get_uid(block, round_x, round_y); + } + else if ((block == E_DOOR) && (player.secret == false)) + { + player.secret = true; + game_hud_text = TEXT_FOUND_SECRET; + sound_play(s_snd, S_SND_LEN, game_music_enable); + } + else if ((block == E_DOOR2) && (player.secret2 == false)) + { + player.secret2 = true; + game_hud_text = TEXT_FOUND_SECRET; + sound_play(s_snd, S_SND_LEN, game_music_enable); + } + else if ((block == E_DOOR3) && (player.secret3 == false)) + { + player.secret3 = true; + game_hud_text = TEXT_FOUND_SECRET; + sound_play(s_snd, S_SND_LEN, game_music_enable); + } + + if (only_walls) + return UID_NULL; + + // Entity collision + for (uint8_t i = 0; i < num_entities; i++) + { + // Don't collide with itself + if (&(entity[i].pos) == pos) + continue; + + EntityType type = entities_get_type(entity[i].uid); + + // Only ALIVE enemy collision + if ((type != E_ENEMY) || + (entity[i].state == S_DEAD) || + (entity[i].state == S_HIDDEN)) + continue; + + Coords new_coords = {entity[i].pos.x - rel_x, entity[i].pos.y - rel_y}; + uint8_t distance = coords_get_distance(pos, &new_coords); + + // Check distance and if it's getting closer + if ((distance < ENEMY_COLLIDER_DIST) && + (distance < entity[i].distance)) + return entity[i].uid; + } + + return UID_NULL; +} + +/** + * @brief GAME update position if possible, otherwise return collided uid. + * + * @param level Level byte map + * @param pos Position to be checked + * @param rel_x X relative direction + * @param rel_y Y relative direction + * @param only_walls Check only walls collisions + * @return EntityUID Entity UID number + */ +EntityUID game_update_position(const uint8_t level[], Coords *pos, float rel_x, + float rel_y, bool only_walls) +{ + EntityUID collide_x = game_detect_collision( + level, pos, rel_x, 0.0f, only_walls); + EntityUID collide_y = game_detect_collision( + level, pos, 0.0f, rel_y, only_walls); + + if (!collide_x) + pos->x += rel_x; + if (!collide_y) + pos->y += rel_y; - if (collided) - { - game_remove_entity(entity[i].uid); - continue; - } - } - break; - } + return (collide_x || collide_y || UID_NULL); +} - case E_MEDKIT: +/** + * @brief GAME player fire shootgun and compute damage. + * + */ +void game_fire_shootgun(void) +{ + sound_play(shoot_snd, SHOOT_SND_LEN, game_music_enable); + for (uint8_t i = 0; i < num_entities; i++) + { + // Shoot only ALIVE enemies + if ((entities_get_type(entity[i].uid) != E_ENEMY) || + (entity[i].state == S_DEAD) || + (entity[i].state == S_HIDDEN)) + continue; + + Coords transform = game_translate_into_view(&(entity[i].pos)); + if ((fabsf(transform.x) < 20.0f) && (transform.y > 0.0f)) { - if ((entity[i].distance < ITEM_COLLIDER_DIST) && - (player.health != PLAYER_MAX_HEALTH) && - (jump_height < 14)) - { - // Pickup - sound_play(medkit_snd, MEDKIT_SND_LEN, music_enable); - entity[i].state = S_HIDDEN; + // Damage decrease with distance + uint8_t damage = MIN( + player_max_damage, + (player_max_damage / + (fabsf(transform.x) * entity[i].distance) / 5.0f)); - player.health = MIN( - PLAYER_MAX_HEALTH, player.health + medkit_heal_value); - screen_flash = true; - game_hud_text = TEXT_FOUND_MEDKIT; - } - break; + entity[i].health = MAX(0, entity[i].health - damage); + entity[i].state = S_HIT; + entity[i].timer = 2; } + } +} - case E_AMMO: +/** + * @brief GAME player perform melee attack and compute damage. + * + */ +void game_melee_attack(void) +{ + sound_play(melee_snd, MELEE_SND_LEN, game_music_enable); + for (uint8_t i = 0; i < num_entities; i++) + { + if (entity[i].distance <= ENEMY_MELEE_DIST) { - if ((entity[i].distance < ITEM_COLLIDER_DIST) && - (player.ammo < PLAYER_MAX_AMMO) && - (jump_height < 14)) + // Attack only ALIVE enemies + if ((entities_get_type(entity[i].uid) != E_ENEMY) || + (entity[i].state == S_DEAD) || + (entity[i].state == S_HIDDEN)) + continue; + + Coords transform = game_translate_into_view(&(entity[i].pos)); + if ((fabsf(transform.x) < 20.0f) && (transform.y > 0.0f)) { - // Pickup - sound_play(get_key_snd, GET_KEY_SND_LEN, music_enable); - entity[i].state = S_HIDDEN; - player.ammo = MIN( - PLAYER_MAX_AMMO, player.ammo + ammo_pickup_value); - game_hud_text = TEXT_FOUND_AMMO; + // Damage decrease with distance + uint8_t damage = MIN( + player_max_damage, + (player_max_damage / + (fabsf(transform.x) * entity[i].distance) / 5.0f)); + + entity[i].health = MAX(0, entity[i].health - damage); + entity[i].state = S_HIT; + entity[i].timer = 2; } - break; } + } +} - default: - break; - } +/** + * @brief GAME get random item drop. + * + * @return EntityType Random item between ammo, medkit, or nothing + */ +EntityType game_get_item_drop(void) +{ + EntityType item = 0; - i++; + uint8_t random_item = rand() % 4; + if (random_item > 0) + { + if (random_item < 3) + item = E_AMMO; + else + item = E_MEDKIT; } + + return item; +} + +/** + * @brief GAME translate 2D map coordinates into camera coordinates. + * + * @param pos 2D map coordinates + * @return Coords Camera coordinates + */ +Coords game_translate_into_view(Coords *pos) +{ + // Translate sprite position to relative to camera + float sprite_x = pos->x - player.pos.x; + float sprite_y = pos->y - player.pos.y; + + // Required for correct matrix multiplication + float inv_det = 1.0f / (player.plane.x * player.dir.y - + player.dir.x * player.plane.y); + float transform_x = inv_det * (player.dir.y * sprite_x - + player.dir.x * sprite_y); + float transform_y = inv_det * (-player.plane.y * sprite_x + + player.plane.x * sprite_y); + + return (Coords){transform_x, transform_y}; } /** @@ -835,31 +898,31 @@ void game_render_map(const uint8_t level[], float view_height) // Wall detection uint8_t depth = 0; - bool hit = false; - bool coll = false; - bool side; - while ((!hit) && (depth < MAX_RENDER_DEPTH)) + bool hit_wall = false; + bool is_side_wall; + bool is_coll = false; + while ((!hit_wall) && (depth < MAX_RENDER_DEPTH)) { if (side_x < side_y) { side_x += delta_x; map_x += step_x; - side = false; + is_side_wall = false; } else { side_y += delta_y; map_y += step_y; - side = true; + is_side_wall = true; } uint8_t block = game_get_level_entity(level, map_x, map_y); if ((block == E_WALL) || (block == E_DOOR) || (block == E_DOOR2) || (block == E_DOOR3) || (block == E_COLL)) { - hit = true; + hit_wall = true; if (block == E_COLL) - coll = true; + is_coll = true; } else { @@ -885,10 +948,10 @@ void game_render_map(const uint8_t level[], float view_height) depth++; } - if (hit) + if (hit_wall) { float distance; - if (side) + if (is_side_wall) distance = MAX( 1, (map_y - player.pos.y + (1 - step_y) / 2) / ray_y); else @@ -904,68 +967,15 @@ void game_render_map(const uint8_t level[], float view_height) display_draw_vline( x, ((view_height / distance) - (line_height / 2) + - (RENDER_HEIGHT / 2) + (-17 ? coll : 0)), + (RENDER_HEIGHT / 2) + (-17 ? is_coll : 0)), ((view_height / distance) + (line_height / 2) + (RENDER_HEIGHT / 2)), - ((GRADIENT_COUNT - (side * 2)) - + ((GRADIENT_COUNT - (is_side_wall * 2)) - (distance / MAX_RENDER_DEPTH * GRADIENT_COUNT))); } } } -/** - * @brief GAME sort entities from far to close. - * - */ -void game_sort_entities(void) -{ - uint8_t gap = num_entities; - bool swapped = false; - while ((gap > 1) || (swapped)) - { - // shrink factor 1.3 - gap = (gap * 10) / 13; - if ((gap == 9) || (gap == 10)) - gap = 11; - if (gap < 1) - gap = 1; - - swapped = false; - for (uint8_t i = 0; i < num_entities - gap; i++) - { - uint8_t j = i + gap; - if (entity[i].distance < entity[j].distance) - { - SWAP(entity[i], entity[j]); - swapped = true; - } - } - } -} - -/** - * @brief GAME translate 2D map coordinates into camera coordinates. - * - * @param pos 2D map coordinates - * @return Coords Camera coordinates - */ -Coords game_translate_into_view(Coords *pos) -{ - // Translate sprite position to relative to camera - float sprite_x = pos->x - player.pos.x; - float sprite_y = pos->y - player.pos.y; - - // Required for correct matrix multiplication - float inv_det = 1.0f / (player.plane.x * player.dir.y - - player.dir.x * player.plane.y); - float transform_x = inv_det * (player.dir.y * sprite_x - - player.dir.x * sprite_y); - float transform_y = inv_det * (-player.plane.y * sprite_x + - player.plane.x * sprite_y); - - return (Coords){transform_x, transform_y}; -} - /** * @brief GAME render entities sprites. * @@ -1158,10 +1168,14 @@ void game_render_hud_text(void) case TEXT_FOUND_SECRET: display_draw_text(33, 58, "FOUND SECRET", 1); + break; case TEXT_GOAL_KILLS: - sprintf(text, "%d OUT OF %d", game_kill_count, game_kill_goal); - display_draw_text(35, 58, text, 1); + if (game_kill_count <= game_kill_goal) + { + sprintf(text, "%d OUT OF %d", game_kill_count, game_kill_goal); + display_draw_text(35, 58, text, 1); + } break; case TEXT_GOAL_FIND_EXIT: @@ -1232,15 +1246,16 @@ void game_jump_to_scene(GameScene scene) } // Reset button press time - button_press_time = millis(); + game_button_time = millis(); - // Reset screen fase animation + // Reset screen animations + screen_flash = false; screen_fade = GRADIENT_COUNT - 1; } /** * @brief GAME fade display between scene transitions. - * + * * @return Transition animation done */ bool game_scene_transition(void) @@ -1293,14 +1308,14 @@ void game_run_difficulty_scene(void) return; uint32_t time = millis(); - if ((time - button_press_time) > BUTTON_PRESS_WAIT) + if ((time - game_button_time) > BUTTON_PRESS_WAIT) { bool up_pressed = input_up(); bool down_pressed = input_down(); bool fire_pressed = input_fire(); if (up_pressed || down_pressed || fire_pressed) - button_press_time = time; + game_button_time = time; if (down_pressed) { @@ -1345,7 +1360,7 @@ void game_run_difficulty_scene(void) case DIFFICULTY_VERY_HARD: medkit_heal_value = MEDKIT_HEAL_VERY_HARD; ammo_pickup_value = AMMO_PICKUP_VERY_HARD; - enemy_melee_damage = ENEMY_MELEE_DAMAGE_HARD; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_VERY_HARD; player_max_damage = GUN_MAX_DAMAGE_VERY_HARD; break; @@ -1367,14 +1382,14 @@ void game_run_music_scene(void) display_draw_text(7, 5, "MUSIC SETTINGS", 1); display_draw_text(18, 20, "DISABLE", 1); display_draw_text(18, 30, "ENABLE", 1); - display_draw_text(7, music_enable * 10 + 20, "#", 1); + display_draw_text(7, game_music_enable * 10 + 20, "#", 1); // Wait for transition animation if (!game_scene_transition()) return; uint32_t time = millis(); - if ((time - button_press_time) > BUTTON_PRESS_WAIT) + if ((time - game_button_time) > BUTTON_PRESS_WAIT) { bool up_pressed = input_up(); bool down_pressed = input_down(); @@ -1382,8 +1397,8 @@ void game_run_music_scene(void) if (up_pressed || down_pressed) { - button_press_time = time; - music_enable = !music_enable; + game_button_time = time; + game_music_enable = !game_music_enable; } else if (fire_pressed) game_jump_to_scene(SCENE_STORY_INTRO); @@ -1434,10 +1449,10 @@ void game_run_story_scene(void) if (!game_scene_transition()) return; - display_draw_text(39, 53, "PRESS FIRE", 1); + display_draw_text(38, 51, "PRESS FIRE", 1); uint32_t time = millis(); - if ((time - button_press_time) > BUTTON_PRESS_WAIT) + if ((time - game_button_time) > BUTTON_PRESS_WAIT) { if (input_fire()) { @@ -1462,25 +1477,19 @@ void game_run_level_scene(void) bool fire_pressed = input_fire(); bool jump_pressed = input_jump(); - if (player.ammo == 0) - coll = false; - else - coll = true; - - // Check if player found secret room + // Check if player found trap room if ((player.pos.x >= 2.0f) && (player.pos.x <= 3.0f) && (player.pos.y >= 54.0f) && (player.pos.y <= 55.0f) && - (player.secret < 2.0f)) + (game_level == level_e1m1)) { game_spawn_entity(E_ENEMY, 1, 51); game_spawn_entity(E_ENEMY, 3, 51); - player.secret++; } // Check if player found the exit in E1M2 if ((player.pos.x >= 46.0f) && (player.pos.x <= 47.0f) && (player.pos.y >= 35.0f) && (player.pos.y <= 36.0f) && - (game_level == E1M2)) + (game_level == level_e1m2)) { player.pos.x = 12.5f; player.pos.y = 33.5f; @@ -1491,36 +1500,28 @@ void game_run_level_scene(void) game_spawn_entity(E_ENEMY, 13, 38); } - // Check if player got to the end of E1M2 level - if ((player.pos.y >= 55.0f) && (player.pos.y <= 56.0f) && - (player.pos.x >= 12.0f) && (player.pos.x <= 23.0f) && - (game_level == E1M2)) - { - sound_play(mus_s1_snd, MUS_S1_SND_LEN, music_enable); - game_jump_to_scene(SCENE_STORY_END); - } - - /** TODO: what is this for? */ - if ((game_level == E1M2) && (game_boss_fight)) + // Boss fight + if ((game_level == level_e1m2) && (game_boss_fight)) { - if ((game_kill_count == 1) || (game_kill_count == 5) || (game_kill_count == 9)) - { - game_clear_dead_enemy(); - game_kill_count++; + if ((game_kill_count == 1) || + (game_kill_count == 5) || + (game_kill_count == 9)) game_spawn_entity(E_ENEMY, 13, 38); - } - else if ((game_kill_count == 3) || (game_kill_count == 7) || + else if ((game_kill_count == 3) || + (game_kill_count == 7) || (game_kill_count == 11)) - { - game_clear_dead_enemy(); - game_kill_count++; game_spawn_entity(E_ENEMY, 10, 38); - } else if (game_kill_count == 13) - { - player.pos.y = player.pos.y + 12; - game_kill_count = 0; - } + player.pos.y += 12; + } + + // Check if player got to the end of E1M2 level + if ((player.pos.y >= 55.0f) && (player.pos.y <= 56.0f) && + (player.pos.x >= 12.0f) && (player.pos.x <= 23.0f) && + (game_level == level_e1m2)) + { + sound_play(mus_s1_snd, MUS_S1_SND_LEN, game_music_enable); + game_jump_to_scene(SCENE_STORY_END); } // If the player is alive @@ -1572,22 +1573,22 @@ void game_run_level_scene(void) } // Player jump - if (jump_state) + if (player_jump_state) { - if ((jump_height > 0) && (jump_state == 2)) + if ((player_jump_height > 0) && (player_jump_state == 2)) { player_view_height -= 4; - jump_height -= 4; + player_jump_height -= 4; } - else if ((jump_height < 20) && (jump_state == 1)) + else if ((player_jump_height < 20) && (player_jump_state == 1)) { player_view_height += 4; - jump_height += 4; + player_jump_height += 4; } - else if (jump_height == 20) - jump_state = 2; - else if (jump_height == 0) - jump_state = 0; + else if (player_jump_height == 20) + player_jump_state = 2; + else if (player_jump_height == 0) + player_jump_state = 0; } else { @@ -1595,24 +1596,24 @@ void game_run_level_scene(void) player_jogging; if (jump_pressed) { - jump_state = 1; + player_jump_state = 1; player_jogging = 0.0f; gun_position = 22; - sound_play(jump_snd, JUMP_SND_LEN, music_enable); + sound_play(jump_snd, JUMP_SND_LEN, game_music_enable); } } // Player walking sound - if ((player_view_height > 2.95f) && (jump_state == 0)) + if ((player_view_height > 2.95f) && (player_jump_state == 0)) { if (player_walk_sound) { - sound_play(walk1_snd, WALK1_SND_LEN, music_enable); + sound_play(walk1_snd, WALK1_SND_LEN, game_music_enable); player_walk_sound = false; } else { - sound_play(walk2_snd, WALK2_SND_LEN, music_enable); + sound_play(walk2_snd, WALK2_SND_LEN, game_music_enable); player_walk_sound = true; } } @@ -1645,7 +1646,7 @@ void game_run_level_scene(void) gun_reload = true; } - if ((game_kill_count == game_kill_goal) && (game_level == E1M1)) + if ((game_kill_count == game_kill_goal) && (game_level == level_e1m1)) { game_hud_text = TEXT_YOU_WIN; if (fire_pressed) @@ -1653,7 +1654,7 @@ void game_run_level_scene(void) player.pos.x = 230; player.pos.y = 50; game_kill_count = 0; - game_level = E1M2; + game_level = level_e1m2; game_hud_text = TEXT_BLANK_SPACE; game_jump_to_scene(SCENE_STORY_MID); } @@ -1671,6 +1672,7 @@ void game_run_level_scene(void) else { // The player is dead + game_level = level_e1m1; game_hud_text = TEXT_GAME_OVER; if (player_view_height > -5.0f) @@ -1700,12 +1702,12 @@ void game_run_level_scene(void) case 3: gun_reload_animation = 2; - sound_play(r1_snd, R1_SND_LEN, music_enable); + sound_play(r1_snd, R1_SND_LEN, game_music_enable); break; case 5: gun_reload_animation = 1; - sound_play(r2_snd, R2_SND_LEN, music_enable); + sound_play(r2_snd, R2_SND_LEN, game_music_enable); break; case 7: @@ -1754,25 +1756,29 @@ void game_run_score_scene(void) game_score = (player.ammo / 2); game_score += player.health; game_score *= (game_difficulty + 1); - if (player.secret > 0) + if (player.secret) game_score += 100; - if (player.secret2 > 0) + if (player.secret2) game_score += 100; - if (player.secret3 > 0) + if (player.secret3) game_score += 100; - display_draw_bitmap(8, 8, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, + display_draw_bitmap(6, 6, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, COLOR_WHITE); - display_draw_text(34, 48, "PICO", 1); - display_draw_text(88, 8, "YOU WIN", 1); - display_draw_rect(88, 26, 34, 1, COLOR_WHITE); - display_draw_text(88, 38, "SCORE:", 1); - display_draw_int(88, 48, game_score); + display_draw_text(16, 51, "PRESS FIRE", 1); + display_draw_text(84, 6, "YOU WIN", 1); + display_draw_rect(84, 24, 36, 1, COLOR_WHITE); + display_draw_text(84, 36, "SCORE:", 1); + display_draw_int(84, 47, game_score); + + // Wait for transition animation + if (!game_scene_transition()) + return; if (game_score > SCORE_SECRET_ENDING) - sound_play(walk1_snd, WALK1_SND_LEN, music_enable); + sound_play(walk1_snd, WALK1_SND_LEN, game_music_enable); else - sound_play(shot_snd, SHOT_SND_LEN, music_enable); + sound_play(shot_snd, SHOT_SND_LEN, game_music_enable); if (input_fire()) game_jump_to_scene(SCENE_INTRO); @@ -1800,7 +1806,7 @@ void main(void) input_update(); /* Run current game scene */ - game_run_scene(); + game_run_score_scene(); /* Stop drawing */ display_draw_stop();