From fbd105b697b9c40eac736d23d4b66196476facec Mon Sep 17 00:00:00 2001 From: kichikuou Date: Mon, 14 Jul 2025 15:13:39 +0900 Subject: [PATCH] DrawDungeon2: Implement pathfinding functions --- include/dungeon/dgn.h | 2 ++ include/dungeon/dungeon.h | 1 + src/dungeon/dgn.c | 60 +++++++++++++++++++++++++++++++++++++++ src/dungeon/dungeon.c | 8 ++++++ src/hll/DrawDungeon.c | 7 ++--- 5 files changed, 74 insertions(+), 4 deletions(-) diff --git a/include/dungeon/dgn.h b/include/dungeon/dgn.h index 1a4366b..195068a 100644 --- a/include/dungeon/dgn.h +++ b/include/dungeon/dgn.h @@ -91,6 +91,7 @@ struct dgn_cell { int32_t south_event2; int32_t east_event2; int32_t west_event2; + int pathfinding_cost; struct dgn_cell **visible_cells; }; @@ -139,5 +140,6 @@ static inline bool dgn_is_in_map(struct dgn *dgn, uint32_t x, uint32_t y, uint32 struct dgn_cell **dgn_get_visible_cells(struct dgn *dgn, int x, int y, int z, int *nr_cells_out); struct dgn *dgn_generate_drawdungeon2(int level); +void dgn_paint_step(struct dgn *dgn, int x, int y); #endif /* SYSTEM4_DGN_H */ diff --git a/include/dungeon/dungeon.h b/include/dungeon/dungeon.h index e1c7681..939b1be 100644 --- a/include/dungeon/dungeon.h +++ b/include/dungeon/dungeon.h @@ -76,6 +76,7 @@ void dungeon_set_walked_all(int surface); 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); +void dungeon_paint_step(int surface, int x, int y, int z); struct dungeon_context *dungeon_get_context(int surface); diff --git a/src/dungeon/dgn.c b/src/dungeon/dgn.c index ab80e5b..f231f18 100644 --- a/src/dungeon/dgn.c +++ b/src/dungeon/dgn.c @@ -559,6 +559,7 @@ struct dgn *dgn_generate_drawdungeon2(int level) cell->roof_orientation = -1; cell->roof_texture = -1; cell->roof_underside_texture = -1; + cell->pathfinding_cost = -1; if (map[x][z] == '#') { continue; @@ -593,3 +594,62 @@ struct dgn *dgn_generate_drawdungeon2(int level) } return dgn; } + +// Set pathfinding_cost for each cell on the shortest path to the exit cell +void dgn_paint_step(struct dgn *dgn, int start_x, int start_y) +{ + int nr_cells = dgn_nr_cells(dgn); + for (int i = 0; i < nr_cells; i++) { + dgn->cells[i].pathfinding_cost = -1; + } + + // BFS. + short dist[DD2_MAP_WIDTH][DD2_MAP_HEIGHT] = {0}; + struct { int8_t x, y; } prev[DD2_MAP_WIDTH][DD2_MAP_HEIGHT]; + struct point_list queue = {0}; + int queue_ptr = 0; + + dist[start_x][start_y] = 1; + point_list_add(&queue, start_x, start_y); + + while (queue_ptr < queue.size) { + int cx = queue.p[queue_ptr].x; + int cy = queue.p[queue_ptr].y; + if (cx == dgn->exit_x && cy == dgn->exit_y) + break; + queue_ptr++; + + // Add adjacent cells to the queue + const int dx_offsets[] = {0, 0, -1, 1}; + const int dy_offsets[] = {-1, 1, 0, 0}; + for (int i = 0; i < 4; i++) { + int nx = cx + dx_offsets[i]; + int ny = cy + dy_offsets[i]; + if (nx >= 0 && nx < DD2_MAP_WIDTH && ny >= 0 && ny < DD2_MAP_HEIGHT && + !dist[nx][ny] && dgn->cells[dgn_cell_index(dgn, nx, 0, ny)].floor >= 0) { + dist[nx][ny] = dist[cx][cy] + 1; + prev[nx][ny].x = cx; + prev[nx][ny].y = cy; + point_list_add(&queue, nx, ny); + } + } + } + if (queue_ptr >= queue.size) { + // The exit is not reachable from the start (should not happen) + return; + } + + // Backtrack from the exit to the start to paint the path + int x = dgn->exit_x; + int y = dgn->exit_y; + for (;;) { + struct dgn_cell *cell = &dgn->cells[dgn_cell_index(dgn, x, 0, y)]; + cell->pathfinding_cost = dist[x][y] - 1; // -1 to make the start cell 0 + if (x == start_x && y == start_y) + break; + int px = prev[x][y].x; + int py = prev[x][y].y; + x = px; + y = py; + } +} diff --git a/src/dungeon/dungeon.c b/src/dungeon/dungeon.c index 7d4cc67..5a10c5e 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -567,6 +567,14 @@ bool dungeon_save_walk_data(int surface, int map, struct page **page) } } +void dungeon_paint_step(int surface, int x, int y, int z) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return; + dgn_paint_step(ctx->dgn, x, z); +} + static cJSON *dungeon_to_json(struct sact_sprite *sp, bool verbose) { cJSON *obj, *cam; diff --git a/src/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index 7f49f97..b1e7d35 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -413,16 +413,15 @@ static void DrawDungeon2_GetExitPos(int surface, int *x, int *y) *y = ctx->dgn->exit_y; } -//void DrawDungeon2_PaintStep(int nSurface, int nX, int nY, int nZ); -//int DrawDungeon2_GetMapStep(int nSurface, int nX, int nY, int nZ); +CELL_GETTER(DrawDungeon2_GetMapStep, -1, cell->pathfinding_cost); HLL_LIBRARY(DrawDungeon2, HLL_EXPORT(Init, DrawDungeon2_Init), DRAW_DUNGEON_EXPORTS, HLL_EXPORT(GetPlayerStartPos, DrawDungeon2_GetPlayerStartPos), HLL_EXPORT(GetExitPos, DrawDungeon2_GetExitPos), - HLL_TODO_EXPORT(PaintStep, DrawDungeon2_PaintStep), - HLL_TODO_EXPORT(GetMapStep, DrawDungeon2_GetMapStep) + HLL_EXPORT(PaintStep, dungeon_paint_step), + HLL_EXPORT(GetMapStep, DrawDungeon2_GetMapStep) ); static void DrawDungeon14_SetRasterScroll(int surface, int type)