#include <stdio.h> #include "distance_map.h" #include "movement_logic.h" #include "util.h" // Erratic tunneling monsters don't care about anything but the border static position_t next_monster_move_tunnel_erratic(dungeon_t *d, character_t *c) { position_t next_move; next_move.x = c->pos.x; next_move.y = c->pos.y; while(next_move.x == c->pos.x && next_move.y == c->pos.y) { next_move.x = randrange(max(1, c->pos.x - 1), min(MAP_WIDTH-2, c->pos.x + 1)); next_move.y = randrange(max(1, c->pos.y - 1), min(MAP_HEIGHT-2, c->pos.y + 1)); } return next_move; } // Erratic non-tunneling monsters have to pick a random open space static position_t next_monster_move_erratic(dungeon_t *d, character_t *c) { position_t next_move; next_move.x = c->pos.x; next_move.y = c->pos.y; while(next_move.x == c->pos.x && next_move.y == c->pos.y && !d->hardness[next_move.y][next_move.x]) { next_move.x = randrange(max(1, c->pos.x - 1), min(MAP_WIDTH-2, c->pos.x + 1)); next_move.y = randrange(max(1, c->pos.y - 1), min(MAP_HEIGHT-2, c->pos.y + 1)); } return next_move; } // Smart tunneling monsters move toward the last known position of the player following // the tunneling distance map. Smart non-tunneling monsters do the same but use the non-tunneling // distance map static position_t next_monster_move_smart(dungeon_t *d, character_t *c) { int i, j; uint32_t dist_to_target[MAP_HEIGHT][MAP_WIDTH]; dijkstra_from_pos(d, dist_to_target, (has_characteristic(c, TUNNEL)) ? 255 : 1, c->monster->last_seen.x, c->monster->last_seen.y); position_t best = {c->pos.x, c->pos.y}; int best_dist = dist_to_target[c->pos.y][c->pos.x]; for (i = max(0, c->pos.y-1); i < min(MAP_WIDTH, c->pos.y+2); i++) { for (j = max(0, c->pos.x-1); j < min(MAP_WIDTH, c->pos.x+2); j++) { if (dist_to_target[i][j] < best_dist || (dist_to_target[i][j] == best_dist && i == c->pos.y)) { best_dist = dist_to_target[i][j]; best.x = j; best.y = i; } } } return best; } // Dumb tunneling monsters move directly toward the player position if they know it, and // move erratically otherwise // Dumb non-tunneling monsters do the same, but can't tunnel static position_t next_monster_move_dumb(dungeon_t *d, character_t *c) { if (c->monster->last_seen.x == c->pos.x && c->monster->last_seen.y == c->pos.y) { if (has_characteristic(c, TUNNEL)) { return next_monster_move_tunnel_erratic(d, c); } else { return next_monster_move_erratic(d, c); } } else { position_t next_move; next_move.x = c->pos.x + sign(c->monster->last_seen.x - c->pos.x); next_move.y = c->pos.y + sign(c->monster->last_seen.y - c->pos.y); return next_move; } } position_t monster_move(dungeon_t *d, character_t *c) { // Handle telepathic monsters // If the monster is telepathic, update the position of the PC // Otherwise if it can currently see the PC then update the position // Otherwise if it is not smart then forget the pc position if (has_characteristic(c, TELE)) { c->monster->last_seen = d->player_pos; } else if (d->pc_sight[c->pos.y][c->pos.x]) { c->monster->last_seen = d->player_pos; } else if (!(has_characteristic(c, SMART))) { c->monster->last_seen = c->pos; } // Handle erratic monsters // If the monster is erratic, then 50% chance to move randomly // Movement based on whether it can tunnel or not if (has_characteristic(c, ERRATIC) && randchance(0.5)) { if (has_characteristic(c, TUNNEL)) { return next_monster_move_tunnel_erratic(d, c); } else { return next_monster_move_erratic(d, c); } } // Handle smart/dumb monsters if (has_characteristic(c, SMART)) { return next_monster_move_smart(d, c); } else { return next_monster_move_dumb(d, c); } return c->pos; }