Inventory and Health Potions
This commit is contained in:
parent
cefeacdae9
commit
abd3eb9a9b
13
Actor.cpp
13
Actor.cpp
@ -6,10 +6,13 @@
|
||||
#include "Ai.h"
|
||||
#include "Destructible.h"
|
||||
#include "Attacker.h"
|
||||
#include "Container.h"
|
||||
#include "Pickable.h"
|
||||
|
||||
Actor::Actor(int x, int y, std::string_view ch, std::string name, const TCOD_ColorRGB& col) :
|
||||
x(x), y(y), ch(ch), col(col), name(name),
|
||||
blocks(true),attacker(nullptr), destructible(nullptr), ai(nullptr) {
|
||||
blocks(true), attacker(nullptr), destructible(nullptr), ai(nullptr), pickable(nullptr), container(nullptr) {
|
||||
|
||||
}
|
||||
|
||||
void Actor::render(TCOD_Console& cons) const {
|
||||
@ -21,3 +24,11 @@ void Actor::update() {
|
||||
ai->update(this);
|
||||
}
|
||||
}
|
||||
|
||||
Actor::~Actor() {
|
||||
if (attacker) delete attacker;
|
||||
if (destructible) delete destructible;
|
||||
if (ai) delete ai;
|
||||
if (pickable) delete pickable;
|
||||
if (container) delete container;
|
||||
}
|
6
Actor.h
6
Actor.h
@ -5,9 +5,12 @@
|
||||
class Attacker;
|
||||
class Destructible;
|
||||
class Ai;
|
||||
class Pickable;
|
||||
class Container;
|
||||
|
||||
class Actor {
|
||||
public:
|
||||
|
||||
int x, y; // position on map
|
||||
std::string_view ch; // ascii code
|
||||
TCOD_ColorRGB col; // color
|
||||
@ -16,8 +19,11 @@ public:
|
||||
Attacker* attacker;
|
||||
Destructible* destructible;
|
||||
Ai* ai;
|
||||
Pickable* pickable; // something that can be picked and used
|
||||
Container* container; // something that can contain actors
|
||||
|
||||
Actor(int x, int y, std::string_view ch, std::string name, const TCOD_ColorRGB& col);
|
||||
~Actor();
|
||||
void render(TCOD_Console& cons) const;
|
||||
void update();
|
||||
};
|
88
Ai.cpp
88
Ai.cpp
@ -6,6 +6,8 @@
|
||||
#include "Destructible.h"
|
||||
#include "Attacker.h"
|
||||
#include "Gui.h"
|
||||
#include "Pickable.h"
|
||||
#include "Container.h"
|
||||
|
||||
void PlayerAi::update(Actor* owner) {
|
||||
SDL_Event event;
|
||||
@ -30,7 +32,7 @@ void PlayerAi::update(Actor* owner) {
|
||||
engine->mouse.cx = event.motion.x;
|
||||
engine->mouse.cy = event.motion.y;
|
||||
break;
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
switch (event.key.key) {
|
||||
case SDLK_UP:
|
||||
dy = -1;
|
||||
@ -45,6 +47,9 @@ void PlayerAi::update(Actor* owner) {
|
||||
dx = 1;
|
||||
break;
|
||||
default:
|
||||
if (event.key.key >= SDLK_A && event.key.key <= SDLK_Z) {
|
||||
handleActionKey(owner, event.key.key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -63,6 +68,42 @@ void PlayerAi::update(Actor* owner) {
|
||||
}
|
||||
}
|
||||
}
|
||||
void PlayerAi::handleActionKey(Actor* owner, int sdlkey) {
|
||||
switch (sdlkey) {
|
||||
case SDLK_G: // pickup item
|
||||
{
|
||||
bool found = false;
|
||||
for (Actor** iterator = engine->actors.begin();
|
||||
iterator != engine->actors.end(); iterator++) {
|
||||
Actor* actor = *iterator;
|
||||
if (actor->pickable && actor->x == owner->x && actor->y == owner->y) {
|
||||
if (actor->pickable->pick(actor, owner)) {
|
||||
found = true;
|
||||
engine->gui->message(TCOD_ColorRGB(200,200,200), "You pick up the %s.",
|
||||
actor->name.c_str());
|
||||
break;
|
||||
}
|
||||
else if (!found) {
|
||||
found = true;
|
||||
engine->gui->message(TCOD_ColorRGB(255,0,0), "Your inventory is full.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
engine->gui->message(TCOD_ColorRGB(200,200,200), "There's nothing here that you can pick up.");
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerAi::moveOrAttack(Actor* owner, int targetx, int targety) {
|
||||
if (engine->map->isWall(targetx, targety)) return false;
|
||||
@ -79,9 +120,11 @@ bool PlayerAi::moveOrAttack(Actor* owner, int targetx, int targety) {
|
||||
for (Actor** iterator = engine->actors.begin();
|
||||
iterator != engine->actors.end(); iterator++) {
|
||||
Actor* actor = *iterator;
|
||||
if (actor->destructible && actor->destructible->isDead()
|
||||
bool corpseOrItem = (actor->destructible && actor->destructible->isDead())
|
||||
|| actor->pickable;
|
||||
if (corpseOrItem
|
||||
&& actor->x == targetx && actor->y == targety) {
|
||||
engine->gui->message(TCOD_ColorRGB(150,150,150), "There's a %s here\n", actor->name.c_str());
|
||||
engine->gui->message(TCOD_ColorRGB(200,200,200), "There's a %s here.", actor->name.c_str());
|
||||
}
|
||||
}
|
||||
owner->x = targetx;
|
||||
@ -89,6 +132,45 @@ bool PlayerAi::moveOrAttack(Actor* owner, int targetx, int targety) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Actor* PlayerAi::choseFromInventory(Actor* owner) {
|
||||
static const int INVENTORY_WIDTH = 50;
|
||||
static const int INVENTORY_HEIGHT = 28;
|
||||
|
||||
tcod::Console con = engine->context->new_console(INVENTORY_WIDTH, INVENTORY_HEIGHT);
|
||||
|
||||
TCOD_ColorRGB fg(200, 180, 50);
|
||||
TCOD_ColorRGB bg(0, 0, 0);
|
||||
tcod::print_frame(con, { 0, 0, INVENTORY_WIDTH, INVENTORY_HEIGHT }, "Inventory", &fg, &bg);
|
||||
|
||||
char shortcut = 'a';
|
||||
int y = 1;
|
||||
for (Actor** it = owner->container->inventory.begin();
|
||||
it != owner->container->inventory.end(); it++) {
|
||||
Actor* actor = *it;
|
||||
tcod::print(con, { 1, y }, std::string("(") + shortcut + ") " + actor->name, TCOD_ColorRGB(255, 255, 255), std::nullopt, TCOD_LEFT);
|
||||
y++;
|
||||
shortcut++;
|
||||
}
|
||||
tcod::blit(*engine->console, con, { engine->screenWidth / 2 - INVENTORY_WIDTH / 2, engine->screenHeight / 2 - INVENTORY_HEIGHT / 2 }, { 0, 0, INVENTORY_WIDTH, INVENTORY_HEIGHT });
|
||||
|
||||
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()) {
|
||||
return owner->container->inventory.get(event.key.key - SDLK_A);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
if (event.type == SDL_EVENT_QUIT) {
|
||||
engine->gameStatus = Engine::QUIT;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const int TRACKING_TURNS = 3;
|
||||
|
||||
void MonsterAi::update(Actor* owner) {
|
||||
|
3
Ai.h
3
Ai.h
@ -5,6 +5,7 @@ class Actor;
|
||||
class Ai {
|
||||
public:
|
||||
virtual void update(Actor* owner) = 0;
|
||||
virtual ~Ai() {};
|
||||
};
|
||||
|
||||
class PlayerAi : public Ai {
|
||||
@ -13,6 +14,8 @@ public:
|
||||
|
||||
protected:
|
||||
bool moveOrAttack(Actor* owner, int targetx, int targety);
|
||||
void handleActionKey(Actor* owner, int sdlkey);
|
||||
Actor* choseFromInventory(Actor* owner);
|
||||
};
|
||||
|
||||
class MonsterAi : public Ai {
|
||||
|
@ -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")
|
||||
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")
|
||||
|
||||
target_link_libraries(ADG5
|
||||
PRIVATE
|
||||
|
21
Container.cpp
Normal file
21
Container.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "Container.h"
|
||||
|
||||
Container::Container(int size) : size(size) {
|
||||
}
|
||||
|
||||
Container::~Container() {
|
||||
inventory.clearAndDelete();
|
||||
}
|
||||
|
||||
bool Container::add(Actor* actor) {
|
||||
if (size > 0 && inventory.size() >= size) {
|
||||
// inventory full
|
||||
return false;
|
||||
}
|
||||
inventory.push(actor);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Container::remove(Actor* actor) {
|
||||
inventory.remove(actor);
|
||||
}
|
15
Container.h
Normal file
15
Container.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "libtcod.hpp"
|
||||
|
||||
class Actor;
|
||||
|
||||
class Container {
|
||||
public:
|
||||
int size; // maximum number of actors. 0=unlimited
|
||||
TCODList<Actor*> inventory;
|
||||
|
||||
Container(int size);
|
||||
~Container();
|
||||
bool add(Actor* actor);
|
||||
void remove(Actor* actor);
|
||||
};
|
@ -20,6 +20,14 @@ float Destructible::takeDamage(Actor* owner, float damage) {
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
float Destructible::heal(float amount) {
|
||||
hp += amount;
|
||||
if (hp > maxHp) {
|
||||
amount -= hp - maxHp;
|
||||
hp = maxHp;
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
void Destructible::die(Actor* owner) {
|
||||
// transform the actor into a corpse!
|
||||
|
@ -11,11 +11,12 @@ public:
|
||||
std::string corpseName; // the actor's name once dead/destroyed
|
||||
|
||||
Destructible(float maxHp, float defense, std::string corpseName);
|
||||
virtual ~Destructible() {};
|
||||
inline bool isDead() { return hp <= 0; }
|
||||
float takeDamage(Actor* owner, float damage);
|
||||
virtual void die(Actor* owner);
|
||||
|
||||
|
||||
float heal(float amount);
|
||||
};
|
||||
|
||||
class MonsterDestructible : public Destructible {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Attacker.h"
|
||||
#include "Ai.h"
|
||||
#include "Gui.h"
|
||||
#include "Container.h"
|
||||
|
||||
Engine::Engine(int screenWidth, int screenHeight, tcod::Context *context, tcod::Console *console) {
|
||||
this->context = context;
|
||||
@ -19,6 +20,8 @@ Engine::Engine(int screenWidth, int screenHeight, tcod::Context *context, tcod::
|
||||
fovRadius = 10;
|
||||
computeFov = true;
|
||||
gameStatus = STARTUP;
|
||||
mouse.cx = 0;
|
||||
mouse.cy = 0;
|
||||
}
|
||||
|
||||
void Engine::init() {
|
||||
@ -27,10 +30,11 @@ void Engine::init() {
|
||||
player->destructible = new PlayerDestructible(30, 2, "player corpse");
|
||||
player->attacker = new Attacker(5);
|
||||
player->ai = new PlayerAi();
|
||||
player->container = new Container(26);
|
||||
actors.push(player);
|
||||
map = new Map(80, 45);
|
||||
gui->message(TCOD_ColorRGB(150,0,0),
|
||||
"Welcome stranger!\nPrepare to perish in the Tombs Andrew's Dunegon Game.");
|
||||
"Welcome stranger!\nPrepare to perish in the Tombs of Andrew's Dunegon.");
|
||||
}
|
||||
|
||||
Engine::~Engine() {
|
||||
|
2
Gui.cpp
2
Gui.cpp
@ -52,7 +52,7 @@ void Gui::renderBar(int x, int y, int width, std::string name,
|
||||
tcod::draw_rect(con, { x, y, barWidth, 1 }, ' ', std::nullopt, barColor);
|
||||
}
|
||||
|
||||
tcod::print(con, { x + width / 2, y }, name + " : " + std::to_string((int)value) + "/" + std::to_string((int)maxValue), TCOD_ColorRGB(255, 255, 255), std::nullopt);
|
||||
tcod::print(con, { x + width / 2, y }, name + " : " + std::to_string((int)value) + "/" + std::to_string((int)maxValue), TCOD_ColorRGB(255, 255, 255), std::nullopt, TCOD_CENTER);
|
||||
}
|
||||
|
||||
Gui::Message::Message(std::string text, const TCOD_ColorRGB& col) :
|
||||
|
16
Healer.cpp
Normal file
16
Healer.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "Healer.h"
|
||||
#include "Actor.h"
|
||||
#include "Destructible.h"
|
||||
|
||||
Healer::Healer(float amount) : amount(amount) {
|
||||
}
|
||||
|
||||
bool Healer::use(Actor* owner, Actor* wearer) {
|
||||
if (wearer->destructible) {
|
||||
float amountHealed = wearer->destructible->heal(amount);
|
||||
if (amountHealed > 0) {
|
||||
return Pickable::use(owner, wearer);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
12
Healer.h
Normal file
12
Healer.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pickable.h"
|
||||
|
||||
class Healer : public Pickable {
|
||||
public:
|
||||
float amount; // how many hp
|
||||
|
||||
Healer(float amount);
|
||||
bool use(Actor* owner, Actor* wearer);
|
||||
~Healer() {};
|
||||
};
|
20
Map.cpp
20
Map.cpp
@ -5,11 +5,12 @@
|
||||
#include "Destructible.h"
|
||||
#include "Attacker.h"
|
||||
#include "Ai.h"
|
||||
|
||||
#include "Healer.h"
|
||||
|
||||
static const int ROOM_MAX_SIZE = 12;
|
||||
static const int ROOM_MIN_SIZE = 6;
|
||||
static const int MAX_ROOM_MONSTERS = 3;
|
||||
static const int MAX_ROOM_ITEMS = 2;
|
||||
|
||||
class BspListener : public ITCODBspCallback {
|
||||
private:
|
||||
@ -154,6 +155,15 @@ void Map::createRoom(bool first, int x1, int y1, int x2, int y2) {
|
||||
}
|
||||
nbMonsters--;
|
||||
}
|
||||
int nbItems = rng->getInt(0, MAX_ROOM_ITEMS);
|
||||
while (nbItems > 0) {
|
||||
int x = rng->getInt(x1, x2);
|
||||
int y = rng->getInt(y1, y2);
|
||||
if (canWalk(x, y)) {
|
||||
addItem(x, y);
|
||||
}
|
||||
nbItems--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,3 +188,11 @@ void Map::addMonster(int x, int y) {
|
||||
engine->actors.push(troll);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::addItem(int x, int y) {
|
||||
Actor* healthPotion = new Actor(x, y, "!", "health potion",
|
||||
TCOD_ColorRGB(128, 0, 128));
|
||||
healthPotion->blocks = false;
|
||||
healthPotion->pickable = new Healer(4);
|
||||
engine->actors.push(healthPotion);
|
||||
}
|
1
Map.h
1
Map.h
@ -17,6 +17,7 @@ public:
|
||||
bool isExplored(int x, int y) const;
|
||||
void computeFov();
|
||||
void render(TCOD_Console& cons) const;
|
||||
void addItem(int x, int y);
|
||||
protected:
|
||||
Tile* tiles;
|
||||
friend class BspListener;
|
||||
|
21
Pickable.cpp
Normal file
21
Pickable.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "Pickable.h"
|
||||
#include "Actor.h"
|
||||
#include "Engine.h"
|
||||
#include "Container.h"
|
||||
|
||||
bool Pickable::pick(Actor* owner, Actor* wearer) {
|
||||
if (wearer->container && wearer->container->add(owner)) {
|
||||
engine->actors.remove(owner);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Pickable::use(Actor* owner, Actor* wearer) {
|
||||
if (wearer->container) {
|
||||
wearer->container->remove(owner);
|
||||
delete owner;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
10
Pickable.h
Normal file
10
Pickable.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
class Actor;
|
||||
|
||||
class Pickable {
|
||||
public:
|
||||
bool pick(Actor* owner, Actor* wearer);
|
||||
virtual bool use(Actor* owner, Actor* wearer);
|
||||
virtual ~Pickable() {};
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user