#include "game/modulegame.hpp" #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 = new Prota(this->gfx); this->mapa = new Mapa(this->gfx, this->sam); this->marcador = new Marcador(this->gfx, this->sam); if (info::ctx.num_piramide == 2) { this->bola = new Bola(this->gfx, this->sam); } else { this->bola = nullptr; } this->momies = nullptr; this->iniciarMomies(); } ModuleGame::~ModuleGame() { if (this->bola != nullptr) delete this->bola; if (this->momies != nullptr) { this->momies->clear(); delete this->momies; } delete this->marcador; delete this->mapa; delete this->sam; 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 = info::ctx.num_piramide == 3 ? "piramide_3.ogg" : info::ctx.num_piramide == 2 ? "piramide_2.ogg" : info::ctx.num_piramide == 6 ? "secreta.ogg" : "piramide_1_4_5.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::FadingIn; } void ModuleGame::tick(int delta_ms) { switch (phase_) { case Phase::FadingIn: // 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::FadingOut; } break; case Phase::FadingOut: // 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; } } int ModuleGame::nextState() const { 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() { 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(); if (this->momies != nullptr) this->momies->draw(); if (this->bola != nullptr) this->bola->draw(); } void ModuleGame::Update() { if (JG_ShouldUpdate()) { JI_Update(); this->final_ = this->sam->update(); if (this->momies != nullptr && this->momies->update()) { Momia* seguent = this->momies->next; delete this->momies; this->momies = seguent; info::ctx.momies--; } if (this->bola != nullptr) this->bola->update(); this->mapa->update(); if (this->mapa->novaMomia()) { if (this->momies != nullptr) { this->momies->insertar(new Momia(this->gfx, true, 0, 0, this->sam)); info::ctx.momies++; } else { this->momies = new Momia(this->gfx, true, 0, 0, this->sam); info::ctx.momies++; } } if (JI_CheatActivated("reviu")) info::ctx.vida = 5; if (JI_CheatActivated("alone")) { if (this->momies != nullptr) { this->momies->clear(); delete this->momies; this->momies = nullptr; 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++) { if (this->momies == nullptr) { this->momies = new Momia(this->gfx, dimonis, x, y, this->sam); } else { this->momies->insertar(new Momia(this->gfx, dimonis, x, y, this->sam)); } x += 65; if (x == 345) { x = 20; y -= 35; } } }