diff --git a/floopper-bloopper.c b/floopper-bloopper.c index 46a9aa5..06ce9dc 100644 --- a/floopper-bloopper.c +++ b/floopper-bloopper.c @@ -1,35 +1,150 @@ #include "flipper.h" #include "u8g2/u8g2.h" +#include +#include +#include #include "floopper-bloopper/floopper-bloopper.h" -void render_graphics(GameState* state, u8g2_t* fb) { +#define MAX_LINES 4 + +typedef struct { + size_t line_size; + char* lines[MAX_LINES]; +} TextBlock; + +// narrative +const TextBlock NARRATIVE[] = { + {3, {"Welcome to Game!", "Use < > to move", "Use ^ to jump"}}, + {3, {"OMG, it's happened", "again! Wait, I try", "to help you..."}}, + {1, {"Please, return back"}}, + {3, {"No, you dawn into", "cycle deeply!", " Go back"}}, + {2, {"Okay, you stuck...", "try to press jump"}}, + {1, {"...then left"}}, + {1, {"...then right"}}, + {1, {"...left again"}}, + {3, {"Damn, it worked", "before. I need to", "read manual"}}, + {2, {"Hey! I found", "something helpful!"}}, + {3, {"You need to activate", "DCMPA 0x3A77 trigger", "u know what it is?"}}, + {3, {"Maybe some part of", "the earth looks", "special"}}, + {1, {"Try to jump over it"}}, + {1, {"Jump here!"}}, + {1, {"No, not here..."}} +}; + +const int32_t HEIGHT_MAP[WORLD_WIDTH] = { + 5000, 5200, 5400, 5600, 5800, 6000, 6200, 6400, 6600, 6800, 7000, 7200, 7400, 7600, 7800, 8000, + 8200, 8400, 8600, 8800, 9000, 9200, 9400, 9600, 9800, 10000, 10200, 10400, 10600, 10800, 11000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 4500, 4000, 3500, 3000, 2500, 2000, 1500, 1000, 500, 0, -500, -1000, -2000, -3000, -4000, + -5000, -5000, -5000, -5000, -5000, -5000, -5000, -5000, -5000, -5000, -5000, -5000, -5000, -5000, -5000, -5000, + -4000, -3000, -2500, -2000, -1500, -500, 0, 500, 1200, 1800, 2500, 3000, 3500, 4000, 4500, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, +}; + +#include "floopper-bloopper/player.c" +#include "floopper-bloopper/world.c" +#include "floopper-bloopper/game.c" + +typedef enum { + ComboInputUp = 0, + ComboInputDown, + ComboInputRight, + ComboInputLeft, + ComboInputEmpty, +} ComboInput; +ComboInput combo[COMBO_LENGTH]; + +ComboInput COMBO_PATTERNS[PATTERN_LENGTH][COMBO_LENGTH] = { + {ComboInputLeft, ComboInputRight, ComboInputRight, ComboInputDown, ComboInputEmpty, ComboInputEmpty, ComboInputEmpty, ComboInputEmpty}, //text combo <>>! + {ComboInputLeft, ComboInputDown, ComboInputRight, ComboInputDown, ComboInputDown, ComboInputEmpty, ComboInputEmpty, ComboInputEmpty}, //text combo off !! + {ComboInputLeft, ComboInputUp, ComboInputRight, ComboInputDown, ComboInputEmpty, ComboInputEmpty, ComboInputEmpty, ComboInputEmpty}, + }; + +void render_ui(GameState* state, u8g2_t* fb); + +void render_graphics(GameState* state, u8g2_t* fb, uint32_t t) { u8g2_ClearBuffer(fb); - render_ui(state, fb); - render_world(state, fb); + render_world(state, fb, t); render_player(state, fb); + render_game_state(state, fb); + render_ui(state, fb); } -void render_player(GameState* state, u8g2_t* fb) { - if (state->player_x < BONDARIES_X_LEFT * SCALE) { - state->player_x = BONDARIES_X_LEFT * SCALE; - } else if (state->player_x > (BONDARIES_X_RIGHT - PLAYER_WIDTH) * SCALE) { - state-> player_x = (BONDARIES_X_RIGHT - PLAYER_WIDTH) * SCALE; - } +void render_ui(GameState* state, u8g2_t* fb) { + if(state->combo_panel_activated) { + u8g2_SetDrawColor(fb, 0); + //combo box background + u8g2_DrawBox(fb, CP_POSITION_X, CP_POSITION_Y, (SCREEN_WIDTH) - CP_POSITION_X * 2, CP_HEIGHT); + u8g2_SetDrawColor(fb, 1); + //progress + u8g2_DrawBox(fb, + CP_POSITION_X, + CP_POSITION_Y - CP_PROGRESS_HEIGHT, + (SCREEN_WIDTH - CP_POSITION_X * 2) * state->combo_progress / ( 100 * SCALE ), + CP_PROGRESS_HEIGHT); + //combo box frame + u8g2_DrawFrame(fb, + CP_POSITION_X, + CP_POSITION_Y, + SCREEN_WIDTH - CP_POSITION_X * 2, + CP_HEIGHT); - u8g2_DrawBox(fb, state->player_x / SCALE, state->player_y / SCALE, PLAYER_WIDTH, PLAYER_HEIGHT); + //combo items + u8g2_SetFont(fb, u8g2_font_unifont_t_symbols); + for(size_t i = 0; i < state->combo_panel_cnt; i++) { + uint16_t item_x = CP_POSITION_X + CP_ITEM_WIDTH + (CP_ITEM_WIDTH + CP_ITEM_SPACE) * i; + uint16_t item_y = CP_POSITION_Y + (CP_HEIGHT + CP_ITEM_HEIGHT) / 2; + switch(combo[i]) { + case ComboInputUp: + u8g2_DrawGlyph(fb, item_x, item_y, 9206); + break; + case ComboInputDown: + u8g2_DrawGlyph(fb, item_x, item_y, 9207); + break; + case ComboInputRight: + u8g2_DrawGlyph(fb, item_x, item_y, 9205); + break; + case ComboInputLeft: + u8g2_DrawGlyph(fb, item_x, item_y, 9204); + break; + default: break; + } + } + } } -void render_world(GameState* state, u8g2_t* fb) { - u8g2_DrawBox(fb, 0, SCREEN_HEIGHT - 4, SCREEN_WIDTH, 4); + +void hadle_combo_input(GameState* state, InputEvent* input) { + if(input->state) { + combo[state->combo_panel_cnt] = input->input; + state->combo_progress = 100 * SCALE; + state->combo_panel_cnt += 1; + state->combo_speed = ((SCREEN_WIDTH - CP_POSITION_X * 2) * 1000 * state->combo_panel_cnt) / COMBO_TIME; + } } -void render_ui(GameState* state, u8g2_t* fb) { - u8g2_SetFont(fb, u8g2_font_6x10_mf); - u8g2_SetDrawColor(fb, 1); - u8g2_SetFontMode(fb, 1); - u8g2_DrawStr(fb, 2, 12, "Floopper bloopper!"); +void update_combo_process(GameState* state, uint32_t dt) { + if(state->combo_panel_activated && (state->combo_progress > 0)) { + state->combo_progress -= state->combo_speed * dt; + } else { + state->combo_panel_activated = false; + if(!memcmp(COMBO_PATTERNS[0], combo, COMBO_LENGTH)) { + state->combo_text = true; + } else if(!memcmp(COMBO_PATTERNS[1], combo, COMBO_LENGTH)) { + state->combo_text = false; + } + } } void handle_key(GameState* state, InputEvent* input) { @@ -39,21 +154,37 @@ void handle_key(GameState* state, InputEvent* input) { input->state ? "pressed" : "released" ); - if(input->state) { - if (input->input == InputRight) { - state->player_vx = SPEED_X; - } else if (input->input == InputLeft) { - state->player_vx = -SPEED_X; - } + if(state->combo_panel_activated) { + hadle_combo_input(state, input); } else { - if (input->input == InputRight || input->input == InputLeft) { - state->player_vx = 0; + handle_player_input(state, input); + } + + if(input->input == InputDown) { + if(input->state) { + //for tests + if(state->in_boundaries){ + state->in_boundaries = false; + } else { + state->in_boundaries = true; + } } } - if(input->input == InputUp) { + + if(input->input == InputOk) { if(input->state) { - state->player_jump = true; + if(!state->combo_panel_activated) { + state->combo_panel_cnt = 0; + state->combo_panel_activated = true; + state->combo_progress = 100 * SCALE; + state->combo_speed = ((SCREEN_WIDTH - CP_POSITION_X * 2) * 1000 * 0.5) / COMBO_TIME; + for(size_t i = 0; i < COMBO_LENGTH; i++){ + combo[i] = ComboInputEmpty; + } + } else { + state->combo_panel_activated = false; + } } } } @@ -61,19 +192,7 @@ void handle_key(GameState* state, InputEvent* input) { void handle_tick(GameState* state, uint32_t t, uint32_t dt) { // printf("t: %d, dt: %d\n", t, dt); - // gravity - if(state->player_jump) { - state->player_y -= 1 * SCALE; - state->player_vy = -60; - state->player_jump = false; - } else { - if(state->player_y > ((SCREEN_HEIGHT - 5 - PLAYER_HEIGHT) * SCALE)) { - state->player_vy = 0; - } else { - state->player_vy += 5; - } - } - - state->player_x += state->player_vx * dt; - state->player_y += state->player_vy * dt; -} \ No newline at end of file + update_player_coordinates(state, dt); + update_game_state(state, t, dt); + update_combo_process(state, dt); +} diff --git a/floopper-bloopper.h b/floopper-bloopper.h index 700b1bd..4f8b190 100644 --- a/floopper-bloopper.h +++ b/floopper-bloopper.h @@ -2,20 +2,89 @@ #include "u8g2/u8g2.h" typedef struct { - int32_t player_x; - int32_t player_y; - int32_t player_vx; - int32_t player_vy; + int32_t x; + int32_t y; +} Vec2; + +typedef struct { + Vec2 player; + Vec2 player_global; + Vec2 player_v; + + Vec2 screen; + + bool in_boundaries; bool player_jump; + uint8_t player_anim; GpioPin* green; + + bool combo_panel_activated; + uint8_t combo_panel_cnt; + int32_t combo_progress; + uint32_t combo_speed; + + size_t label_id; + uint8_t glitch_level; + uint32_t glitch_t; + + int32_t player_odo; + uint32_t player_t; + + bool combo_text; } GameState; +// global +#define SCALE 1024 + +// screen #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define BONDARIES_X_LEFT 20 #define BONDARIES_X_RIGHT 108 -#define PLAYER_WIDTH 6 -#define PLAYER_HEIGHT 6 -#define SCALE 1000 -#define SPEED_X 50 + +// player +#define PLAYER_WIDTH 9 +#define PLAYER_HEIGHT 12 +#define SPEED_X 40 +#define JUMP_SPEED -100 + +// world +#define WORLD_WIDTH 256 +#define WORLD_HEIGHT 64 + +#define LABEL_X 30 * SCALE +#define LABEL_Y 12 * SCALE +#define LABEL_HEIGHT 8 * SCALE + +#define TEST_BOX_SIZE 6 + +enum { + WELCOME, + OMG, + OMG_HELP, + WRONG, + STUCK, + HELP_1, + HELP_2, + HELP_3, + DAMN, + MANUAL_FOUND, + MANUAL, + TIP_0, + TIP_1, + TIP_HERE, + TIP_NO_HERE, +}; + +//combo +#define CP_POSITION_X 10 +#define CP_POSITION_Y 20 +#define CP_HEIGHT 20 +#define CP_ITEM_WIDTH 8 +#define CP_ITEM_HEIGHT 12 +#define CP_ITEM_SPACE 5 +#define CP_PROGRESS_HEIGHT 3 +#define COMBO_TIME 1000 +#define COMBO_LENGTH 8 +#define PATTERN_LENGTH 3 diff --git a/game-engine.c b/game-engine.c index ea0fbd5..262bee8 100644 --- a/game-engine.c +++ b/game-engine.c @@ -70,14 +70,37 @@ void floopper_bloopper(void* p) { digitalWrite(green, HIGH); GameState state = { - .player_x = (SCREEN_WIDTH/2 - PLAYER_WIDTH/2) * SCALE, - .player_y = (SCREEN_HEIGHT - 5 - PLAYER_WIDTH) * SCALE, - .player_vx = 0, - .player_vy = 0, + .player = { + .x = (SCREEN_WIDTH/2 - PLAYER_WIDTH/2) * SCALE, + .y = (SCREEN_HEIGHT/2) * SCALE, + }, + .player_global = { + .x = (SCREEN_WIDTH/2 - PLAYER_WIDTH/2) * SCALE, + .y = (SCREEN_HEIGHT/2) * SCALE, + }, + .player_v = {.x = 0, .y = 0,}, + + .in_boundaries = false, .player_jump = false, - .green = &green + .player_anim = 0, + .green = &green, + + .combo_panel_activated = false, + + .label_id = WELCOME, + + .glitch_level = 0, + .glitch_t = 0, + + .player_odo = 0, + .player_t = 0, + + .combo_text = false, }; + state.screen.x = state.player_global.x - state.player.x; + state.screen.y = state.player_global.y - state.player.y; + Event event; uint32_t t = xTaskGetTickCount(); @@ -85,6 +108,8 @@ void floopper_bloopper(void* p) { while(1) { if(xQueueReceive(event_queue, (void*)&event, portMAX_DELAY)) { + // digitalWrite(green, LOW); + t = xTaskGetTickCount(); if(event.type == EventTypeTick) { @@ -99,9 +124,11 @@ void floopper_bloopper(void* p) { u8g2_t* fb = furi_take(fb_record); if(fb != NULL) { - render_graphics(&state, fb); + render_graphics(&state, fb, t); } furi_commit(fb_record); + + // digitalWrite(green, HIGH); } } } \ No newline at end of file diff --git a/game.c b/game.c new file mode 100644 index 0000000..4232f0e --- /dev/null +++ b/game.c @@ -0,0 +1,148 @@ + +void update_game_state(GameState* state, uint32_t t, uint32_t dt) { + switch(state->label_id) { + case WELCOME: + state->player_odo += state->player_v.x * dt; + + if(state->player_odo / SCALE > 180 || state->player_odo / SCALE < -160) { + state->glitch_level = 2; + } + + if( + (abs((LABEL_X - state->screen.x) / SCALE)) % 256 < 2 && + state->glitch_level == 2 && + state->player_t == 0 + ) { + state->in_boundaries = true; + } + + if( + (abs((LABEL_X - state->screen.x) / SCALE)) % 256 < 10 && + state->glitch_level == 2 && + state->player_t == 0 + ) { + state->player_t = t; + } + + if(state->player_t > 0 && t - state->player_t > 2000) { + state->player_t = t; + + state->label_id = OMG; + state->glitch_level = 0; + } + break; + + case OMG: + if(t - state->player_t > 3000) { + state->label_id = OMG_HELP; + state->in_boundaries = false; + state->player_odo = 0; + } + break; + + case OMG_HELP: + state->player_odo += state->player_v.x * dt; + + if(state->player_odo / SCALE > WORLD_WIDTH * 0.8) { + state->label_id = WRONG; + state->player_odo = 0; + } + + if( + state->player_odo / SCALE < -WORLD_WIDTH * 0.8 && + (abs((LABEL_X - state->screen.x) / SCALE)) % 256 < 2 + ) { + state->label_id = STUCK; + state->in_boundaries = true; + } + break; + + case STUCK: + if(state->player_v.y < -20) { + state->label_id = HELP_1; + } + break; + + case HELP_1: + if(state->player_v.x < 0) { + state->label_id = HELP_2; + } + break; + + case HELP_2: + if(state->player_v.x > 0) { + state->label_id = HELP_3; + } + break; + + case HELP_3: + if(state->player_v.x < 0) { + state->label_id = DAMN; + state->player_t = t; + } + break; + + case DAMN: + + if(t - state->player_t > 3000 && state->glitch_level == 0) { + state->player_t = t; + state->glitch_level = 5; + } + + if(t - state->player_t > 5000 && state->glitch_level == 5) { + state->glitch_level = 0; + state->label_id = MANUAL_FOUND; + } + break; + + case MANUAL_FOUND: + if(t - state->player_t > 2000) { + state->glitch_level = 0; + state->label_id = MANUAL; + state->player_odo = 0; + state->in_boundaries = false; + } + break; + + case MANUAL: + state->player_odo += state->player_v.x * dt; + + if(state->player_odo / SCALE > 180 || state->player_odo / SCALE < -160) { + state->label_id = TIP_0; + state->player_odo = 0; + } + break; + + case TIP_0: + state->player_odo += state->player_v.x * dt; + + if(state->player_odo / SCALE > 180 || state->player_odo / SCALE < -160) { + state->label_id = TIP_1; + state->player_odo = 0; + } + break; + + case TIP_1: + state->player_odo += state->player_v.x * dt; + + if(state->player_odo / SCALE > 180 || state->player_odo / SCALE < -160) { + state->label_id = TIP_NO_HERE; + } + break; + + // TIP_NO_HERE + + default: break; + } +} + +void render_game_state(GameState* state, u8g2_t* fb) { + char buf[32]; + + u8g2_SetFont(fb, u8g2_font_6x10_mf); + u8g2_SetDrawColor(fb, 1); + u8g2_SetFontMode(fb, 1); + + sprintf(buf, "odo: %d", state->player_odo); + u8g2_DrawStr(fb, 0, 40, buf); +} \ No newline at end of file diff --git a/player.c b/player.c new file mode 100644 index 0000000..2797cb0 --- /dev/null +++ b/player.c @@ -0,0 +1,126 @@ + +#include "floopper-bloopper/player_0/player_0_0.xbm" +#include "floopper-bloopper/player_0/player_0_1.xbm" +#include "floopper-bloopper/player_0/player_0_2.xbm" +#include "floopper-bloopper/player_0/player_0_3.xbm" +#include "floopper-bloopper/player_0/player_0_4.xbm" +#include "floopper-bloopper/player_0/player_0_5.xbm" +#include "floopper-bloopper/player_0/player_0_6.xbm" + +void render_player(GameState* state, u8g2_t* fb) { + unsigned char* player_sprite = NULL; + + if(state->player_v.y > 40) { + player_sprite = (unsigned char*)player_0_2_bits; + } else if(state->player_v.y < -40) { + player_sprite = (unsigned char*)player_0_3_bits; + } else { + if(state->player_v.x < 0) { + if(state->player_anim == 0) { + player_sprite = (unsigned char*)player_0_0_bits; + } else { + player_sprite = (unsigned char*)player_0_1_bits; + } + } else if(state->player_v.x > 0) { + if(state->player_anim == 0) { + player_sprite = (unsigned char*)player_0_5_bits; + } else { + player_sprite = (unsigned char*)player_0_6_bits; + } + } else { + player_sprite = (unsigned char*)player_0_4_bits; + } + } + + if(player_sprite != NULL) { + u8g2_DrawXBM( + fb, + state->player.x / SCALE, state->player.y / SCALE, + player_0_0_width, player_0_0_height, + (unsigned char*)player_sprite + ); + } +} + +void handle_player_input(GameState* state, InputEvent* input) { + if(input->state) { + if (input->input == InputRight) { + state->player_v.x = SPEED_X; + } else if (input->input == InputLeft) { + state->player_v.x = -SPEED_X; + } + } else { + if (input->input == InputRight || input->input == InputLeft) { + state->player_v.x = 0; + } + } + + if(input->input == InputUp) { + if(input->state) { + state->player_v.y = JUMP_SPEED; + } + } +} + +void update_player_coordinates(GameState* state, uint32_t dt) { + state->player.y += state->player_v.y * dt; + state->player_global.y += state->player_v.y * dt; + + if (state->player.x < BONDARIES_X_LEFT * SCALE) { + state->player.x = BONDARIES_X_LEFT * SCALE; + } else if (state->player.x > (BONDARIES_X_RIGHT - PLAYER_WIDTH) * SCALE) { + state-> player.x = (BONDARIES_X_RIGHT - PLAYER_WIDTH) * SCALE; + } else { + state->player.x += state->player_v.x * dt; + } + + if (state->player.x <= BONDARIES_X_LEFT * SCALE) { + if(!state->in_boundaries) { + state->player_global.x += state->player_v.x * dt; + } + } else if (state->player.x >= (BONDARIES_X_RIGHT - PLAYER_WIDTH) * SCALE) { + if(!state->in_boundaries) { + state->player_global.x += state->player_v.x * dt; + } + } else { + state->player_global.x += state->player_v.x * dt; + } + + // gravity + floor + + int32_t floor_height = SCREEN_HEIGHT * SCALE - + HEIGHT_MAP[(abs(state->player_global.x) / SCALE) % WORLD_WIDTH] - + PLAYER_HEIGHT * SCALE; + + int32_t f_h; + for(size_t i = 1; i < PLAYER_WIDTH; i++) { + f_h = SCREEN_HEIGHT * SCALE - + HEIGHT_MAP[(abs(state->player_global.x) / SCALE + i) % WORLD_WIDTH] - + PLAYER_HEIGHT * SCALE; + if (f_h < floor_height) { + floor_height = f_h; + } + } + + if(state->player_global.y >= floor_height){ + state->player.y = floor_height; + state->player_global.y = floor_height; + state->player_v.y = 0; + } else { + state->player_v.y += 5; + } + + if(state->player.y > (SCREEN_HEIGHT - PLAYER_HEIGHT - 4) * SCALE) { + state->player.y = (SCREEN_HEIGHT - PLAYER_HEIGHT - 4) * SCALE; + } + + // global + state->screen.x = state->player_global.x - state->player.x; + state->screen.y = state->player.y - state->player_global.y; + + if (state->player_global.x < BONDARIES_X_LEFT * SCALE) { + state->player_global.x += WORLD_WIDTH * SCALE; + } + + state->player_anim = (state->player_global.x / (SCALE * 4)) % 2; +} \ No newline at end of file diff --git a/player_0/player_0_0.xbm b/player_0/player_0_0.xbm new file mode 100644 index 0000000..76e536a --- /dev/null +++ b/player_0/player_0_0.xbm @@ -0,0 +1,5 @@ +#define player_0_0_width 9 +#define player_0_0_height 12 +static const unsigned char player_0_0_bits[] = { + 0x0c, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x18, 0x00, + 0x3c, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x14, 0x00, 0x32, 0x00, 0x20, 0x00 }; diff --git a/player_0/player_0_1.xbm b/player_0/player_0_1.xbm new file mode 100644 index 0000000..6b14664 --- /dev/null +++ b/player_0/player_0_1.xbm @@ -0,0 +1,5 @@ +#define player_0_1_width 9 +#define player_0_1_height 12 +static const unsigned char player_0_1_bits[] = { + 0x18, 0x00, 0x3c, 0x00, 0x24, 0x00, 0x24, 0x00, 0x18, 0x00, 0x18, 0x00, + 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00 }; diff --git a/player_0/player_0_2.xbm b/player_0/player_0_2.xbm new file mode 100644 index 0000000..284d21f --- /dev/null +++ b/player_0/player_0_2.xbm @@ -0,0 +1,5 @@ +#define player_0_2_width 9 +#define player_0_2_height 12 +static const unsigned char player_0_2_bits[] = { + 0x38, 0x00, 0x44, 0x00, 0x6c, 0x00, 0x45, 0x01, 0x45, 0x01, 0x39, 0x01, + 0xfe, 0x00, 0x38, 0x00, 0x38, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00 }; diff --git a/player_0/player_0_3.xbm b/player_0/player_0_3.xbm new file mode 100644 index 0000000..0ec8cd1 --- /dev/null +++ b/player_0/player_0_3.xbm @@ -0,0 +1,5 @@ +#define player_0_3_width 9 +#define player_0_3_height 12 +static const unsigned char player_0_3_bits[] = { + 0x38, 0x00, 0x44, 0x00, 0x6c, 0x00, 0x44, 0x00, 0x44, 0x00, 0x38, 0x00, + 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x6c, 0x00, 0x28, 0x00, 0x28, 0x00 }; diff --git a/player_0/player_0_4.xbm b/player_0/player_0_4.xbm new file mode 100644 index 0000000..856a8ce --- /dev/null +++ b/player_0/player_0_4.xbm @@ -0,0 +1,5 @@ +#define player_0_4_width 9 +#define player_0_4_height 12 +static const unsigned char player_0_4_bits[] = { + 0x38, 0x00, 0x44, 0x00, 0x6c, 0x00, 0x44, 0x00, 0x44, 0x00, 0x38, 0x00, + 0xfe, 0x00, 0xba, 0x00, 0xba, 0x00, 0x28, 0x00, 0x28, 0x00, 0x6c, 0x00 }; diff --git a/player_0/player_0_5.xbm b/player_0/player_0_5.xbm new file mode 100644 index 0000000..34de805 --- /dev/null +++ b/player_0/player_0_5.xbm @@ -0,0 +1,5 @@ +#define player_0_5_width 9 +#define player_0_5_height 12 +static const unsigned char player_0_5_bits[] = { + 0x60, 0x00, 0xf0, 0x00, 0x90, 0x00, 0x90, 0x00, 0x60, 0x00, 0x30, 0x00, + 0x78, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0x50, 0x00, 0x98, 0x00, 0x08, 0x00 }; diff --git a/player_0/player_0_6.xbm b/player_0/player_0_6.xbm new file mode 100644 index 0000000..d7fa917 --- /dev/null +++ b/player_0/player_0_6.xbm @@ -0,0 +1,5 @@ +#define player_0_6_width 9 +#define player_0_6_height 12 +static const unsigned char player_0_6_bits[] = { + 0x30, 0x00, 0x78, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, 0x00, 0x30, 0x00, + 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 }; diff --git a/world.c b/world.c new file mode 100644 index 0000000..af3b44a --- /dev/null +++ b/world.c @@ -0,0 +1,46 @@ + +void render_world(GameState* state, u8g2_t* fb, uint32_t t) { + char buf[32]; + + u8g2_SetDrawColor(fb, 1); + for(size_t i = 0; i < SCREEN_WIDTH; i++) { + int32_t floor_height = HEIGHT_MAP[abs(state->screen.x / SCALE + i) % WORLD_WIDTH]; + + u8g2_DrawBox(fb, + i, SCREEN_HEIGHT - (floor_height - state->screen.y) / SCALE, + 1, 5); + } + + // in-level label + u8g2_SetFont(fb, u8g2_font_6x10_mf); + u8g2_SetDrawColor(fb, 1); + u8g2_SetFontMode(fb, 1); + + if(t - state->glitch_t > 250) { + state->glitch_t = t; + } + + const TextBlock* label = &NARRATIVE[state->label_id]; + for(size_t i = 0; i < label->line_size; i++) { + strcpy(buf, label->lines[i]); + + for(size_t glitch = 0; glitch < state->glitch_level; glitch++) { + buf[(state->glitch_t + glitch * 23) % strlen(buf)] = + ' ' + (state->glitch_t + glitch * 17) % ('z' - ' '); + } + + u8g2_DrawStr(fb, + (LABEL_X - state->screen.x) / SCALE, + ((LABEL_Y + LABEL_HEIGHT * i) + state->screen.y) / SCALE, + buf + ); + } + + if(state->combo_text) { + u8g2_SetDrawColor(fb, 0); + u8g2_DrawBox(fb, SCREEN_WIDTH / 2 - 15, 0, SCREEN_WIDTH / 2 + 15, 25); + u8g2_SetDrawColor(fb, 1); + u8g2_DrawFrame(fb, SCREEN_WIDTH / 2 - 15, 0, SCREEN_WIDTH / 2 + 15, 25); + u8g2_DrawStr(fb, SCREEN_WIDTH / 2 - 10, 15, "COCOCOCOMBO!"); + } +}