#include #include "Gui.h" #include "Engine.h" #include "Actor.h" #include "Map.h" #include "Destructible.h" static const int PANEL_HEIGHT = 7; static const int BAR_WIDTH = 20; static const int MSG_X = BAR_WIDTH + 2; static const int MSG_HEIGHT = PANEL_HEIGHT - 1; Gui::Gui(tcod::Context *ctx, tcod::Console *root) { con = ctx->new_console(engine->screenWidth, PANEL_HEIGHT); this->root = root; } void Gui::clear() { log.clearAndDelete(); } Gui::~Gui() { delete con.release(); clear(); } void Gui::render() { // clear the GUI console con.clear(); renderBar(1, 1, BAR_WIDTH, "HP", engine->player->destructible->hp, engine->player->destructible->maxHp, TCOD_ColorRGB(255,100,100), TCOD_ColorRGB(100, 0, 0)); // draw the message log int y = 1; float colorCoef = 0.4f; for (Message** it = log.begin(); it != log.end(); it++) { Message* message = *it; tcod::print(con, { MSG_X, y }, message->text, TCOD_ColorRGB(message->col.r * colorCoef, message->col.g * colorCoef, message->col.b * colorCoef), std::nullopt); y++; if (colorCoef < 1.0f) { colorCoef += 0.3f; } } renderMouseLook(); tcod::blit(*root, con, { 0, engine->screenHeight - PANEL_HEIGHT }, { 0, 0, engine->screenWidth, PANEL_HEIGHT }); } void Gui::renderBar(int x, int y, int width, std::string name, float value, float maxValue, const TCOD_ColorRGB& barColor, const TCOD_ColorRGB& backColor) { tcod::draw_rect(con, { x, y, width, 1 }, ' ', std::nullopt, backColor); int barWidth = (int)(value / maxValue * width); if (barWidth > 0) { // draw the bar tcod::draw_rect(con, { x, y, barWidth, 1 }, ' ', std::nullopt, barColor); } tcod::print(con, { x + width / 2, y }, name + " : " + std::to_string((int)value) + "/" + std::to_string((int)maxValue), TCOD_ColorRGB(255, 255, 255), std::nullopt, TCOD_CENTER); } Gui::Message::Message(std::string text, const TCOD_ColorRGB& col) : text(text), col(col) { } Gui::Message::~Message() { } void Gui::message(const TCOD_ColorRGB& col, const char* text, ...) { // build the text va_list ap; char buf[128]; va_start(ap, text); vsprintf(buf, text, ap); va_end(ap); char* lineBegin = buf; char* lineEnd; if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0'; do { // make room for the new message if (log.size() == MSG_HEIGHT) { Message* toRemove = log.get(0); log.remove(toRemove); delete toRemove; } lineEnd = strchr(lineBegin, '\n'); if (lineEnd) { *lineEnd = '\0'; } Message* msg = new Message(lineBegin, col); log.push(msg); // go to next line lineBegin = lineEnd + 1; } while (lineEnd); } void Gui::renderMouseLook() { if (!engine->map->isInFov(engine->mouse.cx, engine->mouse.cy)) { // if mouse is out of fov, nothing to render return; } char buf[128] = ""; bool first = true; for (Actor** it = engine->actors.begin(); it != engine->actors.end(); it++) { Actor* actor = *it; // find actors under the mouse cursor if (actor->x == engine->mouse.cx && actor->y == engine->mouse.cy) { if (!first) { strcat(buf, ", "); } else { first = false; } strcat(buf, actor->name.c_str()); } } tcod::print(con, { 1, 0 }, buf, TCOD_ColorRGB(200, 200, 200), std::nullopt); } void Gui::save(TCODZip& zip) { zip.putInt(log.size()); for (Message** it = log.begin(); it != log.end(); it++) { zip.putString((*it)->text.c_str()); zip.putInt((*it)->col.r); zip.putInt((*it)->col.g); zip.putInt((*it)->col.b); } } void Gui::load(TCODZip& zip) { int nbMessages = zip.getInt(); while (nbMessages > 0) { const char* text = zip.getString(); TCOD_ColorRGB col(zip.getInt(), zip.getInt(), zip.getInt()); message(col, text); nbMessages--; } } Menu::~Menu() { clear(); } void Menu::clear() { items.clearAndDelete(); } void Menu::addItem(MenuItemCode code, std::string label) { MenuItem* item = new MenuItem(); item->code = code; item->label = label; items.push(item); } Menu::MenuItemCode Menu::pick(tcod::Context *ctx, tcod::Console *con) { static TCODImage img("menu_background1.png"); int selectedItem = 0; while (true) { img.blit2x(*con, 0, 0); int currentItem = 0; for (MenuItem** it = items.begin(); it != items.end(); it++) { if (currentItem == selectedItem) { tcod::print(*con, { 10, 10 + currentItem * 3 }, (*it)->label,TCOD_ColorRGB(255, 100, 255), std::nullopt); } else { tcod::print(*con, { 10, 10 + currentItem * 3 }, (*it)->label, TCOD_ColorRGB(200, 200, 200), std::nullopt); } currentItem++; } ctx->present(*con); // check key presses SDL_Event event; while (SDL_PollEvent(&event)) { ctx->convert_event_coordinates(event); switch (event.type) { case SDL_EVENT_KEY_DOWN: { if (event.key.key == SDLK_UP) { selectedItem--; if (selectedItem < 0) { selectedItem = items.size() - 1; } } else if (event.key.key == SDLK_DOWN) { selectedItem = (selectedItem + 1) % items.size(); } else if (event.key.key == SDLK_RETURN) { return items.get(selectedItem)->code; } else if (event.key.key == SDLK_ESCAPE) { return NONE; } } break; case SDL_EVENT_QUIT: engine->gameStatus = Engine::QUIT; return NONE; } } } }