Difference between revisions of "Complete roguelike tutorial using C++ and libtcod - part 8: items and inventory"

From RogueBasin
Jump to navigation Jump to search
(pasted */ Container implementation */)
Line 73: Line 73:
     if ( container ) delete container;
     if ( container ) delete container;
  }
  }
==Container implementation==
Our container will obviously contain a list of actors and a capacity :
Container.hpp :
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);
};
The constructor initializes the size field :
Container::Container(int size) : size(size) {
}
The destructor deletes all actors in the container :
Container::~Container() {
    inventory.clearAndDelete();
}
The add method checks that the container is not full.
bool Container::add(Actor *actor) {
    if ( size > 0 && inventory.size() >= size ) {
        // inventory full
        return false;
    }
Then add the actor : 
    inventory.push(actor);
    return true;
}
The remove method... well you already know :
void Container::remove(Actor *actor) {
    inventory.remove(actor);
}
Ok that was really easy. Let's add a 26 slots inventory to the player. Why 26 ? To be able to affect a letter shortcut to each slot. In the Engine constructor :
player->ai = new PlayerAi();
<span style="color:green">player->container = new Container(26);</span>
actors.push(player);




[[Category:Developing]]
[[Category:Developing]]

Revision as of 15:54, 15 October 2015

Complete roguelike tutorial using C++ and libtcod
-originally written by Jice
Text in this tutorial was released under the Creative Commons Attribution-ShareAlike 3.0 Unported and the GNU Free Documentation License (unversioned, with no invariant sections, front-cover texts, or back-cover texts) on 2015-09-21.


In this article, we will start to add items to the dungeon, in the form of health potions. This will make it possible to kill every monster in the dungeon for the first time, even if the engine won't yet detect the end of game.

libtcod functions used in this article :

TCODConsole::printFrame

TCODSystem::waitForEvent

Actors that can be healed

For the health potion to work, we first need to be able to heal a Destructible. Let's add this. Destructible.hpp :

float heal(float amount);

Destructible.cpp :

float Destructible::heal(float amount) {
   hp += amount;
   if ( hp > maxHp ) {
       amount -= hp-maxHp;
       hp=maxHp;
   }
   return amount;
}

The function returns the amount of health point actually restored.

Pickable actors and containers

Now, we can start to make items that we can pick. Roguelikes often make a strong separation between creatures and items. Creatures have inventory and items can be picked. This can lead to unnecessary complications. For example, a chest is an item, has an inventory and cannot be picked.

Here we will break this separation and simply create actors that can be picked (and used) and actors that can contain other actors (a chest or a creature with an inventory). Let's add those two new features to our almighty Actor class :

Ai *ai; // something self-updating
Pickable *pickable; // something that can be picked and used
Container *container; // something that can contain actors

Include the headers (yet to be written) in main.hpp :

#include "Ai.hpp"
#include "Pickable.hpp"
#include "Container.hpp"
#include "Actor.hpp"

And initialize the features in the Actor constructor :

Actor::Actor(int x, int y, int ch, const char *name,
   const TCODColor &col) :
   x(x),y(y),ch(ch),col(col), name(name),
   blocks(true),attacker(NULL),destructible(NULL),ai(NULL),
   pickable(NULL),container(NULL) {
}   

Ok. So far we didn't bother with what happens when an actor is destroyed (because it never happens in the game since even a dead creature is an Actor). But when we're going to drink a health potion, we expect it to disappear from our inventory, so we're actually doing to delete the Actor object. Let's add a destructor that cleans the features :

Actor.hpp:

Actor(int x, int y, int ch, const char *name, const TCODColor &col);
~Actor();
void update();

Actor.cpp :

Actor::~Actor() {
   if ( attacker ) delete attacker;
   if ( destructible ) delete destructible;
   if ( ai ) delete ai;
   if ( pickable ) delete pickable;
   if ( container ) delete container;
}

Container implementation

Our container will obviously contain a list of actors and a capacity : Container.hpp :

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);
};

The constructor initializes the size field :

Container::Container(int size) : size(size) {
}

The destructor deletes all actors in the container :

Container::~Container() {
   inventory.clearAndDelete();
}

The add method checks that the container is not full.

bool Container::add(Actor *actor) {
   if ( size > 0 && inventory.size() >= size ) {
       // inventory full
       return false;
   }

Then add the actor :

   inventory.push(actor);
   return true;
}

The remove method... well you already know :

void Container::remove(Actor *actor) {
   inventory.remove(actor);
}

Ok that was really easy. Let's add a 26 slots inventory to the player. Why 26 ? To be able to affect a letter shortcut to each slot. In the Engine constructor :

player->ai = new PlayerAi();
player->container = new Container(26);
actors.push(player);