feat(trails): render authoritative player route trails
This commit is contained in:
@@ -68,6 +68,36 @@ static int game_has_passage(const maze32_game_t* game, maze32_cell_t cell,
|
||||
return (game_passages(game, cell) & passage) != 0U;
|
||||
}
|
||||
|
||||
static uint16_t trail_edge_index(const maze32_maze_t* maze, maze32_cell_t cell,
|
||||
maze32_passage_t passage) {
|
||||
uint16_t horizontal_count = (uint16_t)(maze->config.height * (maze->config.width - 1U));
|
||||
if (passage == MAZE32_PASSAGE_EAST) {
|
||||
return (uint16_t)(cell.y * (maze->config.width - 1U) + cell.x);
|
||||
}
|
||||
return (uint16_t)(horizontal_count + cell.y * maze->config.width + cell.x);
|
||||
}
|
||||
|
||||
static uint8_t trail_owner_mask(const maze32_game_t* game, uint16_t edge_index) {
|
||||
uint8_t byte = game->trail_owners[edge_index / 4U];
|
||||
return (uint8_t)((byte >> ((edge_index % 4U) * 2U)) & 0x03U);
|
||||
}
|
||||
|
||||
static void mark_trail_edge(maze32_game_t* game, uint8_t player_index, maze32_cell_t origin,
|
||||
maze32_game_direction_t direction) {
|
||||
maze32_cell_t canonical = origin;
|
||||
maze32_passage_t passage = direction_passage(direction);
|
||||
if (direction == MAZE32_GAME_DIRECTION_NORTH) {
|
||||
canonical.y--;
|
||||
passage = MAZE32_PASSAGE_SOUTH;
|
||||
} else if (direction == MAZE32_GAME_DIRECTION_WEST) {
|
||||
canonical.x--;
|
||||
passage = MAZE32_PASSAGE_EAST;
|
||||
}
|
||||
uint16_t edge_index = trail_edge_index(game->maze, canonical, passage);
|
||||
uint8_t shift = (uint8_t)((edge_index % 4U) * 2U);
|
||||
game->trail_owners[edge_index / 4U] |= (uint8_t)((1U << player_index) << shift);
|
||||
}
|
||||
|
||||
static void reset_perseverance(maze32_game_player_t* player) {
|
||||
player->perseverance_hits = 0U;
|
||||
player->perseverance_last_impact_ms = 0U;
|
||||
@@ -518,6 +548,7 @@ maze32_game_command_result_t maze32_game_process_next(maze32_game_t* game) {
|
||||
}
|
||||
finish_outward_move(game, player_index, command.submitted_ms, &processed);
|
||||
} else {
|
||||
maze32_cell_t origin = player->position;
|
||||
maze32_passage_t passage = direction_passage(command.direction);
|
||||
if (!game_has_passage(game, player->position, passage)) {
|
||||
processed.breakthrough_hits = record_wall_impact(
|
||||
@@ -544,6 +575,7 @@ maze32_game_command_result_t maze32_game_process_next(maze32_game_t* game) {
|
||||
return processed;
|
||||
}
|
||||
player->position = moved_cell(player->position, command.direction);
|
||||
mark_trail_edge(game, player_index, origin, command.direction);
|
||||
accept_player_move(player, command.submitted_ms);
|
||||
processed.moved = 1U;
|
||||
resolve_cell_entry(game, player_index, &processed);
|
||||
@@ -670,6 +702,20 @@ maze32_game_result_t maze32_game_project_view(const maze32_game_t* game, maze32_
|
||||
view->cells[view->cell_count].cell_index = index;
|
||||
view->cells[view->cell_count].passages = game_passages(game, cell);
|
||||
view->cells[view->cell_count].opened_passages = game->opened_passages[index];
|
||||
if (x + 1U < game->maze->config.width) {
|
||||
maze32_cell_t east = {x + 1U, y};
|
||||
if (reveal_all || is_visible(center, east, radius)) {
|
||||
view->cells[view->cell_count].trail_east = trail_owner_mask(
|
||||
game, trail_edge_index(game->maze, cell, MAZE32_PASSAGE_EAST));
|
||||
}
|
||||
}
|
||||
if (y + 1U < game->maze->config.height) {
|
||||
maze32_cell_t south = {x, y + 1U};
|
||||
if (reveal_all || is_visible(center, south, radius)) {
|
||||
view->cells[view->cell_count].trail_south = trail_owner_mask(
|
||||
game, trail_edge_index(game->maze, cell, MAZE32_PASSAGE_SOUTH));
|
||||
}
|
||||
}
|
||||
view->cell_count++;
|
||||
}
|
||||
}
|
||||
@@ -861,9 +907,9 @@ maze32_game_result_t maze32_game_serialize_view_chunk(const maze32_view_t* view,
|
||||
}
|
||||
for (size_t index = first; index < end; ++index) {
|
||||
const maze32_view_cell_t* cell = &view->cells[index];
|
||||
if (!append_text(output, output_size, &offset, "%s[%u,%u,%u]",
|
||||
if (!append_text(output, output_size, &offset, "%s[%u,%u,%u,%u,%u]",
|
||||
index == first ? "" : ",", cell->cell_index, cell->passages,
|
||||
cell->opened_passages)) {
|
||||
cell->opened_passages, cell->trail_east, cell->trail_south)) {
|
||||
return MAZE32_GAME_RESULT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user