156 lines
5.6 KiB
C++
156 lines
5.6 KiB
C++
#include "game/gameplay/scoreboard.hpp"
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "core/locale/locale.hpp"
|
|
#include "core/rendering/screen.hpp"
|
|
#include "core/rendering/surface.hpp"
|
|
#include "core/rendering/text.hpp"
|
|
#include "core/resources/resource_cache.hpp"
|
|
#include "game/options.hpp"
|
|
#include "utils/defines.hpp"
|
|
|
|
// Constructor
|
|
Scoreboard::Scoreboard(std::shared_ptr<Data> data)
|
|
: data_(std::move(data)) {
|
|
const float SURFACE_WIDTH = Options::game.width;
|
|
constexpr float SURFACE_HEIGHT = 24.0F; // 3 líneas de 8px
|
|
|
|
surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT);
|
|
surface_dest_ = {.x = 0, .y = Options::game.height - SURFACE_HEIGHT, .w = SURFACE_WIDTH, .h = SURFACE_HEIGHT};
|
|
}
|
|
|
|
// Pinta el objeto en pantalla
|
|
void Scoreboard::render() {
|
|
surface_->render(nullptr, &surface_dest_);
|
|
}
|
|
|
|
// Actualiza las variables del objeto
|
|
void Scoreboard::update(float delta_time) {
|
|
updateItemsColor(delta_time);
|
|
fillTexture();
|
|
|
|
if (!is_paused_) {
|
|
clock_ = getTime();
|
|
}
|
|
}
|
|
|
|
// Obtiene el tiempo transcurrido de partida
|
|
auto Scoreboard::getTime() -> Scoreboard::ClockData {
|
|
const Uint32 TIME_ELAPSED = SDL_GetTicks() - data_->ini_clock - paused_time_elapsed_;
|
|
|
|
ClockData time;
|
|
time.hours = TIME_ELAPSED / 3600000;
|
|
time.minutes = TIME_ELAPSED / 60000;
|
|
time.seconds = TIME_ELAPSED / 1000;
|
|
time.separator = (TIME_ELAPSED % 1000 <= 500) ? ":" : " ";
|
|
|
|
return time;
|
|
}
|
|
|
|
// Pone el marcador en modo pausa
|
|
void Scoreboard::setPaused(bool value) {
|
|
if (is_paused_ == value) { return; }
|
|
is_paused_ = value;
|
|
|
|
if (is_paused_) {
|
|
paused_time_ = SDL_GetTicks();
|
|
} else {
|
|
paused_time_elapsed_ += SDL_GetTicks() - paused_time_;
|
|
}
|
|
}
|
|
|
|
// Actualiza el color de la cantidad de items recogidos
|
|
void Scoreboard::updateItemsColor(float delta_time) {
|
|
if (!data_->jail_is_open) { return; }
|
|
|
|
items_color_timer_ += delta_time;
|
|
if (items_color_timer_ >= ITEMS_COLOR_BLINK_DURATION * 2.0F) {
|
|
items_color_timer_ = 0.0F;
|
|
}
|
|
items_color_ = (items_color_timer_ < ITEMS_COLOR_BLINK_DURATION) ? VALUE_COLOR : 6;
|
|
}
|
|
|
|
// Devuelve la cantidad de minutos de juego transcurridos
|
|
auto Scoreboard::getMinutes() -> int {
|
|
return getTime().minutes;
|
|
}
|
|
|
|
// Dibuja los elementos del marcador en la surface
|
|
void Scoreboard::fillTexture() {
|
|
auto previous_renderer = Screen::get()->getRendererSurface();
|
|
Screen::get()->setRendererSurface(surface_);
|
|
|
|
surface_->clear(0);
|
|
|
|
auto text = Resource::Cache::get()->getText("8bithud");
|
|
const int CANVAS_W = static_cast<int>(Options::game.width);
|
|
const std::string SEP = " - ";
|
|
const int MONO_W = 7; // Ancho fijo por carácter monoespaciado (dígitos + separador)
|
|
|
|
// Valores formateados
|
|
const std::string LIVES_STR = std::to_string(data_->lives);
|
|
const std::string ITEMS_STR = std::to_string(data_->items);
|
|
const std::string TIME_STR = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
|
|
|
|
// --- Línea 1: vides X - objectes X - temps MM:SS (centrada) ---
|
|
const std::string LIVES_LABEL = Locale::get()->get("scoreboard.lives");
|
|
const std::string ITEMS_LABEL = Locale::get()->get("scoreboard.items");
|
|
const std::string TIME_LABEL = Locale::get()->get("scoreboard.time");
|
|
|
|
// Ancho total: labels proporcionales + valores monoespaciados
|
|
const int LINE1_W = text->length(LIVES_LABEL) + text->lengthMono(LIVES_STR, MONO_W) + text->length(SEP) + text->length(ITEMS_LABEL) + text->lengthMono(ITEMS_STR, MONO_W) + text->length(SEP) + text->length(TIME_LABEL) + text->lengthMono(TIME_STR, MONO_W);
|
|
|
|
int x = (CANVAS_W - LINE1_W) / 2;
|
|
text->writeColored(x, LINE1_Y, LIVES_LABEL, LABEL_COLOR);
|
|
x += text->length(LIVES_LABEL);
|
|
text->writeColoredMono(x, LINE1_Y, LIVES_STR, VALUE_COLOR, MONO_W);
|
|
x += text->lengthMono(LIVES_STR, MONO_W);
|
|
text->writeColored(x, LINE1_Y, SEP, LABEL_COLOR);
|
|
x += text->length(SEP);
|
|
text->writeColored(x, LINE1_Y, ITEMS_LABEL, LABEL_COLOR);
|
|
x += text->length(ITEMS_LABEL);
|
|
text->writeColoredMono(x, LINE1_Y, ITEMS_STR, items_color_, MONO_W);
|
|
x += text->lengthMono(ITEMS_STR, MONO_W);
|
|
text->writeColored(x, LINE1_Y, SEP, LABEL_COLOR);
|
|
x += text->length(SEP);
|
|
text->writeColored(x, LINE1_Y, TIME_LABEL, LABEL_COLOR);
|
|
x += text->length(TIME_LABEL);
|
|
text->writeColoredMono(x, LINE1_Y, TIME_STR, VALUE_COLOR, MONO_W);
|
|
|
|
// --- Línea 2: indicadores activos (centrada) ---
|
|
std::vector<std::string> indicators;
|
|
if (data_->music) {
|
|
indicators.push_back(Locale::get()->get("scoreboard.music_on"));
|
|
}
|
|
if (Options::cheats.infinite_lives == Options::Cheat::State::ENABLED) {
|
|
indicators.push_back(Locale::get()->get("scoreboard.cheat_infinite_lives"));
|
|
}
|
|
if (Options::cheats.invincible == Options::Cheat::State::ENABLED) {
|
|
indicators.push_back(Locale::get()->get("scoreboard.cheat_invincibility"));
|
|
}
|
|
|
|
if (!indicators.empty()) {
|
|
int line2_w = 0;
|
|
for (size_t i = 0; i < indicators.size(); ++i) {
|
|
if (i > 0) { line2_w += text->length(SEP); }
|
|
line2_w += text->length(indicators[i]);
|
|
}
|
|
x = (CANVAS_W - line2_w) / 2;
|
|
for (size_t i = 0; i < indicators.size(); ++i) {
|
|
if (i > 0) {
|
|
text->writeColored(x, LINE2_Y, SEP, LABEL_COLOR);
|
|
x += text->length(SEP);
|
|
}
|
|
text->writeColored(x, LINE2_Y, indicators[i], LABEL_COLOR);
|
|
x += text->length(indicators[i]);
|
|
}
|
|
}
|
|
|
|
Screen::get()->setRendererSurface(previous_renderer);
|
|
}
|