240 lines
6.5 KiB
C++
240 lines
6.5 KiB
C++
|
#include "libtcod.hpp"
|
||
|
#include "main.hpp"
|
||
|
|
||
|
Engine::Engine(int screenWidth, int screenHeight) : gameStatus(STARTUP),
|
||
|
player(NULL), map(NULL), fovRadius(10),
|
||
|
screenWidth(screenWidth), screenHeight(screenHeight), level(1) {
|
||
|
TCODConsole::initRoot(80, 50, "libtcod C++ tutorial", false);
|
||
|
gui = new Gui();
|
||
|
}
|
||
|
|
||
|
Engine::~Engine() {
|
||
|
term();
|
||
|
delete gui;
|
||
|
}
|
||
|
|
||
|
void Engine::update() {
|
||
|
if(gameStatus == STARTUP) map->computeFov();
|
||
|
gameStatus=IDLE;
|
||
|
TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS|TCOD_EVENT_MOUSE, &lastKey, &mouse);
|
||
|
if(lastKey.vk == TCODK_ESCAPE) {
|
||
|
save();
|
||
|
load();
|
||
|
}
|
||
|
player->update();
|
||
|
if(gameStatus == NEW_TURN) {
|
||
|
for(Actor **iterator=actors.begin(); iterator != actors.end(); iterator++) {
|
||
|
Actor *actor=*iterator;
|
||
|
if(actor != player) {
|
||
|
actor->update();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Engine::render() {
|
||
|
TCODConsole::root->clear();
|
||
|
// draw the map
|
||
|
map->render();
|
||
|
|
||
|
// draw the actors
|
||
|
for(Actor **iterator=actors.begin();
|
||
|
iterator != actors.end(); iterator++) {
|
||
|
Actor *actor = *iterator;
|
||
|
if(actor != player
|
||
|
&& ((!actor->fovOnly && map->isExplored(actor->x, actor->y))
|
||
|
|| map->isInFov(actor->x, actor->y))) {
|
||
|
actor->render();
|
||
|
}
|
||
|
}
|
||
|
player->render();
|
||
|
gui->render();
|
||
|
}
|
||
|
|
||
|
void Engine::sendToBack(Actor *actor) {
|
||
|
actors.remove(actor);
|
||
|
actors.insertBefore(actor, 0);
|
||
|
}
|
||
|
|
||
|
Actor *Engine::getClosestMonster(int x, int y, float range) const {
|
||
|
Actor *closest = NULL;
|
||
|
float bestDistance=1E6f;
|
||
|
|
||
|
for(Actor **iterator=actors.begin();
|
||
|
iterator != actors.end(); iterator++) {
|
||
|
Actor *actor = *iterator;
|
||
|
if(actor != player && actor->destructible
|
||
|
&& !actor->destructible->isDead()) {
|
||
|
float distance=actor->getDistance(x, y);
|
||
|
if(distance < bestDistance &&
|
||
|
(distance <= range || range == 0.0f)) {
|
||
|
bestDistance = distance;
|
||
|
closest = actor;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return closest;
|
||
|
}
|
||
|
|
||
|
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 NULL;
|
||
|
}
|
||
|
|
||
|
bool Engine::pickATile(int *x, int *y, float maxRange) {
|
||
|
while(!TCODConsole::isWindowClosed()) {
|
||
|
render();
|
||
|
// highlight the possible range
|
||
|
for(int cx=0; cx < map->width; cx++) {
|
||
|
for(int cy=0; cy < map->height; cy++) {
|
||
|
if(map->isInFov(cx, cy)
|
||
|
&& (maxRange == 0 || player->getDistance(cx, cy) <= maxRange)) {
|
||
|
TCODColor col = TCODConsole::root->getCharBackground(cx, cy);
|
||
|
col = col * 1.2f;
|
||
|
TCODConsole::root->setCharBackground(cx, cy, col);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS|TCOD_EVENT_MOUSE, &lastKey, &mouse);
|
||
|
if(map->isInFov(mouse.cx, mouse.cy)
|
||
|
&& (maxRange == 0 || player->getDistance(mouse.cx, mouse.cy) <= maxRange)) {
|
||
|
TCODConsole::root->setCharBackground(mouse.cx, mouse.cy, TCODColor::white);
|
||
|
if(mouse.lbutton_pressed) {
|
||
|
*x = mouse.cx;
|
||
|
*y = mouse.cy;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
if(mouse.rbutton_pressed || lastKey.vk != TCODK_NONE) {
|
||
|
return false;
|
||
|
}
|
||
|
TCODConsole::flush();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void Engine::init() {
|
||
|
player = new Actor(40, 25, '@', "player", TCODColor::white);
|
||
|
player->destructible = new PlayerDestructible(30, 2, "Your cadaver");
|
||
|
player->attacker = new Attacker(5);
|
||
|
player->ai = new PlayerAi();
|
||
|
player->container = new Container(26);
|
||
|
actors.push(player);
|
||
|
|
||
|
stairs = new Actor(0, 0,'>',"stairs",TCODColor::white);
|
||
|
stairs->blocks=false;
|
||
|
stairs->fovOnly=false;
|
||
|
actors.push(stairs);
|
||
|
|
||
|
map = new Map(80, 43);
|
||
|
map->init(true);
|
||
|
|
||
|
gui->message(TCODColor::red, "Welcome stranger!\nPrepare to perish in the Tombs of the Ancient Kings.");
|
||
|
gameStatus=STARTUP;
|
||
|
}
|
||
|
|
||
|
void Engine::term() {
|
||
|
actors.clearAndDelete();
|
||
|
if(map) delete map;
|
||
|
}
|
||
|
|
||
|
void Engine::save() {
|
||
|
if(player->destructible->isDead()) {
|
||
|
TCODSystem::deleteFile("game.sav");
|
||
|
} else {
|
||
|
TCODZip zip;
|
||
|
// Save the map first
|
||
|
zip.putInt(map->width);
|
||
|
zip.putInt(map->height);
|
||
|
map->save(zip);
|
||
|
// Then the player
|
||
|
player->save(zip);
|
||
|
// Then the stairs
|
||
|
stairs->save(zip);
|
||
|
// Then all the other actors
|
||
|
zip.putInt(actors.size() - 2);
|
||
|
for(Actor **it = actors.begin(); it != actors.end(); it++) {
|
||
|
if(*it != player && *it != stairs) {
|
||
|
(*it)->save(zip);
|
||
|
}
|
||
|
}
|
||
|
// Finally the message log
|
||
|
gui->save(zip);
|
||
|
zip.saveToFile("game.sav");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Engine::load() {
|
||
|
engine.gui->menu.clear();
|
||
|
engine.gui->menu.addItem(Menu::NEW_GAME, "New Game");
|
||
|
if(TCODSystem::fileExists("game.sav")) {
|
||
|
engine.gui->menu.addItem(Menu::CONTINUE, "Continue");
|
||
|
}
|
||
|
engine.gui->menu.addItem(Menu::EXIT, "Exit");
|
||
|
Menu::MenuItemCode menuItem = engine.gui->menu.pick();
|
||
|
if(menuItem == Menu::EXIT || menuItem == Menu::NONE) {
|
||
|
// Exit or window closed
|
||
|
exit(0);
|
||
|
} else if(menuItem == Menu::NEW_GAME) {
|
||
|
// new game
|
||
|
engine.term();
|
||
|
engine.init();
|
||
|
} else {
|
||
|
TCODZip zip;
|
||
|
// Continue a saved game
|
||
|
engine.term();
|
||
|
zip.loadFromFile("game.sav");
|
||
|
// Load the map
|
||
|
int width = zip.getInt();
|
||
|
int height = zip.getInt();
|
||
|
map = new Map(width, height);
|
||
|
map->load(zip);
|
||
|
// Then load the player
|
||
|
player = new Actor(0, 0, 0, " ", TCODColor::white);
|
||
|
player->load(zip);
|
||
|
actors.push(player);
|
||
|
// The stairs
|
||
|
stairs=new Actor(0, 0, 0, " ", TCODColor::white);
|
||
|
stairs->load(zip);
|
||
|
actors.push(stairs);
|
||
|
// then all other actors
|
||
|
int nbActors=zip.getInt();
|
||
|
while(nbActors > 0) {
|
||
|
Actor *actor = new Actor(0, 0, 0, " ", TCODColor::white);
|
||
|
actor->load(zip);
|
||
|
actors.push(actor);
|
||
|
nbActors--;
|
||
|
}
|
||
|
// Finally the message log
|
||
|
gui->load(zip);
|
||
|
// to force FOV recomputation
|
||
|
gameStatus = STARTUP;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Engine::nextLevel() {
|
||
|
level++;
|
||
|
gui->message(TCODColor::lightViolet, "You take a moment to rest and recover your strength.");
|
||
|
player->destructible->heal(player->destructible->maxHp/2);
|
||
|
gui->message(TCODColor::red, "After a rare moment of peace, you descend\ndeeper into the heart of the dungeon...");
|
||
|
delete map;
|
||
|
// Delete all actors but player and stairs
|
||
|
for(Actor **it=actors.begin(); it!=actors.end(); it++) {
|
||
|
if(*it != player && *it != stairs) {
|
||
|
delete *it;
|
||
|
it = actors.remove(it);
|
||
|
}
|
||
|
}
|
||
|
// Create a new map
|
||
|
map = new Map(80,43);
|
||
|
map->init(true);
|
||
|
gameStatus=STARTUP;
|
||
|
}
|