From 0b0a667ce0d7b6d6bdb8c3f42efaae0d24008858 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sat, 21 May 2022 18:54:22 +0100 Subject: [PATCH] add a sandbox level to test enemy behaviors --- CMakeLists.txt | 2 + assets-cg/levels/lv2.tmx | 2 +- assets-cg/levels/lvsandbox.tmx | 34 ++++++++++ assets-cg/levels/lvsandbox.txt | 8 +++ assets-cg/tilesets/heaven.tsx | 4 ++ src/enemies.c | 3 + src/game.c | 33 +++++---- src/game.h | 3 + src/level.c | 6 ++ src/level.h | 4 ++ src/main.c | 120 ++++++++++++++++++++++++++------- src/menu.c | 8 +-- 12 files changed, 185 insertions(+), 42 deletions(-) create mode 100644 assets-cg/levels/lvsandbox.tmx create mode 100644 assets-cg/levels/lvsandbox.txt create mode 100644 assets-cg/tilesets/heaven.tsx diff --git a/CMakeLists.txt b/CMakeLists.txt index d6d9f39..806d521 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,8 @@ set(ASSETS assets-cg/levels/lv1.txt assets-cg/levels/lv2.tmx assets-cg/levels/lv2.txt + assets-cg/levels/lvsandbox.tmx + assets-cg/levels/lvsandbox.txt # Menu assets-cg/menu_title.png assets-cg/menu_arrows.png diff --git a/assets-cg/levels/lv2.tmx b/assets-cg/levels/lv2.tmx index 708689f..acf079d 100644 --- a/assets-cg/levels/lv2.tmx +++ b/assets-cg/levels/lv2.tmx @@ -1,5 +1,5 @@ - + diff --git a/assets-cg/levels/lvsandbox.tmx b/assets-cg/levels/lvsandbox.tmx new file mode 100644 index 0000000..06efdc8 --- /dev/null +++ b/assets-cg/levels/lvsandbox.tmx @@ -0,0 +1,34 @@ + + + + + +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,7,15,8,7,8,7,16,8,7,15,7,7,16,8,2,2,2,2,2, +2,2,2,2,2,4,4,14,14,6,3,3,3,3,6,4,4,14,4,2,2,2,2,2, +2,2,2,2,2,14,14,5,3,3,3,5,5,3,3,3,5,4,4,2,2,2,2,2, +2,2,2,2,2,3,5,3,3,3,4,5,5,4,3,3,3,5,3,2,2,2,2,2, +2,2,2,2,2,5,3,3,6,5,5,6,6,5,5,6,3,3,5,2,2,2,2,2, +2,2,2,2,2,3,5,3,3,3,4,5,5,4,3,3,3,5,3,2,2,2,2,2, +2,2,2,2,2,14,4,5,3,3,3,5,5,3,3,3,5,4,14,2,2,2,2,2, +2,2,2,2,2,4,14,4,4,6,3,3,3,3,6,14,14,4,4,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,10,0,0,0,0,0,10,0,0,9,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/assets-cg/levels/lvsandbox.txt b/assets-cg/levels/lvsandbox.txt new file mode 100644 index 0000000..1a31450 --- /dev/null +++ b/assets-cg/levels/lvsandbox.txt @@ -0,0 +1,8 @@ +name: Sandbox +map: lvsandbox + +player_spawn: 6,5 + +spawner: 17,5 + +wave: 1s 1*slime/1 diff --git a/assets-cg/tilesets/heaven.tsx b/assets-cg/tilesets/heaven.tsx new file mode 100644 index 0000000..6a4f2e5 --- /dev/null +++ b/assets-cg/tilesets/heaven.tsx @@ -0,0 +1,4 @@ + + + + diff --git a/src/enemies.c b/src/enemies.c index e5af723..13c485c 100644 --- a/src/enemies.c +++ b/src/enemies.c @@ -118,6 +118,9 @@ static enemy_t const * const enemies[] = { enemy_t const *enemy_data(int enemy_id) { + if(enemy_id < 1 || (size_t)enemy_id >= sizeof enemies / sizeof *enemies) + return NULL; + return enemies[enemy_id]; } diff --git a/src/game.c b/src/game.c index f3e8061..cf2bad3 100644 --- a/src/game.c +++ b/src/game.c @@ -350,9 +350,27 @@ int game_sort_entities(game_t const *g, entity_measure_t *measure, // Per-frame update functions //--- -void game_spawn_enemies(game_t *g) +void game_spawn_enemy(game_t *g, int identity, int spawner) { level_t const *level = g->level; + + /* Select a random spawner if none is specified */ + if(spawner < 0) + spawner = rand() % level->spawner_count; + + entity_t *e = enemy_make(identity); + g->wave_spawned++; + if(!e) return; + + physical_t *p = getcomp(e, physical); + p->x = fix(level->spawner_x[spawner]) + fix(0.5); + p->y = fix(level->spawner_y[spawner]) + fix(0.5); + + game_spawn_entity(g, e); +} + +void game_spawn_enemies(game_t *g) +{ level_event_t const *event = game_current_event(g); level_wave_t const *wave = game_current_wave(g); if(!wave || !g->wave_left) return; @@ -379,18 +397,7 @@ void game_spawn_enemies(game_t *g) return; /* just in case */ g->wave_left[entry]--; - /* Select a random spawner */ - int s = rand() % level->spawner_count; - - entity_t *e = enemy_make(wave->entries[entry].identity); - g->wave_spawned++; - if(!e) continue; - - physical_t *p = getcomp(e, physical); - p->x = fix(level->spawner_x[s]) + fix(0.5); - p->y = fix(level->spawner_y[s]) + fix(0.5); - - game_spawn_entity(g, e); + game_spawn_enemy(g, wave->entries[entry].identity, -1); } } diff --git a/src/game.h b/src/game.h index c752624..9c4914d 100644 --- a/src/game.h +++ b/src/game.h @@ -96,6 +96,9 @@ void game_add_entity(game_t *g, entity_t *e); /* Like game_add_entity(), but with a visual effect */ void game_spawn_entity(game_t *g, entity_t *e); +/* Spawn a new enemy into the arena. Spawner is selected randomly if -1. */ +void game_spawn_enemy(game_t *g, int identity, int spawner_id); + /* Remove dead entities. */ void game_remove_dead_entities(game_t *g); diff --git a/src/level.c b/src/level.c index 30cdda9..56166e3 100644 --- a/src/level.c +++ b/src/level.c @@ -1,5 +1,11 @@ #include "level.h" +level_t const *level_all[LEVEL_COUNT] = { + &level_lv1, + &level_lv2, + &level_lvsandbox, +}; + int level_wave_count(level_t const *lv) { int wave_count = 0; diff --git a/src/level.h b/src/level.h index 8b3069d..c618d1f 100644 --- a/src/level.h +++ b/src/level.h @@ -80,3 +80,7 @@ int level_wave_count(level_t const *lv); /* List of levels */ extern level_t level_lv1; extern level_t level_lv2; +extern level_t level_lvsandbox; + +#define LEVEL_COUNT 3 +extern level_t const *level_all[LEVEL_COUNT]; diff --git a/src/main.c b/src/main.c index a28567f..eea2417 100644 --- a/src/main.c +++ b/src/main.c @@ -53,18 +53,19 @@ int main(void) usb_open(interfaces, GINT_CALL_NULL); int lv = menu_level_select(0); - level_t const *level = NULL; if(lv == -1) return 1; - if(lv == 0) level = &level_lv1; - if(lv == 1) level = &level_lv2; - game_t game = { 0 }; camera_t *c = &game.camera; - game_load(&game, level); + game_load(&game, level_all[lv]); struct { + /* Developer menu is open */ + bool dev_menu; + /* Show developer submenus */ + bool dev_menu_view; + bool dev_menu_spawn; /* Show variables */ bool show_vars; /* Show hitboxes */ @@ -175,7 +176,7 @@ int main(void) fixed_t dt_rt = dt; if(bullet_time) dt >>= 2; - if(debug.paused) + if(debug.paused || debug.dev_menu) dt = dt_rt = 0; perf_render = prof_make(); @@ -215,6 +216,42 @@ int main(void) dprint(15, 160, gray, "[)] -/+ [sin]"); } + if(debug.dev_menu_view) { + uint32_t *vram = (void *)gint_vram; + for(int i = 0; i < DWIDTH * DHEIGHT / 2; i++) + vram[i] = (vram[i] & 0xf7def7de) >> 1; + + int fg = C_RGB(31, 31, 0); + dprint(3, 25, debug.show_hitboxes ? fg : C_WHITE, + "[1] Show hitboxes"); + dprint(3, 40, debug.show_bfs_field ? fg : C_WHITE, + "[2] Show BFS field"); + dprint(3, 55, debug.show_path ? fg : C_WHITE, + "[3] Show pathfinding to spawner"); + } + + if(debug.dev_menu_spawn) { + uint32_t *vram = (void *)gint_vram; + for(int i = 0; i < DWIDTH * DHEIGHT / 2; i++) + vram[i] = (vram[i] & 0xf7def7de) >> 1; + + dprint(3, 25, C_WHITE, "Spawn an enemy"); + + for(int i = 0; i < 15; i++) { + int x=12+124*(i/5), y=40+15*(i%5); + enemy_t const *enemy = enemy_data(i+1); + if(!enemy) + continue; + + anim_frame_t *frame = enemy->anim_idle->start[0]; + dprint(x, y, C_WHITE, "[%d]", i+1); + dsubimage(x+20, y+4 - frame->h / 2, frame->sheet, + frame->x, frame->y, frame->w, frame->h, DIMAGE_NONE); + dprint(x+40, y, C_WHITE, "%s (lv. %d)", enemy->name, + enemy->level); + } + } + if(debug.show_path) { if(debug.grid_path.points) for(int i = 0; i < debug.grid_path.length; i++) { @@ -258,17 +295,17 @@ int main(void) dprint(1, 29, C_WHITE, "Simul: %.3D ms", time_simul); } - if(keydown(KEY_VARS)) { + if(debug.dev_menu) { int fg = C_RGB(31, 31, 0); fkey_button(1, "PARAMS", debug.show_vars ? fg : C_WHITE); - fkey_button(2, "HITBOX", debug.show_hitboxes ? fg : C_WHITE); - fkey_button(3, "BFS", debug.show_bfs_field ? fg : C_WHITE); - fkey_button(4, "PATHS", debug.show_path ? fg : C_WHITE); + fkey_button(2, "VIEW", debug.dev_menu_view ? fg : C_WHITE); + fkey_button(3, "SPAWN", debug.dev_menu_spawn ? fg : C_WHITE); + fkey_button(4, "GOD", C_WHITE); fkey_button(5, "PERF", debug.show_perf ? fg : C_WHITE); fkey_button(6, "PAUSE", debug.paused ? fg : C_WHITE); } - if(keydown(KEY_F6) && keydown(KEY_ALPHA) && !keydown(KEY_VARS) + if(keydown(KEY_F6) && keydown(KEY_ALPHA) && debug.dev_menu && usb_is_open()) { rogue_life_video_capture = !rogue_life_video_capture; } @@ -301,18 +338,52 @@ int main(void) stop = true; /* Debug settings */ -// if(ev.key == KEY_F1 && keydown(KEY_VARS)) -// debug.show_vars ^= 1; - if(ev.key == KEY_F2 && keydown(KEY_VARS)) - debug.show_hitboxes ^= 1; - if(ev.key == KEY_F3 && keydown(KEY_VARS)) - debug.show_bfs_field ^= 1; - if(ev.key == KEY_F4 && keydown(KEY_VARS)) - debug.show_path ^= 1; - if(ev.key == KEY_F5 && keydown(KEY_VARS)) + if(ev.key == KEY_OPTN) { + debug.dev_menu ^= 1; + if(!debug.dev_menu) { + debug.dev_menu_view = 0; + debug.dev_menu_spawn = 0; + } + } + /* Main debug menu entries */ + if(ev.key == KEY_F1 && debug.dev_menu) + debug.show_vars ^= 1; + if(ev.key == KEY_F2 && debug.dev_menu) { + debug.dev_menu_view ^= 1; + if(debug.dev_menu_view) + debug.dev_menu_spawn = 0; + } + if(ev.key == KEY_F3 && debug.dev_menu) { + debug.dev_menu_spawn ^= 1; + if(debug.dev_menu_spawn) + debug.dev_menu_view = 0; + } + if(ev.key == KEY_F4 && debug.dev_menu) { + player_add_xp(game.player, 1000); + fighter_invulnerability(game.player, fix(999.0)); + player_f->skills[1] = AOE_SHOCK; + player_f->skills[2] = AOE_JUDGEMENT; + player_f->skills[3] = SKILL_DASH; + player_f->skills[4] = AOE_BULLET; + } + if(ev.key == KEY_F5 && debug.dev_menu) debug.show_perf ^= 1; - if(ev.key == KEY_F6 && keydown(KEY_VARS)) + if(ev.key == KEY_F6 && debug.dev_menu) debug.paused ^= 1; + if(ev.key == KEY_F2 && debug.dev_menu) { + } + /* Debug menu: View */ + if(ev.key == KEY_1 && debug.dev_menu_view) + debug.show_hitboxes ^= 1; + if(ev.key == KEY_2 && debug.dev_menu_view) + debug.show_bfs_field ^= 1; + if(ev.key == KEY_3 && debug.dev_menu_view) + debug.show_path ^= 1; + /* Debug menu: Spawn */ + if(keycode_digit(ev.key) >= 0 && debug.dev_menu_spawn) { + int id = keycode_digit(ev.key); + game_spawn_enemy(&game, id, -1); + } #if 0 if(ev.key == KEY_XOT) @@ -356,11 +427,12 @@ int main(void) camera_zoom(c, c->zoom - 1); #endif - if(!debug.paused && !game.menu_open && ev.key == KEY_SHIFT) + if(!debug.paused && !game.menu_open && ev.key == KEY_SHIFT + && !debug.dev_menu) attack = true; /* Menus */ - if(!debug.paused && ev.key == KEY_F6 && !keydown(KEY_VARS) + if(!debug.paused && ev.key == KEY_F6 && !debug.dev_menu && !keydown(KEY_ALPHA)) game.menu_open = !game.menu_open; @@ -423,7 +495,7 @@ int main(void) /* Player skills (including movement skills) */ bool can_use_skill = !debug.paused && !game.menu_open - && player_f->HP > 0 && !keydown(KEY_VARS); + && player_f->HP > 0 && !debug.dev_menu; if(can_use_skill && keydown(KEY_F1)) skill_use(&game, player, 1, fdir(next_dir)); diff --git a/src/menu.c b/src/menu.c index fb1c353..e26e474 100644 --- a/src/menu.c +++ b/src/menu.c @@ -60,11 +60,11 @@ int menu_level_select(int start) { extern bopti_image_t img_menu_title, img_menu_arrows; - menu_game_t *options[2]; - #define OPTION_COUNT ((int)(sizeof options / sizeof options[0])) + menu_game_t *options[LEVEL_COUNT]; + #define OPTION_COUNT LEVEL_COUNT - options[0] = menu_load_game(&level_lv1); - options[1] = menu_load_game(&level_lv2); + for(int i = 0; i < LEVEL_COUNT; i++) + options[i] = menu_load_game(level_all[i]); int selection = (start >= 0 && start < OPTION_COUNT) ? start : 0; int target_x=0, x=0;