#include #include "libtcod.hpp" #include "Actor.h" #include "Map.h" #include "Engine.h" #include "Destructible.h" #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; this->console = console; this->screenWidth = screenWidth; this->screenHeight = screenHeight; gui = nullptr; map = nullptr; player = nullptr; fovRadius = 10; computeFov = true; mouse.cx = 0; mouse.cy = 0; mouse.rbutton_pressed = false; mouse.lbutton_pressed = false; } void Engine::init() { player = new Actor(40, 25, "@", "player", TCOD_ColorRGB(255, 255, 255)); 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); map->init(true); gui->message(TCOD_ColorRGB(150,0,0), "Welcome stranger!\nPrepare to perish in the Tombs of Andrew's Dunegon."); gameStatus = STARTUP; } void Engine::term() { actors.clearAndDelete(); if (map) delete map; gui->clear(); } Engine::~Engine() { term(); delete gui; } bool Engine::update() { if (gameStatus == STARTUP) map->computeFov(); gameStatus = IDLE; player->update(); if (gameStatus == NEW_TURN) { for (Actor** iterator = actors.begin(); iterator != actors.end(); iterator++) { Actor* actor = *iterator; if (actor != player) { actor->update(); } } } else if (gameStatus == QUIT) { return false; } else if (gameStatus == PAUSE) { save(); load(); } return true; } void Engine::render(bool present) { console->clear(); // draw the map map->render(*console); // draw the actors for (Actor** iterator = actors.begin(); iterator != actors.end(); iterator++) { Actor* actor = *iterator; if (actor != player && map->isInFov(actor->x, actor->y)) { actor->render(*console); } } player->render(*console); gui->render(); if (present) context->present(*console); } 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; } bool Engine::pickATile(int* x, int* y, float maxRange) { while (true) { render(false); // 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)) { TCOD_ColorRGBA col = console->at(cx, cy).bg; 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; } } } SDL_Event event; while (SDL_PollEvent(&event)) { engine->context->convert_event_coordinates(event); switch (event.type) { case SDL_EVENT_MOUSE_MOTION: engine->mouse.cx = event.motion.x; engine->mouse.cy = event.motion.y; break; case SDL_EVENT_MOUSE_BUTTON_DOWN: 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; } } if (map->isInFov(mouse.cx, mouse.cy) && (maxRange == 0 || player->getDistance(mouse.cx, mouse.cy) <= maxRange)) { console->at(mouse.cx, mouse.cy).bg = TCOD_ColorRGBA(100, 100, 100, 255); if (mouse.lbutton_pressed) { *x = mouse.cx; *y = mouse.cy; return true; } } if (mouse.rbutton_pressed) { return false; } context->present(*console); } } 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; } 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 all the other actors zip.putInt(actors.size() - 1); for (Actor** it = actors.begin(); it != actors.end(); it++) { if (*it != player) { (*it)->save(zip); } } // finally the message log gui->save(zip); zip.saveToFile("game.sav"); } } void Engine::load() { gui = new Gui(context, console); gui->menu.clear(); 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(context, console); if (menuItem == Menu::EXIT || menuItem == Menu::NONE) { // Exit or window closed exit(0); } else if (menuItem == Menu::NEW_GAME) { // New game term(); init(); } else if (menuItem == Menu::CONTINUE) { // Continue TCODZip zip; 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 the player player = new Actor(0, 0, "?", "", TCOD_ColorRGB(255, 255, 255)); player->load(zip); actors.push(player); // then all other actors int nbActors = zip.getInt(); while (nbActors > 0) { Actor* actor = new Actor(0, 0, "?", "", TCOD_ColorRGB(255, 255, 255)); actor->load(zip); actors.push(actor); nbActors--; } // finally the message log gui->load(zip); gameStatus = STARTUP; } }