#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; gameStatus = STARTUP; mouse.cx = 0; mouse.cy = 0; mouse.rbutton_pressed = false; mouse.lbutton_pressed = false; } void Engine::init() { gui = new Gui(context, console); 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); gui->message(TCOD_ColorRGB(150,0,0), "Welcome stranger!\nPrepare to perish in the Tombs of Andrew's Dunegon."); } Engine::~Engine() { actors.clearAndDelete(); delete map; 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(); } } } if (gameStatus == QUIT) { return false; } 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; }