diff --git a/Ai.cpp b/Ai.cpp index de76f89..c26e6ae 100644 --- a/Ai.cpp +++ b/Ai.cpp @@ -1,4 +1,5 @@ #include +#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); } -} \ No newline at end of file +} + +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; + } +} diff --git a/Ai.h b/Ai.h index 8aab802..2528c07 100644 --- a/Ai.h +++ b/Ai.h @@ -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; }; \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 57c4b2c..7b35f72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Confuser.cpp b/Confuser.cpp new file mode 100644 index 0000000..ea292c2 --- /dev/null +++ b/Confuser.cpp @@ -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 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); +} \ No newline at end of file diff --git a/Confuser.h b/Confuser.h new file mode 100644 index 0000000..2a54dc6 --- /dev/null +++ b/Confuser.h @@ -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); +}; \ No newline at end of file diff --git a/Engine.cpp b/Engine.cpp index 2cc4585..d8c65f0 100644 --- a/Engine.cpp +++ b/Engine.cpp @@ -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; } \ No newline at end of file diff --git a/Engine.h b/Engine.h index 5cceedd..4e5f509 100644 --- a/Engine.h +++ b/Engine.h @@ -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; }; diff --git a/Map.cpp b/Map.cpp index 810e7dc..17c8069 100644 --- a/Map.cpp +++ b/Map.cpp @@ -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); + } } \ No newline at end of file diff --git a/Pickable.cpp b/Pickable.cpp index 1fddca0..dd96170 100644 --- a/Pickable.cpp +++ b/Pickable.cpp @@ -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()); + } } \ No newline at end of file diff --git a/Pickable.h b/Pickable.h index 5aaba4d..855cf83 100644 --- a/Pickable.h +++ b/Pickable.h @@ -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() {}; };