TombsOfHarc/src/Engine.cpp

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