#include "game/modulegame.hpp" #include #include "core/audio/audio.hpp" #include "core/jail/jdraw8.hpp" #include "core/jail/jgame.hpp" #include "core/jail/jinput.hpp" ModuleGame::ModuleGame() { this->gfx_ = Jd8::loadSurface(info::ctx.pepe_activat ? "gfx/frames2.gif" : "gfx/frames.gif"); JG_SetUpdateTicks(10); this->sam_ = std::make_unique(this->gfx_); this->mapa_ = std::make_unique(this->gfx_, this->sam_.get()); this->marcador_ = std::make_unique(this->gfx_, this->sam_.get()); if (info::ctx.num_piramide == 2) { this->bola_ = std::make_unique(this->gfx_, this->sam_.get()); } this->iniciarMomies(); } ModuleGame::~ModuleGame() { Jd8::freeSurface(this->gfx_); } void ModuleGame::onEnter() { // Primera Draw per omplir `screen` amb el contingut del gameplay // abans que el fade-in arranque. Si no, les primeres iteracions del // fade interpolarien cap a una paleta amb pantalla buida. this->draw(); // Audio::playMusic ja és idempotent: si la pista actual coincideix amb la // demanada, no fa res. Per això podem cridar-lo cada onEnter sense // desencadenar restarts indesitjats. const char* music_name = "piramide_1_4_5.ogg"; if (info::ctx.num_piramide == 3) { music_name = "piramide_3.ogg"; } else if (info::ctx.num_piramide == 2) { music_name = "piramide_2.ogg"; } else if (info::ctx.num_piramide == 6) { music_name = "secreta.ogg"; } Audio::get()->playMusic(music_name); // Arranca el fade-in tick-based. El `PaletteFade` avança un pas (de // 32) per cada tick; durant aquesta fase el gameplay no corre, // només Draw+fade. Substituïx la crida bloquejant `JD8_FadeToPal`. fade_.startFadeTo(Jd8::loadPalette(info::ctx.pepe_activat ? "gfx/frames2.gif" : "gfx/frames.gif")); phase_ = Phase::FADING_IN; } void ModuleGame::tick(int delta_ms) { switch (phase_) { case Phase::FADING_IN: // No redibuixem durant el fade: el `screen` ja va ser omplit // per la Draw() d'onEnter. Només el Jd8::flip del caller muta // pixel_data segons la paleta que avança pas a pas. fade_.tick(delta_ms); if (fade_.done()) { phase_ = Phase::PLAYING; } break; case Phase::PLAYING: this->draw(); this->update(); if (this->final_ != 0) { this->applyFinalTransitions(); fade_.startFadeOut(); phase_ = Phase::FADING_OUT; } break; case Phase::FADING_OUT: // No redibuixem: el `screen` té l'últim frame pintat per la // fase Playing (just abans que Update() setegés `final_`). // El vell `JD8_FadeOut` feia exactament això — flips amb // paleta fading però sense tocar el buffer. Redibuixar ací // mostraria l'estat post-Update del sprite (p.ex. el prota // "tornant" davant la porta després d'haver eixit). fade_.tick(delta_ms); if (fade_.done()) { phase_ = Phase::DONE; } break; case Phase::DONE: break; } } auto ModuleGame::nextState() const -> int { if (JG_Quitting()) { return -1; } if (info::ctx.num_habitacio == 1 || info::ctx.num_piramide == 100 || info::ctx.num_piramide == 7) { return 1; } return 0; } void ModuleGame::applyFinalTransitions() const { if (this->final_ == 1) { info::ctx.num_habitacio++; if (info::ctx.num_habitacio == 6) { info::ctx.num_habitacio = 1; info::ctx.num_piramide++; } if (info::ctx.num_piramide == 6 && info::ctx.num_habitacio == 2) { info::ctx.num_piramide++; } } else if (this->final_ == 2) { info::ctx.num_piramide = 100; } } void ModuleGame::draw() { // No crida Jd8::flip — el caller (mini-loop del fiber, o Director a // Phase B.2) ho fa després de cada tick. this->mapa_->draw(); this->marcador_->draw(); this->sam_->draw(); for (auto& m : this->momies_) { m->draw(); } if (this->bola_) { this->bola_->draw(); } } void ModuleGame::update() { if (JG_ShouldUpdate()) { JI_Update(); this->final_ = this->sam_->update(); const auto erased = std::erase_if(this->momies_, [](auto& m) { return m->update(); }); info::ctx.momies -= static_cast(erased); if (this->bola_) { this->bola_->update(); } this->mapa_->update(); if (this->mapa_->novaMomia()) { this->momies_.emplace_back(std::make_unique(this->gfx_, true, 0, 0, this->sam_.get())); info::ctx.momies++; } if (JI_CheatActivated("reviu")) { info::ctx.vida = 5; } if (JI_CheatActivated("alone")) { this->momies_.clear(); info::ctx.momies = 0; } if (JI_CheatActivated("obert")) { for (int i = 0; i < 16; i++) { this->mapa_->tombes[i].costat[0] = true; this->mapa_->tombes[i].costat[1] = true; this->mapa_->tombes[i].costat[2] = true; this->mapa_->tombes[i].costat[3] = true; this->mapa_->comprovaCaixa(i); } } if (JI_KeyPressed(SDL_SCANCODE_ESCAPE)) { JG_QuitSignal(); } } } void ModuleGame::iniciarMomies() { if (info::ctx.num_habitacio == 1) { info::ctx.momies = 1; } else { info::ctx.momies++; } if (info::ctx.num_piramide == 6) { info::ctx.momies = 8; } int x = 20; int y = 170; bool dimonis = info::ctx.num_piramide == 6; for (int i = 0; i < info::ctx.momies; i++) { this->momies_.emplace_back(std::make_unique(this->gfx_, dimonis, x, y, this->sam_.get())); x += 65; if (x == 345) { x = 20; y -= 35; } } }