diff --git a/.gitignore b/.gitignore index 4ff8a14..30e7c7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -.vscode bin -lib +raylib +doom_pico* +.vscode \ No newline at end of file diff --git a/Makefile b/Makefile index 80f929b..296bd83 100644 --- a/Makefile +++ b/Makefile @@ -2,39 +2,51 @@ 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) +SRCS := $(shell find $(SRC_DIR) -name "*.c") +OBJS := $(patsubst $(SRC_DIR)/%,$(BIN_DIR)/%.o,$(SRCS)) DEPS := $(OBJS:.o=.d) -CFLAGS := -Iinc -Ilib -MMD -MP -g +CFLAGS := -I$(INC_DIR) -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 + 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) +$(TARGET_EXEC): $(OBJS) $(CC) $(OBJS) -o $@ $(LDFLAGS) -$(BIN_DIR)/%.c.o: %.c - mkdir -p $(dir $@) +$(BIN_DIR)/%.c.o: $(SRC_DIR)/%.c + $(MKDIR) $(dir $@) $(CC) $(CFLAGS) -c $< -o $@ +$(RAYLIB_DIR): + ./install_raylib.sh + .PHONY: run -run: - $(MAKE) clean +run: $(RAYLIB_DIR) $(MAKE) USE_RAYLIB=1 - ./$(BIN_DIR)/$(TARGET_EXEC) + ./$(TARGET_EXEC) .PHONY: clean clean: +ifneq (,$(wildcard $(BIN_DIR))) $(RM) $(BIN_DIR) +endif -include $(DEPS) diff --git a/inc/constants.h b/inc/constants.h index 31449ba..2ef7b00 100644 --- a/inc/constants.h +++ b/inc/constants.h @@ -21,50 +21,81 @@ * 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 + +/* Depth buffer for sprites */ +#define ZBUFFER_SIZE ((SCREEN_WIDTH / Z_RES_DIVIDER) + 4) /* Display */ -#define SCREEN_WIDTH 128 +#define SCREEN_WIDTH 128 #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 -#define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) -#define LEVEL_HEIGHT 57 -#define LEVEL_SIZE (LEVEL_WIDTH / 2 * LEVEL_HEIGHT) +/* Display colors */ +#define COLOR_BLACK 0 +#define COLOR_WHITE 1 /* Game */ #define GUN_TARGET_POS 18 -#define GUN_SHOT_POS (GUN_TARGET_POS + 4) - -#define ROT_SPEED 0.12f -#define MOV_SPEED 0.2f -#define MOV_SPEED_INV (1.0f / MOV_SPEED) - -#define JOGGING_SPEED 0.005f -#define ENEMY_SPEED 0.02f -#define FIREBALL_SPEED 0.2f -#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_ENTITY_DISTANCE 200 // * DISTANCE_MULTIPLIER -#define MAX_ENEMY_VIEW 80 // * 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 ENEMY_MELEE_DAMAGE 8 -#define ENEMY_FIREBALL_DAMAGE 20 -#define GUN_MAX_DAMAGE 15 +#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 FIREBALL_COLLIDER_DIST 3 +#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/display.h b/inc/display.h index 60465cc..d471ae1 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 ------------------------------------------------------ */ @@ -163,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 9426c88..6f74ccc 100644 --- a/inc/entities.h +++ b/inc/entities.h @@ -20,29 +20,31 @@ 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, + 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 @@ -52,7 +54,10 @@ typedef struct Coords plane; float velocity; uint8_t health; - uint8_t keys; + uint8_t ammo; + bool secret; + bool secret2; + bool secret3; } Player; typedef struct @@ -60,9 +65,10 @@ 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 drop_item; } Entity; typedef struct @@ -77,7 +83,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 +93,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 +103,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 +116,15 @@ static inline Player entities_create_player(uint8_t x, uint8_t y) .plane = {0.0f, -0.66f}, .velocity = 0.0f, .health = 100, - .keys = 0}; + .ammo = 10, + .secret = false, + .secret2 = false, + .secret3 = false}; } /** * @brief ENTITIES create enemy entity struct. - * + * * @param x X coordinate * @param y Y coordinate * @return Entity Enemy entity instance @@ -128,12 +137,13 @@ static inline Entity entities_create_enemy(uint8_t x, uint8_t y) .state = S_STAND, .health = 100, .distance = 0, - .timer = 0}; + .timer = 0, + .drop_item = true}; } /** * @brief ENTITIES create medkit entity struct. - * + * * @param x X coordinate * @param y Y coordinate * @return Entity Medkit entity instance @@ -146,12 +156,13 @@ static inline Entity entities_create_medkit(uint8_t x, uint8_t y) .state = S_STAND, .health = 100, .distance = 0, - .timer = 0}; + .timer = 0, + .drop_item = true}; } /** * @brief ENTITIES create key entity struct. - * + * * @param x X coordinate * @param y Y coordinate * @return Entity Key entity instance @@ -159,17 +170,18 @@ 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, .distance = 0, - .timer = 0}; + .timer = 0, + .drop_item = true}; } /** * @brief ENTITIES create fireball entity struct. - * + * * @param x X coordinate * @param y Y coordinate * @param dir Angle @@ -178,12 +190,13 @@ 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, .distance = 0, - .timer = 0}; + .timer = 0, + .drop_item = true}; } #endif /* ENTITIES_H */ 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/level.h b/inc/level.h index 0d424e6..a946abe 100644 --- a/inc/level.h +++ b/inc/level.h @@ -5,227 +5,322 @@ /* 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}; +#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, + 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 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, + 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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 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..bc99347 100644 --- a/inc/sound.h +++ b/inc/sound.h @@ -12,14 +12,142 @@ /* Definitions -------------------------------------------------------------- */ -static const uint8_t SHOOT_SND_LEN = 27; -static const uint8_t shoot_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}; -static const uint8_t GET_KEY_SND_LEN = 90; -static const uint8_t get_key_snd[] = { +#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, @@ -29,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[] = { +#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, @@ -48,6 +176,9 @@ 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}; +#define MELEE_SND_LEN 3 +static const uint8_t melee_snd[MELEE_SND_LEN] = {0x8f, 0x8e, 0x8e}; + /* Function prototypes ------------------------------------------------------ */ /** @@ -59,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/inc/sprites.h b/inc/sprites.h index b609298..9567eeb 100644 --- a/inc/sprites.h +++ b/inc/sprites.h @@ -16,17 +16,17 @@ #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,38 +359,23 @@ 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}; #define GRADIENT_WIDTH 2 #define GRADIENT_HEIGHT 8 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/install_raylib.sh b/install_raylib.sh new file mode 100755 index 0000000..2ef8996 --- /dev/null +++ b/install_raylib.sh @@ -0,0 +1,27 @@ +#!/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}" + 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}" + find "${RAYLIB_DIR}/lib/" -name "*.so*" -delete +else + echo "Platform currently not supported." + exit 1 +fi +rm -rf "${RAYLIB_ARCHIVE}" diff --git a/src/display.c b/src/display.c index 522ccc7..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); } } @@ -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; @@ -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/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 548d4a3..cde205e 100644 --- a/src/game.c +++ b/src/game.c @@ -1,10 +1,11 @@ /* Includes ----------------------------------------------------------------- */ -#include -#include +#include #include +#include +#include +#include #include -#include #include #include "constants.h" @@ -18,32 +19,62 @@ #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 */ + SCENE_DIFFICULTY, + SCENE_MUSIC, + SCENE_STORY_INTRO, + SCENE_STORY_MID, + SCENE_STORY_END, + SCENE_LEVEL, + 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 +} GameText; + +typedef enum +{ + DIFFICULTY_EASY, + DIFFICULTY_NORMAL, + DIFFICULTY_HARD, + DIFFICULTY_VERY_HARD, +} GameDifficulty; + +typedef enum +{ + CUTSCENE_INTRO, + CUTSCENE_MID, + 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); 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_remove_dead_enemy(void); static void game_update_entities(const uint8_t level[]); static void game_sort_entities(void); @@ -55,64 +86,77 @@ 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 */ 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_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); +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); +static void game_run_story_scene(void); static void game_run_level_scene(void); +static void game_run_score_scene(void); /* Global variables --------------------------------------------------------- */ -/* 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; +static uint8_t num_entities = 0; 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); +static uint8_t num_static_entities = 0; + +/* 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; + +/* Display */ +static bool screen_flash = false; +static uint8_t screen_fade = GRADIENT_COUNT - 1; + +/* 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; /* 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. * @@ -120,21 +164,33 @@ void game_jump_to_scene(GameScene scene) */ void game_init_level_scene(const uint8_t level[]) { - // Initialize game entities + /* Player */ + player_walk_sound = false; + player_view_height = 0.0f; + player_jogging = 0.0f; + player_jump_state = 0; + player_jump_height = 0; + + /* 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 - 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; + /* Gun */ + gun_position = 0; + gun_fired = false; + gun_reload = false; + gun_reload_state = 0; + gun_reload_animation = 0; + + /* 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--) @@ -142,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; } @@ -162,7 +221,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; @@ -230,7 +289,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; @@ -239,6 +298,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; } } @@ -254,15 +316,15 @@ void game_spawn_fireball(float x, float y) 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; // 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; @@ -308,7 +370,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--; @@ -322,115 +384,21 @@ void game_remove_static_entity(EntityUID uid) } /** - * @brief GAME detect collision between entities and level blocks. + * @brief GAME clear farthest dead enemy entity. * - * @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) +void game_remove_dead_enemy(void) { - // 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++) + uint8_t i = num_entities - 1; + while (i >= 0) { - // 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)) + if ((type == E_ENEMY) && (entity[i].state == S_DEAD)) { - 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; - } + game_remove_entity(entity[i].uid); + return; } + i--; } } @@ -445,17 +413,22 @@ 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. if (entity[i].timer > 0) entity[i].timer--; + // 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; } @@ -466,8 +439,7 @@ void game_update_entities(const uint8_t level[]) continue; } - EntityType type = entities_get_type(entity[i].uid); - switch (type) + switch (entities_get_type(entity[i].uid)) { case E_ENEMY: { @@ -476,9 +448,20 @@ void game_update_entities(const uint8_t level[]) { if (entity[i].state != S_DEAD) { - entity[i].state = S_DEAD; // Entity is dead + if (game_level == level_e1m1) + game_hud_text = TEXT_GOAL_KILLS; + entity[i].state = S_DEAD; entity[i].timer = 6; } + + 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].drop_item = false; + game_kill_count++; + } } else if (entity[i].state == S_HIT) { @@ -522,10 +505,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); } } @@ -541,16 +524,14 @@ 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 - { entity[i].state = S_STAND; - } } break; } @@ -560,23 +541,22 @@ 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; + 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. + // 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(entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED), + (sinf(entity[i].health / FIREBALL_ANGLES * PI) * + FIREBALL_SPEED), true); if (collided) @@ -590,155 +570,43 @@ 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 != PLAYER_MAX_HEALTH) && + (player_jump_height < 14)) { // Pickup - sound_play(medkit_snd, MEDKIT_SND_LEN); + sound_play(medkit_snd, MEDKIT_SND_LEN, game_music_enable); entity[i].state = S_HIDDEN; - player.health = MIN(100, player.health + 50); - flash_screen = true; + + player.health = MIN( + PLAYER_MAX_HEALTH, player.health + medkit_heal_value); + screen_flash = true; + game_hud_text = TEXT_FOUND_MEDKIT; } break; } - case E_KEY: + case E_AMMO: { - if (entity[i].distance < ITEM_COLLIDER_DIST) + 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); + sound_play(get_key_snd, GET_KEY_SND_LEN, game_music_enable); entity[i].state = S_HIDDEN; - player.keys++; - flash_screen = true; + player.ammo = MIN( + PLAYER_MAX_AMMO, player.ammo + ammo_pickup_value); + game_hud_text = TEXT_FOUND_AMMO; } 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++; + default: + break; } - 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)); - } + i++; } } @@ -773,10 +641,194 @@ void game_sort_entities(void) } /** - * @brief GAME translate 2D map coordinates into camera coordinates. + * @brief GAME detect collision between entities and level blocks. * - * @param pos 2D map coordinates - * @return Coords Camera coordinates + * @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; + + 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, 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)) + { + // 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, game_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 translate 2D map coordinates into camera coordinates. + * + * @param pos 2D map coordinates + * @return Coords Camera coordinates */ Coords game_translate_into_view(Coords *pos) { @@ -785,16 +837,145 @@ 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}; } +/** + * @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.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); + uint8_t map_y = (uint8_t)(player.pos.y); + Coords map_coords = {player.pos.x, player.pos.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; + float side_x; + float side_y; + + if (ray_x < 0.0f) + { + step_x = -1; + side_x = (player.pos.x - map_x) * delta_x; + } + else + { + step_x = 1; + side_x = (map_x + 1.0f - player.pos.x) * delta_x; + } + + if (ray_y < 0.0f) + { + step_y = -1; + side_y = (player.pos.y - map_y) * delta_y; + } + else + { + step_y = 1; + side_y = (map_y + 1.0f - player.pos.y) * delta_y; + } + + // Wall detection + uint8_t depth = 0; + 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; + is_side_wall = false; + } + else + { + side_y += delta_y; + map_y += step_y; + 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_wall = true; + if (block == E_COLL) + is_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)) + { + // 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_wall) + { + float distance; + if (is_side_wall) + 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, 0xff); + + // Render vertical line + uint8_t line_height = RENDER_HEIGHT / distance - 1; + display_draw_vline( + x, + ((view_height / distance) - (line_height / 2) + + (RENDER_HEIGHT / 2) + (-17 ? is_coll : 0)), + ((view_height / distance) + (line_height / 2) + + (RENDER_HEIGHT / 2)), + ((GRADIENT_COUNT - (is_side_wall * 2)) - + (distance / MAX_RENDER_DEPTH * GRADIENT_COUNT))); + } + } +} + /** * @brief GAME render entities sprites. * @@ -815,16 +996,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)) @@ -833,7 +1014,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) @@ -847,7 +1028,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, @@ -859,8 +1040,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, @@ -873,8 +1054,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, @@ -884,11 +1065,11 @@ void game_render_entities(float view_height) 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, + 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, @@ -897,6 +1078,9 @@ void game_render_entities(float view_height) transform.y); break; } + + default: + break; } } } @@ -907,24 +1091,45 @@ void game_render_entities(float view_height) * @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 pos, float jogging, bool fired, uint8_t reload) { - // 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; + // Jogging + int8_t x = 48 + sinf(millis() * JOGGING_SPEED) * 10 * jogging - 9; + int8_t y = fabsf(cosf(millis() * JOGGING_SPEED)) * 8 * jogging - 3 - pos + + RENDER_HEIGHT; // 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); + 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, COLOR_WHITE); - // Don't draw over the hud - uint8_t clip_height = MAX(0, MIN(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); + // 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, COLOR_BLACK); + display_draw_bitmap(x - 10, y - 22, bmp_re1_bits, BMP_RE1_WIDTH, + clip_height, COLOR_WHITE); + break; - // 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); + 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, COLOR_BLACK); + display_draw_bitmap(x - 10, y - 22, bmp_re2_bits, BMP_RE2_WIDTH, + 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, + COLOR_BLACK); + display_draw_bitmap(x, y, bmp_gun_bits, BMP_GUN_WIDTH, clip_height, + COLOR_WHITE); + break; + } } /** @@ -933,18 +1138,136 @@ void game_render_gun(uint8_t gun_pos, float jogging) */ 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); + 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); +} + +/** + * @brief GAME render text on heads-up display (HUD). + * + */ +void game_render_hud_text(void) +{ + char text[32]; + + switch (game_hud_text) + { + case TEXT_BLANK_SPACE: + break; + + case TEXT_FOUND_AMMO: + sprintf(text, "FOUND %d AMMO", ammo_pickup_value); + display_draw_text(33, 58, text, 1); + break; + + case TEXT_FOUND_MEDKIT: + display_draw_text(33, 58, "FOUND MEDKIT", 1); + break; + + case TEXT_FOUND_SECRET: + display_draw_text(33, 58, "FOUND SECRET", 1); + break; + + case TEXT_GOAL_KILLS: + 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: + display_draw_text(33, 58, "FIND THE EXIT", 1); + break; + + case TEXT_GAME_OVER: + display_draw_text(38, 58, "GAME OVER", 1); + break; + + case TEXT_YOU_WIN: + display_draw_text(44, 58, "YOU WIN", 1); + break; + + default: + break; + } +} + +/** + * @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 + game_button_time = millis(); + + // 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) +{ + if (screen_fade > 0) + { + display_fade(screen_fade, COLOR_BLACK); + screen_fade--; + return false; + } + + return true; } /** @@ -953,175 +1276,511 @@ void game_render_hud(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(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()) - game_jump_to_scene(SCENE_LEVEL1); + game_jump_to_scene(SCENE_DIFFICULTY); } /** - * @brief GAME run level scene. + * @brief GAME run difficulty selection scene. * */ -void game_run_level_scene(void) +void game_run_difficulty_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_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); + + // Wait for transition animation + if (!game_scene_transition()) + return; - // If the player is alive - if (player.health > 0) + uint32_t time = millis(); + if ((time - game_button_time) > BUTTON_PRESS_WAIT) { - // Player speed - if (input_up()) + bool up_pressed = input_up(); + bool down_pressed = input_down(); + bool fire_pressed = input_fire(); + + if (up_pressed || down_pressed || fire_pressed) + game_button_time = time; + + if (down_pressed) { - player.velocity += (MOV_SPEED - player.velocity) * 0.4f; - jogging = fabsf(player.velocity) * MOV_SPEED_INV; + if (game_difficulty == DIFFICULTY_VERY_HARD) + game_difficulty = DIFFICULTY_EASY; + else + game_difficulty++; } - else if (input_down()) + else if (up_pressed) { - player.velocity -= (MOV_SPEED + player.velocity) * 0.4f; - jogging = fabsf(player.velocity) * MOV_SPEED_INV; + if (game_difficulty == DIFFICULTY_EASY) + game_difficulty = DIFFICULTY_VERY_HARD; + else + game_difficulty--; } - else + else if (fire_pressed) { - player.velocity *= 0.5f; - jogging = fabsf(player.velocity) * MOV_SPEED_INV; + // Adjust game settings based on difficulty + switch (game_difficulty) + { + case DIFFICULTY_EASY: + 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_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_HARD; + ammo_pickup_value = AMMO_PICKUP_HARD; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_HARD; + player_max_damage = GUN_MAX_DAMAGE_HARD; + break; + + case DIFFICULTY_VERY_HARD: + medkit_heal_value = MEDKIT_HEAL_VERY_HARD; + ammo_pickup_value = AMMO_PICKUP_VERY_HARD; + enemy_melee_damage = ENEMY_MELEE_DAMAGE_VERY_HARD; + player_max_damage = GUN_MAX_DAMAGE_VERY_HARD; + break; + + default: + break; + } + + game_jump_to_scene(SCENE_MUSIC); } + } +} - // Player rotation - if (input_right()) +/** + * @brief GAME run music settings scene. + * + */ +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, game_music_enable * 10 + 20, "#", 1); + + // Wait for transition animation + if (!game_scene_transition()) + return; + + uint32_t time = millis(); + 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) + { + game_button_time = time; + game_music_enable = !game_music_enable; + } + else if (fire_pressed) + game_jump_to_scene(SCENE_STORY_INTRO); + } +} + +/** + * @brief GAME run story scene. + * + */ +void game_run_story_scene(void) +{ + if (game_cutscene == CUTSCENE_INTRO) + { + 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 (game_cutscene == CUTSCENE_MID) + { + 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 (game_cutscene == CUTSCENE_END) + { + 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); + } + + // Wait for transition animation + if (!game_scene_transition()) + return; + + display_draw_text(38, 51, "PRESS FIRE", 1); + + uint32_t time = millis(); + if ((time - game_button_time) > BUTTON_PRESS_WAIT) + { + if (input_fire()) { - 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 (game_cutscene != CUTSCENE_END) + game_jump_to_scene(SCENE_LEVEL); + else + game_jump_to_scene(SCENE_SCORE); } - else if (input_left()) + } +} + +/** + * @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(); + + // 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) && + (game_level == level_e1m1)) + { + game_spawn_entity(E_ENEMY, 1, 51); + game_spawn_entity(E_ENEMY, 3, 51); + } + + // 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 == level_e1m2)) + { + player.pos.x = 12.5f; + player.pos.y = 33.5f; + 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); + } + + // Boss fight + if ((game_level == level_e1m2) && (game_boss_fight)) + { + 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) || + (game_kill_count == 11)) + game_spawn_entity(E_ENEMY, 10, 38); + else if (game_kill_count == 13) + 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 + if (player.health > 0) + { + // Player movement speed + if (up_pressed || down_pressed) { - 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 (up_pressed) + player.velocity += (MOV_SPEED - player.velocity) * 0.4f; + else + player.velocity += (-MOV_SPEED - player.velocity) * 0.4f; } + else + player.velocity *= 0.5f; - view_height = - fabsf(sinf(platform_millis() * JOGGING_SPEED)) * 6.0f * jogging; + // Player jogging speed animation + player_jogging = fabsf(player.velocity) * GUN_SPEED * 2.0f; - if (view_height > 5.9f) + // Player rotation + if (left_pressed || right_pressed) { - if (walk_sound_toggle) + float old_dir_x = player.dir.x; + float old_plane_x = player.plane.x; + float rot_speed = ROT_SPEED * delta_time; + + if (left_pressed) { - sound_play(walk1_snd, WALK1_SND_LEN); - walk_sound_toggle = false; + 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 { - sound_play(walk2_snd, WALK2_SND_LEN); - walk_sound_toggle = true; + 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)); } } - // Update gun - if (gun_pos > GUN_TARGET_POS) + // Player jump + if (player_jump_state) + { + if ((player_jump_height > 0) && (player_jump_state == 2)) + { + player_view_height -= 4; + player_jump_height -= 4; + } + else if ((player_jump_height < 20) && (player_jump_state == 1)) + { + player_view_height += 4; + player_jump_height += 4; + } + else if (player_jump_height == 20) + player_jump_state = 2; + else if (player_jump_height == 0) + player_jump_state = 0; + } + else { - // Right after fire - gun_pos -= 1; + player_view_height = fabsf(sinf(millis() * JOGGING_SPEED)) * 6 * + player_jogging; + if (jump_pressed) + { + player_jump_state = 1; + player_jogging = 0.0f; + gun_position = 22; + sound_play(jump_snd, JUMP_SND_LEN, game_music_enable); + } } - else if (gun_pos < GUN_TARGET_POS) + + // Player walking sound + if ((player_view_height > 2.95f) && (player_jump_state == 0)) { - // Showing up - gun_pos += 2; + if (player_walk_sound) + { + sound_play(walk1_snd, WALK1_SND_LEN, game_music_enable); + player_walk_sound = false; + } + else + { + sound_play(walk2_snd, WALK2_SND_LEN, game_music_enable); + player_walk_sound = true; + } } - else if (!gun_fired && input_fire()) + + // Update gun + 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 (fire_pressed && !gun_fired && !gun_reload) { // Ready to fire and fire pressed - gun_pos = GUN_SHOT_POS; + gun_position = GUN_SHOT_POS; gun_fired = true; - game_fire_shootgun(); + 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 (!fire_pressed && gun_fired) { // Just fired and restored position gun_fired = false; + gun_reload = true; + } + + if ((game_kill_count == game_kill_goal) && (game_level == level_e1m1)) + { + game_hud_text = TEXT_YOU_WIN; + if (fire_pressed) + { + player.pos.x = 230; + player.pos.y = 50; + game_kill_count = 0; + game_level = level_e1m2; + game_hud_text = TEXT_BLANK_SPACE; + game_jump_to_scene(SCENE_STORY_MID); + } } - // Update player game_update_position( - level_1, + game_level, &(player.pos), player.dir.x * player.velocity * delta_time, player.dir.y * player.velocity * delta_time, false); - // Update entities - game_update_entities(level_1); + game_update_entities(game_level); } else { // The player is dead - if (view_height > -10.0f) - view_height--; - else if (input_fire()) + game_level = level_e1m1; + game_hud_text = TEXT_GAME_OVER; + + if (player_view_height > -5.0f) + player_view_height--; + else if (fire_pressed) game_jump_to_scene(SCENE_INTRO); - if (gun_pos > 1) - gun_pos -= 2; + if (gun_position > 0) + gun_position -= 2; + else + gun_reload_animation = 3; + } + + // Play reload animation and sound + if (gun_reload) + { + if (player.ammo == 0) + gun_reload_state = 7; + else + gun_reload_state++; + + switch (gun_reload_state) + { + case 1: + gun_reload_animation = 1; + break; + + case 3: + gun_reload_animation = 2; + sound_play(r1_snd, R1_SND_LEN, game_music_enable); + break; + + case 5: + gun_reload_animation = 1; + sound_play(r2_snd, R2_SND_LEN, game_music_enable); + break; + + case 7: + gun_reload_state = 0; + gun_reload_animation = 0; + gun_reload = false; + break; + + default: + break; + } } // Render stuff - game_render_map(level_1, view_height); - game_render_entities(view_height); - game_render_gun(gun_pos, jogging); + 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) - { - display_fade(fade_screen, false); - fade_screen--; + // Wait for transition animation + if (!game_scene_transition()) 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 - if (input_exit()) + if (input_home()) + 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) + game_score += 100; + if (player.secret2) + game_score += 100; + if (player.secret3) + game_score += 100; + + display_draw_bitmap(6, 6, bmp_logo_bits, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, + COLOR_WHITE); + 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, game_music_enable); + else + sound_play(shot_snd, SHOT_SND_LEN, game_music_enable); + + if (input_fire()) game_jump_to_scene(SCENE_INTRO); } @@ -1147,7 +1806,7 @@ void main(void) input_update(); /* Run current game scene */ - game_run_scene(); + game_run_score_scene(); /* Stop drawing */ display_draw_stop(); 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..ec377ff 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,8 +109,11 @@ void platform_draw_pixel(uint8_t x, uint8_t y, bool color) */ void platform_audio_play(void) { - old_frequency = 0; - ResumeAudioStream(audio_stream); + if (!audio_is_playing) + { + audio_is_playing = true; + ResumeAudioStream(audio_stream); + } } /** @@ -130,21 +134,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; } /** @@ -153,18 +163,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; } /** @@ -269,6 +285,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 a32264b..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; @@ -70,8 +74,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[sound_idx]); + return 1193181 / (60 * (uint16_t)sound_ptr[sound_idx]); } /* -------------------------------------------------------------------------- */ \ 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