Spells pt3

This commit is contained in:
Andrew Pamment 2025-04-21 13:04:27 +10:00
parent 2686764cb3
commit 35dcee85a0
10 changed files with 141 additions and 10 deletions

52
Ai.cpp
View File

@ -1,4 +1,5 @@
#include <SDL3/SDL.h>
#include "libtcod.hpp"
#include "Ai.h"
#include "Actor.h"
#include "Engine.h"
@ -68,6 +69,7 @@ void PlayerAi::update(Actor* owner) {
}
}
}
void PlayerAi::handleActionKey(Actor* owner, int sdlkey) {
switch (sdlkey) {
case SDLK_G: // pickup item
@ -92,15 +94,29 @@ void PlayerAi::handleActionKey(Actor* owner, int sdlkey) {
if (!found) {
engine->gui->message(TCOD_ColorRGB(200,200,200), "There's nothing here that you can pick up.");
}
engine->gameStatus = Engine::NEW_TURN;
if (engine->gameStatus != Engine::QUIT)
engine->gameStatus = Engine::NEW_TURN;
}
break;
case SDLK_I:
{
Actor* actor = choseFromInventory(owner);
if (actor) {
actor->pickable->use(actor, owner);
engine->gameStatus = Engine::NEW_TURN;
if (engine->gameStatus != Engine::QUIT)
engine->gameStatus = Engine::NEW_TURN;
}
}
break;
case SDLK_D: // drop item
{
Actor* actor = choseFromInventory(owner);
if (actor) {
actor->pickable->drop(actor, owner);
if (engine->gameStatus != Engine::QUIT)
engine->gameStatus = Engine::NEW_TURN;
}
}
break;
}
}
@ -156,7 +172,6 @@ Actor* PlayerAi::choseFromInventory(Actor* owner) {
engine->context->present(*engine->console);
SDL_Event event;
while (1) {
printf("HERE\n");
SDL_WaitEvent(&event);
if (event.type == SDL_EVENT_KEY_UP) {
if (event.key.key >= SDLK_A && event.key.key < SDLK_A + owner->container->inventory.size()) {
@ -213,4 +228,33 @@ void MonsterAi::moveOrAttack(Actor* owner, int targetx, int targety) {
else if (owner->attacker) {
owner->attacker->attack(owner, engine->player);
}
}
}
ConfusedMonsterAi::ConfusedMonsterAi(int nbTurns, Ai* oldAi)
: nbTurns(nbTurns), oldAi(oldAi) {
}
void ConfusedMonsterAi::update(Actor* owner) {
TCODRandom* rng = TCODRandom::getInstance();
int dx = rng->getInt(-1, 1);
int dy = rng->getInt(-1, 1);
if (dx != 0 || dy != 0) {
int destx = owner->x + dx;
int desty = owner->y + dy;
if (engine->map->canWalk(destx, desty)) {
owner->x = destx;
owner->y = desty;
}
else {
Actor* actor = engine->getActor(destx, desty);
if (actor) {
owner->attacker->attack(owner, actor);
}
}
}
nbTurns--;
if (nbTurns == 0) {
owner->ai = oldAi;
delete this;
}
}

9
Ai.h
View File

@ -25,4 +25,13 @@ public:
protected:
int moveCount;
void moveOrAttack(Actor* owner, int targetx, int targety);
};
class ConfusedMonsterAi : public Ai {
public:
ConfusedMonsterAi(int nbTurns, Ai* oldAi);
void update(Actor* owner);
protected:
int nbTurns;
Ai* oldAi;
};

View File

@ -14,7 +14,7 @@ project ("ADG5")
find_package(libtcod CONFIG REQUIRED)
# Add source to this project's executable.
add_executable (ADG5 "ADG5.cpp" "ADG5.h" "Actor.cpp" "Actor.h" "Map.h" "Map.cpp" "Engine.h" "Engine.cpp" "Destructible.h" "Destructible.cpp" "Attacker.h" "Attacker.cpp" "Ai.h" "Ai.cpp" "Gui.h" "Gui.cpp" "Container.h" "Container.cpp" "Pickable.h" "Pickable.cpp" "Healer.h" "Healer.cpp" "Lightningbolt.h" "Lightningbolt.cpp" "Fireball.h" "Fireball.cpp")
add_executable (ADG5 "ADG5.cpp" "ADG5.h" "Actor.cpp" "Actor.h" "Map.h" "Map.cpp" "Engine.h" "Engine.cpp" "Destructible.h" "Destructible.cpp" "Attacker.h" "Attacker.cpp" "Ai.h" "Ai.cpp" "Gui.h" "Gui.cpp" "Container.h" "Container.cpp" "Pickable.h" "Pickable.cpp" "Healer.h" "Healer.cpp" "Lightningbolt.h" "Lightningbolt.cpp" "Fireball.h" "Fireball.cpp" "Confuser.h" "Confuser.cpp")
target_link_libraries(ADG5
PRIVATE

28
Confuser.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "libtcod.hpp"
#include "Confuser.h"
#include "Engine.h"
#include "Gui.h"
#include "Ai.h"
#include "Actor.h"
Confuser::Confuser(int nbTurns, float range)
: nbTurns(nbTurns), range(range) {
}
bool Confuser::use(Actor* owner, Actor* wearer) {
engine->gui->message(TCOD_ColorRGB(0, 255, 255), "Left-click an enemy to confuse it,\nor right-click to cancel.");
int x, y;
if (!engine->pickATile(&x, &y, range)) {
return false;
}
Actor* actor = engine->getActor(x, y);
if (!actor) {
return false;
}
// confuse the monster for <nbTurns> turns
Ai* confusedAi = new ConfusedMonsterAi(nbTurns, actor->ai);
actor->ai = confusedAi;
engine->gui->message(TCOD_ColorRGB(100, 255, 100), "The eyes of the %s look vacant,\nas he starts to stumble around!",
actor->name.c_str());
return Pickable::use(owner, wearer);
}

13
Confuser.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include "Pickable.h"
class Actor;
class Confuser : public Pickable {
public:
int nbTurns;
float range;
Confuser(int nbTurns, float range);
bool use(Actor* owner, Actor* wearer);
};

View File

@ -107,7 +107,7 @@ Actor* Engine::getClosestMonster(int x, int y, float range) const {
}
bool Engine::pickATile(int* x, int* y, float maxRange) {
while (context->get_sdl_window() != nullptr) {
while (true) {
render(false);
// highlight the possible range
@ -117,9 +117,9 @@ bool Engine::pickATile(int* x, int* y, float maxRange) {
&& (maxRange == 0 || player->getDistance(cx, cy) <= maxRange)) {
TCOD_ColorRGBA col = console->at(cx, cy).bg;
col.r = col.r * 1.2f;
col.g = col.g * 1.2f;
col.b = col.b * 1.2f;
col.r = (int)((float)col.r * 1.2f);
col.g = (int)((float)col.g * 1.2f);
col.b = (int)((float)col.b * 1.2f);
console->at(cx, cy).bg = col;
}
@ -137,6 +137,9 @@ bool Engine::pickATile(int* x, int* y, float maxRange) {
engine->mouse.lbutton_pressed = event.button.button == SDL_BUTTON_LEFT;
engine->mouse.rbutton_pressed = event.button.button == SDL_BUTTON_RIGHT;
break;
case SDL_EVENT_QUIT:
engine->gameStatus = Engine::QUIT;
return false;
}
}
@ -154,5 +157,16 @@ bool Engine::pickATile(int* x, int* y, float maxRange) {
}
context->present(*console);
}
return false;
}
Actor* Engine::getActor(int x, int y) const {
for (Actor** iterator = actors.begin();
iterator != actors.end(); iterator++) {
Actor* actor = *iterator;
if (actor->x == x && actor->y == y && actor->destructible
&& !actor->destructible->isDead()) {
return actor;
}
}
return nullptr;
}

View File

@ -34,6 +34,7 @@ public:
void sendToBack(Actor* actor);
Actor* getClosestMonster(int x, int y, float range) const;
bool pickATile(int* x, int* y, float maxRange = 0.0f);
Actor* getActor(int x, int y) const;
private:
bool computeFov;
};

View File

@ -8,6 +8,7 @@
#include "Healer.h"
#include "Lightningbolt.h"
#include "Fireball.h"
#include "Confuser.h"
static const int ROOM_MAX_SIZE = 12;
static const int ROOM_MIN_SIZE = 6;
@ -219,4 +220,12 @@ void Map::addItem(int x, int y) {
scrollOfFireball->pickable = new Fireball(3, 12);
engine->actors.push(scrollOfFireball);
}
else {
// create a scroll of confusion
Actor* scrollOfConfusion = new Actor(x, y, "#", "scroll of confusion",
TCOD_ColorRGB(255, 100, 100));
scrollOfConfusion->blocks = false;
scrollOfConfusion->pickable = new Confuser(10, 8);
engine->actors.push(scrollOfConfusion);
}
}

View File

@ -2,6 +2,7 @@
#include "Actor.h"
#include "Engine.h"
#include "Container.h"
#include "Gui.h"
bool Pickable::pick(Actor* owner, Actor* wearer) {
if (wearer->container && wearer->container->add(owner)) {
@ -18,4 +19,15 @@ bool Pickable::use(Actor* owner, Actor* wearer) {
return true;
}
return false;
}
void Pickable::drop(Actor* owner, Actor* wearer) {
if (wearer->container) {
wearer->container->remove(owner);
engine->actors.push(owner);
owner->x = wearer->x;
owner->y = wearer->y;
engine->gui->message(TCOD_ColorRGB(200,200,200), "%s drops a %s.",
wearer->name.c_str(), owner->name.c_str());
}
}

View File

@ -6,5 +6,6 @@ class Pickable {
public:
bool pick(Actor* owner, Actor* wearer);
virtual bool use(Actor* owner, Actor* wearer);
void drop(Actor* owner, Actor* wearer);
virtual ~Pickable() {};
};