add a sandbox level to test enemy behaviors

This commit is contained in:
Lephenixnoir 2022-05-21 18:54:22 +01:00
parent de57441d24
commit 0b0a667ce0
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
12 changed files with 185 additions and 42 deletions

View File

@ -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

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="24" height="11" tilewidth="16" tileheight="16" infinite="0" nextlayerid="3" nextobjectid="1">
<map version="1.8" tiledversion="1.8.4" orientation="orthogonal" renderorder="right-down" width="24" height="11" tilewidth="16" tileheight="16" infinite="0" nextlayerid="3" nextobjectid="1">
<tileset firstgid="1" source="../tilesets/lab.tsx"/>
<layer id="1" name="Ground" width="24" height="11">
<data encoding="csv">

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.8" tiledversion="1.8.4" orientation="orthogonal" renderorder="right-down" width="24" height="11" tilewidth="16" tileheight="16" infinite="0" nextlayerid="3" nextobjectid="1">
<tileset firstgid="1" source="../tilesets/cavern.tsx"/>
<layer id="1" name="Ground" width="24" height="11">
<data encoding="csv">
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
</data>
</layer>
<layer id="2" name="Decorations" width="24" height="11">
<data encoding="csv">
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
</data>
</layer>
</map>

View File

@ -0,0 +1,8 @@
name: Sandbox
map: lvsandbox
player_spawn: 6,5
spawner: 17,5
wave: 1s 1*slime/1

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.8" tiledversion="1.8.4" name="heaven" tilewidth="16" tileheight="16" tilecount="16" columns="8">
<image source="heaven.png" width="128" height="32"/>
</tileset>

View File

@ -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];
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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];

View File

@ -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));

View File

@ -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;