From 9c6bf5c110b53f9f7dcfbc54146ee4be4561de32 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 12 Jun 2021 23:52:52 +0900 Subject: [PATCH] DrawDungeon: Move walk-flag management code out of map.c So that ctx->map can just be null in DrawDungeon14 (GALZOO), where 2D maps are not drawn by the HLL. --- include/dungeon/dgn.h | 7 ++ include/dungeon/dungeon.h | 5 ++ include/dungeon/map.h | 6 +- src/dungeon/dgn.c | 19 ++++- src/dungeon/dungeon.c | 140 ++++++++++++++++++++++++++++++++ src/dungeon/map.c | 167 ++------------------------------------ src/hll/DrawDungeon.c | 8 +- 7 files changed, 181 insertions(+), 171 deletions(-) diff --git a/include/dungeon/dgn.h b/include/dungeon/dgn.h index df69673..c194294 100644 --- a/include/dungeon/dgn.h +++ b/include/dungeon/dgn.h @@ -80,6 +80,7 @@ struct dgn_cell { // Runtime data (not stored in .dgn) int x, y, z; + int walked; int event_blend_rate; float north_door_angle; float south_door_angle; @@ -119,6 +120,12 @@ void dgn_free(struct dgn *dgn); int dgn_cell_index(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z); struct dgn_cell *dgn_cell_at(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z); +int dgn_calc_conquer(struct dgn *dgn); + +static inline int dgn_nr_cells(struct dgn *dgn) +{ + return dgn->size_x * dgn->size_y * dgn->size_z; +} static inline bool dgn_is_in_map(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z) { diff --git a/include/dungeon/dungeon.h b/include/dungeon/dungeon.h index 79bc0f0..2674262 100644 --- a/include/dungeon/dungeon.h +++ b/include/dungeon/dungeon.h @@ -22,6 +22,7 @@ #include #include +struct page; struct dgn; struct dtx; struct tes; @@ -61,6 +62,10 @@ void dungeon_context_free(struct dungeon_context *ctx); bool dungeon_load(struct dungeon_context *ctx, int num); void dungeon_set_camera(int surface, float x, float y, float z, float angle, float angle_p); void dungeon_render(struct dungeon_context *ctx); +void dungeon_set_walked(int surface, int x, int y, int z, int flag); +int dungeon_calc_conquer(int surface); +bool dungeon_load_walk_data(int surface, int map, struct page **page); +bool dungeon_save_walk_data(int surface, int map, struct page **page); struct dungeon_context *dungeon_get_context(int surface); void dungeon_update(void); diff --git a/include/dungeon/map.h b/include/dungeon/map.h index 6f8db86..614a306 100644 --- a/include/dungeon/map.h +++ b/include/dungeon/map.h @@ -17,7 +17,6 @@ #ifndef SYSTEM4_DUNGEON_MAP_H #define SYSTEM4_DUNGEON_MAP_H -struct page; struct dungeon_context; struct dungeon_map; @@ -33,9 +32,6 @@ void dungeon_map_set_all_view(int surface, int flag); void dungeon_map_set_cg(int surface, int index, int sprite); void dungeon_map_set_small_map_floor(int surface, int floor); void dungeon_map_set_large_map_floor(int surface, int floor); -void dungeon_map_set_walked(int surface, int x, int y, int z, int flag); -int dungeon_map_calc_conquer(int surface); -bool dungeon_map_load_walk_data(int surface, int map, struct page **page); -bool dungeon_map_save_walk_data(int surface, int map, struct page **page); +void dungeon_map_reveal(struct dungeon_context *ctx, int x, int y, int z); #endif /* SYSTEM4_DUNGEON_MAP_H */ diff --git a/src/dungeon/dgn.c b/src/dungeon/dgn.c index bf432ad..ff7873b 100644 --- a/src/dungeon/dgn.c +++ b/src/dungeon/dgn.c @@ -42,7 +42,7 @@ struct dgn *dgn_parse(uint8_t *data, size_t size) dgn->size_z = buffer_read_int32(&r); buffer_skip(&r, 40); - int nr_cells = dgn->size_x * dgn->size_y * dgn->size_z; + int nr_cells = dgn_nr_cells(dgn); dgn->cells = xcalloc(nr_cells, sizeof(struct dgn_cell)); uint32_t x = 0, y = 0, z = 0; for (int i = 0; i < nr_cells; i++) { @@ -146,7 +146,7 @@ struct dgn *dgn_parse(uint8_t *data, size_t size) void dgn_free(struct dgn *dgn) { - int nr_cells = dgn->size_x * dgn->size_y * dgn->size_z; + int nr_cells = dgn_nr_cells(dgn); for (int i = 0; i < nr_cells; i++) { if (dgn->cells[i].visible_cells) @@ -175,6 +175,21 @@ struct dgn_cell *dgn_cell_at(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z return &dgn->cells[dgn_cell_index(dgn, x, y, z)]; } +int dgn_calc_conquer(struct dgn *dgn) +{ + int nr_cells = dgn_nr_cells(dgn); + int enterable = 0; + int walked = 0; + for (int i = 0; i < nr_cells; i++) { + if (!dgn->cells[i].enterable) + continue; + enterable++; + if (dgn->cells[i].walked) + walked++; + } + return walked * 100 / enterable; +} + struct pvs_cell { struct dgn_cell *cell; int distance; diff --git a/src/dungeon/dungeon.c b/src/dungeon/dungeon.c index 976947e..4bcbdc1 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -36,6 +36,7 @@ #include "sact.h" #include "sprite.h" #include "vm.h" +#include "vm/page.h" #include "xsystem4.h" #ifndef M_PI @@ -239,3 +240,142 @@ void dungeon_render(struct dungeon_context *ctx) glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo); } + +static void neighbor_reveal(struct dungeon_context *ctx, int x, int y, int z) +{ + struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z); + if (cell->floor < 0) { + cell->walked = 1; + dungeon_map_reveal(ctx, x, y, z); + } +} + +void dungeon_set_walked(int surface, int x, int y, int z, int flag) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx) + return; + dgn_cell_at(ctx->dgn, x, y, z)->walked = 1; + dungeon_map_reveal(ctx, x, y, z); + if (x > 0) + neighbor_reveal(ctx, x - 1, y, z); + if (x + 1u < ctx->dgn->size_x) + neighbor_reveal(ctx, x + 1, y, z); + if (z > 0) + neighbor_reveal(ctx, x, y, z - 1); + if (z + 1u < ctx->dgn->size_z) + neighbor_reveal(ctx, x, y, z + 1); +} + +int dungeon_calc_conquer(int surface) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return 0; + return dgn_calc_conquer(ctx->dgn); +} + +/* + * WalkData serialization format (in Rance VI): + * + * struct WalkData { + * int version; // zero + * int nr_maps; + * struct { + * int map_no; + * int size_x, size_y, size_z; + * int cells[size_x * size_y * size_z]; + * } maps[nr_maps]; + * }; + */ + +enum { + WALK_DATA_NOT_FOUND = -1, + WALK_DATA_BROKEN = -2, +}; + +static int find_walk_data(struct page *array, int map_no, struct dgn *dgn) +{ + if (!array) + return WALK_DATA_BROKEN; + if (array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->rank != 1) + VM_ERROR("Not a flat integer array"); + + int ptr = 0; + if (array->nr_vars < 2 || array->values[ptr++].i != 0) + return WALK_DATA_BROKEN; + int nr_maps = array->values[ptr++].i; + + for (int i = 0; i < nr_maps; i++) { + if (array->nr_vars < ptr + 4) + return WALK_DATA_BROKEN; + int no = array->values[ptr].i; + uint32_t size_x = array->values[ptr + 1].i; + uint32_t size_y = array->values[ptr + 2].i; + uint32_t size_z = array->values[ptr + 3].i; + int nr_cells = size_x * size_y * size_z; + if (no == map_no) { + if (size_x != dgn->size_x || size_y != dgn->size_y || size_z != dgn->size_z) + return WALK_DATA_BROKEN; + if (ptr + 4 + nr_cells > array->nr_vars) + return WALK_DATA_BROKEN; + return ptr; + } + ptr += 4 + nr_cells; + } + return WALK_DATA_NOT_FOUND; +} + +bool dungeon_load_walk_data(int surface, int map, struct page **page) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return false; + struct page *array = *page; + + int offset = find_walk_data(array, map, ctx->dgn); + if (offset < 0) + return false; + + offset += 4; + int nr_cells = dgn_nr_cells(ctx->dgn); + for (struct dgn_cell *c = ctx->dgn->cells; c < ctx->dgn->cells + nr_cells; c++) { + if (array->values[offset].i) + dungeon_map_reveal(ctx, c->x, c->y, c->z); + c->walked = array->values[offset++].i; + } + + return true; +} + +bool dungeon_save_walk_data(int surface, int map, struct page **page) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return false; + struct page *array = *page; + int nr_cells = dgn_nr_cells(ctx->dgn); + + int offset = find_walk_data(array, map, ctx->dgn); + if (offset == WALK_DATA_NOT_FOUND) { + offset = array->nr_vars; + array->values[1].i += 1; + union vm_value dim = { .i = array->nr_vars + 4 + nr_cells }; + *page = array = realloc_array(array, 1, &dim, AIN_ARRAY_INT, 0, false); + } else if (offset == WALK_DATA_BROKEN) { + if (array) + WARNING("Discarding broken walk data"); + union vm_value dim = { .i = 2 + 4 + nr_cells }; + *page = array = realloc_array(array, 1, &dim, AIN_ARRAY_INT, 0, false); + array->values[0].i = 0; + array->values[1].i = 1; + offset = 2; + } + array->values[offset++].i = map; + array->values[offset++].i = ctx->dgn->size_x; + array->values[offset++].i = ctx->dgn->size_y; + array->values[offset++].i = ctx->dgn->size_z; + for (int i = 0; i < nr_cells; i++) + array->values[offset++].i = ctx->dgn->cells[i].walked; + return true; +} diff --git a/src/dungeon/map.c b/src/dungeon/map.c index 73f6546..de3c627 100644 --- a/src/dungeon/map.c +++ b/src/dungeon/map.c @@ -24,7 +24,6 @@ #include "gfx/gfx.h" #include "sact.h" #include "vm.h" -#include "vm/page.h" #ifndef M_PI #define M_PI (3.14159265358979323846) @@ -60,7 +59,6 @@ struct dungeon_map { int large_map_floor; bool radar; bool all_visible; - int *walk_data; int offset_x, offset_y; }; @@ -85,7 +83,6 @@ void dungeon_map_free(struct dungeon_map *map) for (int i = 0; i < map->nr_textures; i++) gfx_delete_texture(&map->textures[i]); free(map->textures); - free(map->walk_data); free(map); } @@ -96,7 +93,6 @@ void dungeon_map_init(struct dungeon_context *ctx) map->textures = xcalloc(dgn->size_y, sizeof(struct texture)); map->nr_textures = dgn->size_y; - map->walk_data = xcalloc(dgn->size_x * dgn->size_y * dgn->size_z, sizeof(int)); // Calculate the bounding box on the XZ plane so that map is drawn in the // center of the texture. uint32_t min_x = dgn->size_x; @@ -130,11 +126,10 @@ void dungeon_map_init(struct dungeon_context *ctx) } } -static void reveal_cell(struct dungeon_context *ctx, int dgn_x, int dgn_y, int dgn_z) +void dungeon_map_reveal(struct dungeon_context *ctx, int x, int y, int z) { - ctx->map->walk_data[dgn_cell_index(ctx->dgn, dgn_x, dgn_y, dgn_z)] = 1; - struct texture *dst = &ctx->map->textures[dgn_y]; - Point pos = texture_pos(ctx, dgn_x, dgn_z); + struct texture *dst = &ctx->map->textures[y]; + Point pos = texture_pos(ctx, x, z); gfx_fill_amap(dst, pos.x, pos.y, CS, CS, 255); } @@ -302,14 +297,10 @@ void dungeon_map_draw_lmap(int surface, int sprite) static void redraw_event_symbols(struct dungeon_context *ctx) { - struct dgn *dgn = ctx->dgn; - for (uint32_t y = 0; y < dgn->size_y; y++) { - for (uint32_t z = 0; z < dgn->size_z; z++) { - for (uint32_t x = 0; x < dgn->size_x; x++) { - if (dgn_cell_at(dgn, x, y, z)->floor_event) - dungeon_map_update_cell(ctx, x, y, z); - } - } + int nr_cells = dgn_nr_cells(ctx->dgn); + for (struct dgn_cell *c = ctx->dgn->cells; c < ctx->dgn->cells + nr_cells; c++) { + if (c->floor_event) + dungeon_map_update_cell(ctx, c->x, c->y, c->z); } } @@ -356,147 +347,3 @@ void dungeon_map_set_large_map_floor(int surface, int floor) return; ctx->map->large_map_floor = floor; } - -void dungeon_map_set_walked(int surface, int x, int y, int z, int flag) -{ - struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx) - return; - reveal_cell(ctx, x, y, z); - if (x > 0 && dgn_cell_at(ctx->dgn, x - 1, y, z)->floor < 0) - reveal_cell(ctx, x - 1, y, z); - if (x + 1u < ctx->dgn->size_x && dgn_cell_at(ctx->dgn, x + 1, y, z)->floor < 0) - reveal_cell(ctx, x + 1, y, z); - if (z > 0 && dgn_cell_at(ctx->dgn, x, y, z - 1)->floor < 0) - reveal_cell(ctx, x, y, z - 1); - if (z + 1u < ctx->dgn->size_z && dgn_cell_at(ctx->dgn, x, y, z + 1)->floor < 0) - reveal_cell(ctx, x, y, z + 1); -} - -int dungeon_map_calc_conquer(int surface) -{ - struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx || !ctx->dgn) - return 0; - - int nr_cells = ctx->dgn->size_x * ctx->dgn->size_y * ctx->dgn->size_z; - int enterable = 0; - int walked = 0; - for (int i = 0; i < nr_cells; i++) { - if (!ctx->dgn->cells[i].enterable) - continue; - enterable++; - if (ctx->map->walk_data[i]) - walked++; - } - return walked * 100 / enterable; -} - -/* - * WalkData serialization format (in Rance VI): - * - * struct WalkData { - * int version; // zero - * int nr_maps; - * struct { - * int map_no; - * int size_x, size_y, size_z; - * int cells[size_x * size_y * size_z]; - * } maps[nr_maps]; - * }; - */ - -enum { - WALK_DATA_NOT_FOUND = -1, - WALK_DATA_BROKEN = -2, -}; - -static int find_walk_data(struct page *array, int map_no, struct dgn *dgn) -{ - if (!array) - return WALK_DATA_BROKEN; - if (array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->rank != 1) - VM_ERROR("Not a flat integer array"); - - int ptr = 0; - if (array->nr_vars < 2 || array->values[ptr++].i != 0) - return WALK_DATA_BROKEN; - int nr_maps = array->values[ptr++].i; - - for (int i = 0; i < nr_maps; i++) { - if (array->nr_vars < ptr + 4) - return WALK_DATA_BROKEN; - int no = array->values[ptr].i; - uint32_t size_x = array->values[ptr + 1].i; - uint32_t size_y = array->values[ptr + 2].i; - uint32_t size_z = array->values[ptr + 3].i; - int nr_cells = size_x * size_y * size_z; - if (no == map_no) { - if (size_x != dgn->size_x || size_y != dgn->size_y || size_z != dgn->size_z) - return WALK_DATA_BROKEN; - if (ptr + 4 + nr_cells > array->nr_vars) - return WALK_DATA_BROKEN; - return ptr; - } - ptr += 4 + nr_cells; - } - return WALK_DATA_NOT_FOUND; -} - -bool dungeon_map_load_walk_data(int surface, int map, struct page **page) -{ - struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx || !ctx->dgn) - return false; - struct page *array = *page; - - int offset = find_walk_data(array, map, ctx->dgn); - if (offset < 0) - return false; - - offset += 4; - int i = 0; - for (uint32_t z = 0; z < ctx->dgn->size_z; z++) { - for (uint32_t y = 0; y < ctx->dgn->size_y; y++) { - for (uint32_t x = 0; x < ctx->dgn->size_x; x++) { - if (array->values[offset].i) - reveal_cell(ctx, x, y, z); - ctx->map->walk_data[i++] = array->values[offset++].i; - } - } - } - - return true; -} - -bool dungeon_map_save_walk_data(int surface, int map, struct page **page) -{ - struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx || !ctx->dgn) - return false; - struct page *array = *page; - int nr_cells = ctx->dgn->size_x * ctx->dgn->size_y * ctx->dgn->size_z; - - int offset = find_walk_data(array, map, ctx->dgn); - if (offset == WALK_DATA_NOT_FOUND) { - offset = array->nr_vars; - array->values[1].i += 1; - union vm_value dim = { .i = array->nr_vars + 4 + nr_cells }; - *page = array = realloc_array(array, 1, &dim, AIN_ARRAY_INT, 0, false); - } else if (offset == WALK_DATA_BROKEN) { - if (array) - WARNING("Discarding broken walk data"); - union vm_value dim = { .i = 2 + 4 + nr_cells }; - *page = array = realloc_array(array, 1, &dim, AIN_ARRAY_INT, 0, false); - array->values[0].i = 0; - array->values[1].i = 1; - offset = 2; - } - array->values[offset++].i = map; - array->values[offset++].i = ctx->dgn->size_x; - array->values[offset++].i = ctx->dgn->size_y; - array->values[offset++].i = ctx->dgn->size_z; - for (int i = 0; i < nr_cells; i++) - array->values[offset++].i = ctx->map->walk_data[i]; - return true; -} diff --git a/src/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index 81e82b1..37cd395 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -360,12 +360,12 @@ HLL_LIBRARY(DrawDungeon, HLL_EXPORT(SetDrawMapRadar, dungeon_map_set_radar), HLL_EXPORT(SetDrawHalfFlag, DrawDungeon_SetDrawHalfFlag), HLL_EXPORT(GetDrawHalfFlag, DrawDungeon_GetDrawHalfFlag), - HLL_EXPORT(SetWalked, dungeon_map_set_walked), + HLL_EXPORT(SetWalked, dungeon_set_walked), HLL_TODO_EXPORT(SetWalkedAll, DrawDungeon_SetWalkedAll), HLL_TODO_EXPORT(CalcNumofFloor, DrawDungeon_CalcNumofFloor), HLL_TODO_EXPORT(CalcNumofWalk, DrawDungeon_CalcNumofWalk), HLL_TODO_EXPORT(CalcNumofWalk2, DrawDungeon_CalcNumofWalk2), - HLL_EXPORT(CalcConquer, dungeon_map_calc_conquer), + HLL_EXPORT(CalcConquer, dungeon_calc_conquer), HLL_EXPORT(SetInterlaceMode, DrawDungeon_SetInterlaceMode), HLL_EXPORT(SetDirect3DMode, DrawDungeon_SetDirect3DMode), HLL_EXPORT(SaveDrawSettingFlag, DrawDungeon_SaveDrawSettingFlag), @@ -378,6 +378,6 @@ HLL_LIBRARY(DrawDungeon, HLL_EXPORT(GetTexSound, DrawDungeon_GetTexSound), HLL_EXPORT(StopTimer, DrawDungeon_StopTimer), HLL_EXPORT(RestartTimer, DrawDungeon_RestartTimer), - HLL_EXPORT(LoadWalkData, dungeon_map_load_walk_data), - HLL_EXPORT(SaveWalkData, dungeon_map_save_walk_data) + HLL_EXPORT(LoadWalkData, dungeon_load_walk_data), + HLL_EXPORT(SaveWalkData, dungeon_save_walk_data) );