Skip to content
Snippets Groups Projects
movement_logic.cpp 3.66 KiB
Newer Older
#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;
}