adg5/Ai.cpp
2025-04-20 17:57:56 +10:00

134 lines
3.2 KiB
C++

#include <SDL3/SDL.h>
#include "Ai.h"
#include "Actor.h"
#include "Engine.h"
#include "Map.h"
#include "Destructible.h"
#include "Attacker.h"
#include "Gui.h"
void PlayerAi::update(Actor* owner) {
SDL_Event event;
int dx = 0, dy = 0;
if (owner->destructible && owner->destructible->isDead()) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_EVENT_QUIT:
engine->gameStatus = Engine::QUIT;
break;
default:
break;
}
}
return;
}
while (SDL_PollEvent(&event)) {
engine->context->convert_event_coordinates(event);
switch (event.type) {
case SDL_EVENT_MOUSE_MOTION:
engine->mouse.cx = event.motion.x;
engine->mouse.cy = event.motion.y;
break;
case SDL_EVENT_KEY_DOWN:
switch (event.key.key) {
case SDLK_UP:
dy = -1;
break;
case SDLK_DOWN:
dy = 1;
break;
case SDLK_LEFT:
dx = -1;
break;
case SDLK_RIGHT:
dx = 1;
break;
default:
break;
}
break;
case SDL_EVENT_QUIT:
engine->gameStatus = Engine::QUIT;
break;
default:
break;
}
if (dx != 0 || dy != 0) {
engine->gameStatus = Engine::NEW_TURN;
if (moveOrAttack(owner, owner->x + dx, owner->y + dy)) {
engine->map->computeFov();
}
}
}
}
bool PlayerAi::moveOrAttack(Actor* owner, int targetx, int targety) {
if (engine->map->isWall(targetx, targety)) return false;
// look for living actors to attack
for (Actor** iterator = engine->actors.begin();
iterator != engine->actors.end(); iterator++) {
Actor* actor = *iterator;
if (actor->destructible && !actor->destructible->isDead()
&& actor->x == targetx && actor->y == targety) {
owner->attacker->attack(owner, actor);
return false;
}
}
for (Actor** iterator = engine->actors.begin();
iterator != engine->actors.end(); iterator++) {
Actor* actor = *iterator;
if (actor->destructible && actor->destructible->isDead()
&& actor->x == targetx && actor->y == targety) {
engine->gui->message(TCOD_ColorRGB(150,150,150), "There's a %s here\n", actor->name.c_str());
}
}
owner->x = targetx;
owner->y = targety;
return true;
}
static const int TRACKING_TURNS = 3;
void MonsterAi::update(Actor* owner) {
if (owner->destructible && owner->destructible->isDead()) {
return;
}
if (engine->map->isInFov(owner->x, owner->y)) {
// we can see the player. move towards him
moveCount = TRACKING_TURNS;
}
else {
moveCount--;
}
if (moveCount > 0) {
// we can see the player. move towards him
moveOrAttack(owner, engine->player->x, engine->player->y);
}
}
void MonsterAi::moveOrAttack(Actor* owner, int targetx, int targety) {
int dx = targetx - owner->x;
int dy = targety - owner->y;
int stepdx = (dx > 0 ? 1 : -1);
int stepdy = (dy > 0 ? 1 : -1);
float distance = sqrtf((float)dx * (float)dx + (float)dy * (float)dy);
if (distance >= 2) {
dx = (int)(round(dx / distance));
dy = (int)(round(dy / distance));
if (engine->map->canWalk(owner->x + dx, owner->y + dy)) {
owner->x += dx;
owner->y += dy;
}
else if (engine->map->canWalk(owner->x + stepdx, owner->y)) {
owner->x += stepdx;
}
else if (engine->map->canWalk(owner->x, owner->y + stepdy)) {
owner->y += stepdy;
}
}
else if (owner->attacker) {
owner->attacker->attack(owner, engine->player);
}
}