8 Commits

Author SHA1 Message Date
b1f9e57f36 fix: color de fonde dels sliders de 050505 a 000000 2026-04-18 15:20:25 +02:00
f7875baa2d refactor: fase 6 — Rule of 5 a Mapa i ModuleGame (no-copiables, no-movibles)
- Mapa té un JD8_Surface fondo propi que s'allibera al destructor: una
  còpia accidental provocaria double-free. Ara els 4 copy/move ops estan
  = delete.
- ModuleGame ja era no-copiable implícitament per tindre unique_ptr
  members, però els = delete expliciten la intenció i protegeixen
  davant refactors futurs que afegeixquen tipus copiables.

Fi de la modernització RAII per fases (1–6).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:03:51 +02:00
c6e37af7d1 refactor: fase 5 — singletons a std::unique_ptr (elimina new/delete manual)
5 singletons afectats: Audio, Screen, Director, Resource::Cache, Resource::List.

- static T* instance → static std::unique_ptr<T> instance
- init(): new T() adoptat immediatament per unique_ptr (ownership RAII)
- destroy(): instance.reset() (sense delete manual)
- get(): retorna instance.get()
- Destructors moguts a public perquè std::default_delete hi pugui accedir
  (ctors privats + copy/move deleted → encapsulació efectiva mantinguda)

Ordre de destrucció preservat: SDL_AppQuit segueix cridant destroy() en
l'ordre invers a init() — la RAII automàtica no s'activa fins al final
del programa (LIFO de variables static).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:02:01 +02:00
5e57034a38 refactor: fase 4 — llista enllaçada de Momia a std::vector<unique_ptr>
Eliminada completament la recursivitat per next-pointer:
- Momia::next, clear(), insertar() desapareixen
- update()/draw() no recursen: operen només sobre la instància pròpia
- ModuleGame::momies: Momia* (head de llista) → std::vector<std::unique_ptr<Momia>>
  - Destructor simplificat (vector s'autodestrueix)
  - Draw: range-for sobre el vector
  - Update: std::erase_if + decrement sincronitzat de info::ctx.momies
  - Cheat "alone": momies.clear()
  - iniciarMomies i nova_momia: emplace_back(std::make_unique<Momia>(...))

Zero new/delete manuals al cicle de vida de les momies.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:56:05 +02:00
2a8fbbb095 refactor: fase 3 — Text::bitmap_ a std::vector<Uint8>
- bitmap_: Uint8* (owning, free'd al destructor) → std::vector<Uint8>
- loadBitmap copia des del buffer de LoadGif i fa free(pixels) de
  l'intermedi (gif.h usa malloc internament)
- ~Text() eliminat: regla 0 aplicada (vector es destrueix sol)
- Les 4 comprovacions !bitmap_ → bitmap_.empty()

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:44:07 +02:00
53e93ef697 refactor: fase 2 — elimina malloc/free a jdraw8 i paletes d'escenes
- JD8_Init/Quit: new[]/delete[] per a screen, main_palette, pixel_data
- JD8_NewSurface/FreeSurface: new Uint8[64000]{}/delete[]
- JD8_LoadPalette: uniforme — sempre retorna `new Color[256]`, copiant del
  LoadPalette extern al path no-cached (l'intermedi raw es frees amb free()
  perquè gif.h el malloca)
- JD8_SetScreenPalette: delete[] la paleta reemplaçada
- slides/secreta/menu/banner/mort scenes: std::free/std::malloc → delete[]/new Color[256]

Ownership uniforme: tot el cicle de vida de surface/palette usa new[]/delete[].

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:42:31 +02:00
e7aa2463b4 refactor: fase 1 — cleanup mecànic de baix risc (NULL→nullptr, typedef→using, explicit, enum class local)
- jdraw8.hpp: typedef → using (JD8_Surface, JD8_Palette)
- jdraw8.cpp: NULL → nullptr, C-casts → static_cast/reinterpret_cast, anon enum FadeType → enum class
- momia.cpp: NULL → nullptr
- bola/mapa/marcador/momia/engendro: explicit als constructors

Zero canvis de lògica ni ownership. Primera fase de la modernització RAII.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:37:48 +02:00
27f8b0ae36 cppcheck 2026-04-18 13:22:13 +02:00
43 changed files with 235 additions and 292 deletions

View File

@@ -0,0 +1 @@
{"sessionId":"7b0c9c32-3dd4-48a3-ba06-c2303dc08243","pid":123890,"acquiredAt":1776510185734}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -24,19 +24,16 @@
#include "game/options.hpp" // Para Options::audio
// Singleton
Audio* Audio::instance = nullptr;
std::unique_ptr<Audio> Audio::instance;
// Inicializa la instancia única del singleton
void Audio::init() { Audio::instance = new Audio(); }
void Audio::init() { Audio::instance = std::unique_ptr<Audio>(new Audio()); }
// Libera la instancia
void Audio::destroy() {
delete Audio::instance;
Audio::instance = nullptr;
}
void Audio::destroy() { Audio::instance.reset(); }
// Obtiene la instancia
auto Audio::get() -> Audio* { return Audio::instance; }
auto Audio::get() -> Audio* { return Audio::instance.get(); }
// Constructor
Audio::Audio() { initSDLAudio(); }

View File

@@ -1,6 +1,7 @@
#pragma once
#include <cstdint> // Para int8_t, uint8_t
#include <memory> // Para std::unique_ptr
#include <string> // Para string
#include <utility> // Para move
@@ -35,6 +36,7 @@ class Audio {
static void init(); // Inicializa el objeto Audio
static void destroy(); // Libera el objeto Audio
static auto get() -> Audio*; // Obtiene el puntero al objeto Audio
~Audio(); // Destructor (públic per a std::unique_ptr)
Audio(const Audio&) = delete; // Evitar copia
auto operator=(const Audio&) -> Audio& = delete; // Evitar asignación
@@ -101,11 +103,10 @@ class Audio {
// --- Métodos ---
Audio(); // Constructor privado
~Audio(); // Destructor privado
void initSDLAudio(); // Inicializa SDL Audio
// --- Variables miembro ---
static Audio* instance; // Instancia única de Audio
static std::unique_ptr<Audio> instance; // Instancia única de Audio
Music music_; // Estado de la música
bool enabled_{true}; // Estado general del audio

View File

@@ -265,13 +265,13 @@ inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) {
auto* music = new JA_Music_t();
music->ogg_data.assign(buffer, buffer + length);
int error = 0;
int vorbis_error = 0;
music->vorbis = stb_vorbis_open_memory(music->ogg_data.data(),
static_cast<int>(length),
&error,
&vorbis_error,
nullptr);
if (!music->vorbis) {
std::cout << "JA_LoadMusic: stb_vorbis_open_memory failed (error " << error << ")" << '\n';
std::cout << "JA_LoadMusic: stb_vorbis_open_memory failed (error " << vorbis_error << ")" << '\n';
delete music;
return nullptr;
}

View File

@@ -19,20 +19,23 @@
#pragma GCC diagnostic pop
#endif
JD8_Surface screen = NULL;
JD8_Palette main_palette = NULL;
Uint32* pixel_data = NULL;
JD8_Surface screen = nullptr;
JD8_Palette main_palette = nullptr;
Uint32* pixel_data = nullptr;
void JD8_Init() {
screen = (JD8_Surface)calloc(1, 64000);
main_palette = (JD8_Palette)calloc(1, 768);
pixel_data = (Uint32*)calloc(1, 320 * 200 * 4);
screen = new Uint8[64000]{};
main_palette = new Color[256]{};
pixel_data = new Uint32[320 * 200]{};
}
void JD8_Quit() {
if (screen != NULL) free(screen);
if (main_palette != NULL) free(main_palette);
if (pixel_data != NULL) free(pixel_data);
delete[] screen;
delete[] main_palette;
delete[] pixel_data;
screen = nullptr;
main_palette = nullptr;
pixel_data = nullptr;
}
void JD8_ClearScreen(Uint8 color) {
@@ -40,9 +43,7 @@ void JD8_ClearScreen(Uint8 color) {
}
JD8_Surface JD8_NewSurface() {
JD8_Surface surface = (JD8_Surface)malloc(64000);
memset(surface, 0, 64000);
return surface;
return new Uint8[64000]{};
}
// Helper intern: deriva el basename d'una ruta per a buscar al Cache.
@@ -71,7 +72,7 @@ JD8_Surface JD8_LoadSurface(const char* file) {
auto buffer = ResourceHelper::loadFile(file);
unsigned short w, h;
Uint8* pixels = LoadGif(buffer.data(), &w, &h);
if (pixels == NULL) {
if (pixels == nullptr) {
printf("Unable to load bitmap: %s\n", SDL_GetError());
exit(1);
}
@@ -82,27 +83,31 @@ JD8_Surface JD8_LoadSurface(const char* file) {
}
JD8_Palette JD8_LoadPalette(const char* file) {
// Sempre retorna un buffer de 256 colors reservat amb `new Color[256]`
// — el caller és responsable d'alliberar-lo amb `delete[]` (o lliurar-ne
// l'ownership a `JD8_SetScreenPalette`).
JD8_Palette palette = new Color[256];
if (Resource::Cache::get() != nullptr) {
try {
const auto& cached = Resource::Cache::get()->getPaletteBytes(jd8_basename(file));
// Reservem un buffer 768 bytes (256 * RGB) que el caller ha
// d'alliberar amb free() — mateixa convenció que el LoadPalette
// original (retornava un malloc).
JD8_Palette palette = (JD8_Palette)malloc(768);
memcpy(palette, cached.data(), 768);
return palette;
} catch (const std::exception&) {
// No està al cache.
// No està al cache — fallback a lectura + LoadPalette.
}
}
auto buffer = ResourceHelper::loadFile(file);
return (JD8_Palette)LoadPalette(buffer.data());
Uint8* raw = LoadPalette(buffer.data()); // external malloc
memcpy(palette, raw, 768);
free(raw);
return palette;
}
void JD8_SetScreenPalette(JD8_Palette palette) {
if (main_palette == palette) return;
if (main_palette != NULL) free(main_palette);
delete[] main_palette;
main_palette = palette;
}
@@ -218,7 +223,7 @@ Uint32* JD8_GetFramebuffer() {
}
void JD8_FreeSurface(JD8_Surface surface) {
free(surface);
delete[] surface;
}
Uint8 JD8_GetPixel(JD8_Surface surface, int x, int y) {
@@ -240,26 +245,26 @@ void JD8_SetPaletteColor(Uint8 index, Uint8 r, Uint8 g, Uint8 b) {
// el caller decideix quan fer Flip.
namespace {
enum FadeType {
FADE_NONE = 0,
FADE_OUT,
FADE_TO_PAL,
enum class FadeType {
None = 0,
Out,
ToPal,
};
constexpr int FADE_STEPS = 32;
FadeType fade_type = FADE_NONE;
FadeType fade_type = FadeType::None;
Color fade_target[256];
int fade_step = 0;
void apply_fade_step() {
if (fade_type == FADE_OUT) {
if (fade_type == FadeType::Out) {
for (int i = 0; i < 256; i++) {
main_palette[i].r = main_palette[i].r >= 8 ? main_palette[i].r - 8 : 0;
main_palette[i].g = main_palette[i].g >= 8 ? main_palette[i].g - 8 : 0;
main_palette[i].b = main_palette[i].b >= 8 ? main_palette[i].b - 8 : 0;
}
} else if (fade_type == FADE_TO_PAL) {
} else if (fade_type == FadeType::ToPal) {
for (int i = 0; i < 256; i++) {
main_palette[i].r = main_palette[i].r <= int(fade_target[i].r) - 8
? main_palette[i].r + 8
@@ -277,28 +282,28 @@ namespace {
} // namespace
void JD8_FadeStartOut() {
fade_type = FADE_OUT;
fade_type = FadeType::Out;
fade_step = 0;
}
void JD8_FadeStartToPal(JD8_Palette pal) {
fade_type = FADE_TO_PAL;
fade_type = FadeType::ToPal;
memcpy(fade_target, pal, sizeof(Color) * 256);
fade_step = 0;
}
bool JD8_FadeIsActive() {
return fade_type != FADE_NONE;
return fade_type != FadeType::None;
}
bool JD8_FadeTickStep() {
if (fade_type == FADE_NONE) return true;
if (fade_type == FadeType::None) return true;
apply_fade_step();
fade_step++;
if (fade_step >= FADE_STEPS) {
fade_type = FADE_NONE;
fade_type = FadeType::None;
return true;
}
return false;

View File

@@ -7,8 +7,8 @@ struct Color {
Uint8 b;
};
typedef Uint8* JD8_Surface;
typedef Color* JD8_Palette;
using JD8_Surface = Uint8*;
using JD8_Palette = Color*;
void JD8_Init();

View File

@@ -82,9 +82,7 @@ void file_setconfigfolder(const char* foldername) {
config_folder = std::string(homedir) + "/.config/" + foldername;
#endif
if (!config_folder.empty()) {
std::filesystem::create_directories(config_folder);
}
std::filesystem::create_directories(config_folder);
}
const char* file_getconfigfolder() {

View File

@@ -55,19 +55,18 @@ namespace {
} // namespace
#endif // __EMSCRIPTEN__
Screen* Screen::instance_ = nullptr;
std::unique_ptr<Screen> Screen::instance_;
void Screen::init() {
instance_ = new Screen();
instance_ = std::unique_ptr<Screen>(new Screen());
}
void Screen::destroy() {
delete instance_;
instance_ = nullptr;
instance_.reset();
}
auto Screen::get() -> Screen* {
return instance_;
return instance_.get();
}
Screen::Screen() {

View File

@@ -13,6 +13,8 @@ class Screen {
static void destroy();
static auto get() -> Screen*;
~Screen(); // públic per a std::unique_ptr
// Presentació — rep el buffer ARGB de 320x200 de JD8
void present(Uint32* pixel_data);
@@ -62,7 +64,6 @@ class Screen {
private:
Screen();
~Screen();
void adjustWindowSize();
void calculateMaxZoom();
@@ -70,7 +71,7 @@ class Screen {
void applyFallbackPresentation(); // Logical presentation + scale mode per al path SDL_Renderer
void ensureFallbackInternalTexture(); // Recrea internal_texture_sdl_ si cal (fallback path)
static Screen* instance_;
static std::unique_ptr<Screen> instance_;
SDL_Window* window_{nullptr};
SDL_Renderer* renderer_{nullptr};

View File

@@ -19,10 +19,6 @@ Text::Text(const char* fnt_file, const char* gif_file) {
loadFont(fnt_file);
}
Text::~Text() {
if (bitmap_) free(bitmap_);
}
// --- UTF-8 ---
auto Text::nextCodepoint(const char*& ptr) -> uint32_t {
@@ -80,27 +76,27 @@ void Text::loadFont(const char* fnt_file) {
// Elimina comentaris inline
auto comment_pos = line.find('#');
if (comment_pos != std::string::npos) {
line = line.substr(0, comment_pos);
line.resize(comment_pos);
}
// Parseja directives
if (line.find("box_width") == 0) {
if (line.starts_with("box_width")) {
sscanf(line.c_str(), "box_width %d", &box_width_);
continue;
}
if (line.find("box_height") == 0) {
if (line.starts_with("box_height")) {
sscanf(line.c_str(), "box_height %d", &box_height_);
continue;
}
if (line.find("columns") == 0) {
if (line.starts_with("columns")) {
sscanf(line.c_str(), "columns %d", &columns_);
continue;
}
if (line.find("cell_spacing") == 0) {
if (line.starts_with("cell_spacing")) {
sscanf(line.c_str(), "cell_spacing %d", &cell_spacing_);
continue;
}
if (line.find("row_spacing") == 0) {
if (line.starts_with("row_spacing")) {
sscanf(line.c_str(), "row_spacing %d", &row_spacing_);
continue;
}
@@ -146,7 +142,8 @@ void Text::loadBitmap(const char* gif_file) {
bitmap_width_ = w;
bitmap_height_ = h;
bitmap_ = pixels;
bitmap_.assign(pixels, pixels + (static_cast<size_t>(w) * h));
free(pixels); // LoadGif usa malloc internament
std::cout << "Text: bitmap loaded " << w << "x" << h << '\n';
}
@@ -154,7 +151,7 @@ void Text::loadBitmap(const char* gif_file) {
// --- Renderitzat ---
void Text::draw(Uint32* pixel_data, int x, int y, const char* text, Uint32 color) const {
if (!bitmap_ || !pixel_data) return;
if (bitmap_.empty() || !pixel_data) return;
const char* ptr = text;
int cursor_x = x;
@@ -207,7 +204,7 @@ void Text::drawCentered(Uint32* pixel_data, int y, const char* text, Uint32 colo
}
void Text::drawClipped(Uint32* pixel_data, int x, int y, const char* text, Uint32 color, int clip_x_min, int clip_x_max, int clip_y_min, int clip_y_max) const {
if (!bitmap_ || !pixel_data) return;
if (bitmap_.empty() || !pixel_data) return;
// Descart ràpid si el glifo sencer cau fora verticalment
if (y + box_height_ <= clip_y_min || y >= clip_y_max) return;
@@ -262,7 +259,7 @@ void Text::drawClipped(Uint32* pixel_data, int x, int y, const char* text, Uint3
}
void Text::drawMono(Uint32* pixel_data, int x, int y, const char* text, Uint32 color, int cell_w) const {
if (!bitmap_ || !pixel_data) return;
if (bitmap_.empty() || !pixel_data) return;
const char* ptr = text;
int cursor_x = x;
@@ -308,7 +305,7 @@ void Text::drawMono(Uint32* pixel_data, int x, int y, const char* text, Uint32 c
}
void Text::drawMonoDigits(Uint32* pixel_data, int x, int y, const char* text, Uint32 color, int digit_cell_w) const {
if (!bitmap_ || !pixel_data) return;
if (bitmap_.empty() || !pixel_data) return;
const char* ptr = text;
int cursor_x = x;

View File

@@ -5,11 +5,11 @@
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>
class Text {
public:
Text(const char* fnt_file, const char* gif_file);
~Text();
// Pinta texto sobre un buffer ARGB de 320x200
void draw(Uint32* pixel_data, int x, int y, const char* text, Uint32 color) const;
@@ -46,7 +46,7 @@ class Text {
int cell_spacing_{0};
int row_spacing_{0};
Uint8* bitmap_{nullptr}; // píxels 8-bit del GIF de la font
std::vector<Uint8> bitmap_; // píxels 8-bit del GIF de la font
int bitmap_width_{0};
int bitmap_height_{0};

View File

@@ -20,14 +20,11 @@ extern unsigned char* LoadPalette(unsigned char* data);
namespace Resource {
Cache* Cache::instance = nullptr;
std::unique_ptr<Cache> Cache::instance;
void Cache::init() { instance = new Cache(); }
void Cache::destroy() {
delete instance;
instance = nullptr;
}
auto Cache::get() -> Cache* { return instance; }
void Cache::init() { instance = std::unique_ptr<Cache>(new Cache()); }
void Cache::destroy() { instance.reset(); }
auto Cache::get() -> Cache* { return instance.get(); }
namespace {
auto basename(const std::string& path) -> std::string {

View File

@@ -3,6 +3,7 @@
#include <SDL3/SDL.h>
#include <cstddef>
#include <memory>
#include <string>
#include <vector>
@@ -20,6 +21,7 @@ namespace Resource {
static void destroy();
static auto get() -> Cache*;
~Cache() = default;
Cache(const Cache&) = delete;
auto operator=(const Cache&) -> Cache& = delete;
@@ -39,7 +41,6 @@ namespace Resource {
private:
Cache() = default;
~Cache() = default;
enum class LoadStage {
MUSICS,
@@ -66,7 +67,7 @@ namespace Resource {
int loaded_count_{0};
std::string current_loading_name_;
static Cache* instance;
static std::unique_ptr<Cache> instance;
};
} // namespace Resource

View File

@@ -9,19 +9,16 @@
namespace Resource {
List* List::instance = nullptr;
std::unique_ptr<List> List::instance;
void List::init(const std::string& yaml_path) {
instance = new List();
instance = std::unique_ptr<List>(new List());
instance->loadFromYaml(yaml_path);
}
void List::destroy() {
delete instance;
instance = nullptr;
}
void List::destroy() { instance.reset(); }
auto List::get() -> List* { return instance; }
auto List::get() -> List* { return instance.get(); }
void List::loadFromYaml(const std::string& yaml_path) {
auto bytes = ResourceHelper::loadFile(yaml_path);

View File

@@ -1,5 +1,6 @@
#pragma once
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
@@ -25,6 +26,7 @@ namespace Resource {
static void destroy();
static auto get() -> List*;
~List() = default;
List(const List&) = delete;
auto operator=(const List&) -> List& = delete;
@@ -44,7 +46,6 @@ namespace Resource {
};
List() = default;
~List() = default;
void loadFromYaml(const std::string& yaml_path);
void loadFromString(const std::string& yaml_content);
@@ -55,7 +56,7 @@ namespace Resource {
std::unordered_map<std::string, Item> file_list_;
static List* instance;
static std::unique_ptr<List> instance;
};
} // namespace Resource

View File

@@ -35,7 +35,7 @@
// Cheats del joc original — declarats a jinput.cpp
extern void JI_moveCheats(Uint8 new_key);
Director* Director::instance_ = nullptr;
std::unique_ptr<Director> Director::instance_;
Director::~Director() = default;
@@ -79,7 +79,7 @@ std::unique_ptr<scenes::Scene> Director::createNextScene() {
}
void Director::init() {
instance_ = new Director();
instance_ = std::unique_ptr<Director>(new Director());
Gamepad::init();
// Registre d'escenes. Cada entrada = un state_key (`num_piramide`)
@@ -116,12 +116,11 @@ void Director::init() {
void Director::destroy() {
Gamepad::destroy();
delete instance_;
instance_ = nullptr;
instance_.reset();
}
auto Director::get() -> Director* {
return instance_;
return instance_.get();
}
void Director::togglePause() {

View File

@@ -52,11 +52,13 @@ class Director {
void togglePause();
auto isPaused() const -> bool { return paused_; }
private:
Director() = default;
public:
~Director();
static Director* instance_;
private:
Director() = default;
static std::unique_ptr<Director> instance_;
void pollAllEvents(); // drenatge amb SDL_PollEvent, només per al bucle natiu

View File

@@ -6,9 +6,9 @@
class Bola : public Sprite {
public:
Bola(JD8_Surface gfx, Prota* sam);
explicit Bola(JD8_Surface gfx, Prota* sam);
void draw();
void draw() override;
void update();
protected:

View File

@@ -29,10 +29,6 @@ Engendro::Engendro(JD8_Surface gfx, Uint16 x, Uint16 y)
this->cycles_per_frame = 30;
}
void Engendro::draw() {
Sprite::draw();
}
bool Engendro::update() {
bool mort = false;

View File

@@ -4,9 +4,8 @@
class Engendro : public Sprite {
public:
Engendro(JD8_Surface gfx, Uint16 x, Uint16 y);
explicit Engendro(JD8_Surface gfx, Uint16 x, Uint16 y);
void draw();
bool update();
protected:

View File

@@ -27,9 +27,14 @@ struct Vertex {
class Mapa {
public:
Mapa(JD8_Surface gfx, Prota* sam);
explicit Mapa(JD8_Surface gfx, Prota* sam);
~Mapa(void);
Mapa(const Mapa&) = delete;
Mapa& operator=(const Mapa&) = delete;
Mapa(Mapa&&) = delete;
Mapa& operator=(Mapa&&) = delete;
void draw();
void update();
bool novaMomia();

View File

@@ -6,7 +6,7 @@
class Marcador {
public:
Marcador(JD8_Surface gfx, Prota* sam);
explicit Marcador(JD8_Surface gfx, Prota* sam);
~Marcador(void);
void draw();

View File

@@ -1,5 +1,7 @@
#include "game/modulegame.hpp"
#include <algorithm>
#include "core/audio/audio.hpp"
#include "core/jail/jdraw8.hpp"
#include "core/jail/jgame.hpp"
@@ -9,29 +11,17 @@ 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);
this->sam = std::make_unique<Prota>(this->gfx);
this->mapa = std::make_unique<Mapa>(this->gfx, this->sam.get());
this->marcador = std::make_unique<Marcador>(this->gfx, this->sam.get());
if (info::ctx.num_piramide == 2) {
this->bola = new Bola(this->gfx, this->sam);
} else {
this->bola = nullptr;
this->bola = std::make_unique<Bola>(this->gfx, this->sam.get());
}
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);
}
@@ -122,8 +112,8 @@ void ModuleGame::Draw() {
this->mapa->draw();
this->marcador->draw();
this->sam->draw();
if (this->momies != nullptr) this->momies->draw();
if (this->bola != nullptr) this->bola->draw();
for (auto& m : this->momies) m->draw();
if (this->bola) this->bola->draw();
}
void ModuleGame::Update() {
@@ -131,32 +121,19 @@ void ModuleGame::Update() {
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();
const auto erased = std::erase_if(this->momies, [](auto& m) { return m->update(); });
info::ctx.momies -= static_cast<int>(erased);
if (this->bola) 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++;
}
this->momies.emplace_back(std::make_unique<Momia>(this->gfx, true, 0, 0, this->sam.get()));
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;
}
this->momies.clear();
info::ctx.momies = 0;
}
if (JI_CheatActivated("obert")) {
for (int i = 0; i < 16; i++) {
@@ -186,11 +163,7 @@ void ModuleGame::iniciarMomies() {
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));
}
this->momies.emplace_back(std::make_unique<Momia>(this->gfx, dimonis, x, y, this->sam.get()));
x += 65;
if (x == 345) {
x = 20;

View File

@@ -1,5 +1,8 @@
#pragma once
#include <memory>
#include <vector>
#include "game/bola.hpp"
#include "game/info.hpp"
#include "game/mapa.hpp"
@@ -28,6 +31,11 @@ class ModuleGame : public scenes::Scene {
ModuleGame();
~ModuleGame() override;
ModuleGame(const ModuleGame&) = delete;
ModuleGame& operator=(const ModuleGame&) = delete;
ModuleGame(ModuleGame&&) = delete;
ModuleGame& operator=(ModuleGame&&) = delete;
void onEnter() override;
void tick(int delta_ms) override;
bool done() const override { return phase_ == Phase::Done; }
@@ -52,9 +60,9 @@ class ModuleGame : public scenes::Scene {
Uint8 final_{0};
JD8_Surface gfx{nullptr};
Mapa* mapa{nullptr};
Prota* sam{nullptr};
Marcador* marcador{nullptr};
Momia* momies{nullptr};
Bola* bola{nullptr};
std::unique_ptr<Mapa> mapa;
std::unique_ptr<Prota> sam;
std::unique_ptr<Marcador> marcador;
std::vector<std::unique_ptr<Momia>> momies;
std::unique_ptr<Bola> bola;
};

View File

@@ -10,15 +10,15 @@ Momia::Momia(JD8_Surface gfx, bool dimoni, Uint16 x, Uint16 y, Prota* sam)
this->sam = sam;
entitat.frames.reserve(20);
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 5; x++) {
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 5; col++) {
Frame f;
f.w = 15;
f.h = 15;
if (info::ctx.num_piramide == 4) f.h -= 5;
f.x = (x * 15) + 75;
f.x = (col * 15) + 75;
if (this->dimoni) f.x += 75;
f.y = 20 + (y * 15);
f.y = 20 + (row * 15);
entitat.frames.push_back(f);
}
}
@@ -40,7 +40,6 @@ Momia::Momia(JD8_Surface gfx, bool dimoni, Uint16 x, Uint16 y, Prota* sam)
this->cur_frame = 0;
this->o = rand() % 4;
this->cycles_per_frame = 4;
this->next = NULL;
if (this->dimoni) {
if (x == 0) {
@@ -57,22 +56,15 @@ Momia::Momia(JD8_Surface gfx, bool dimoni, Uint16 x, Uint16 y, Prota* sam)
} else {
this->y = y;
}
this->engendro = new Engendro(gfx, this->x, this->y);
this->engendro = std::make_unique<Engendro>(gfx, this->x, this->y);
} else {
this->engendro = NULL;
this->x = x;
this->y = y;
}
}
void Momia::clear() {
if (this->next != NULL) this->next->clear();
if (this->engendro != NULL) delete this->engendro;
delete this->next;
}
void Momia::draw() {
if (this->engendro != NULL) {
if (this->engendro) {
this->engendro->draw();
} else {
Sprite::draw();
@@ -85,95 +77,77 @@ void Momia::draw() {
}
}
}
if (this->next != NULL) this->next->draw();
}
bool Momia::update() {
bool morta = false;
if (this->engendro != NULL) {
if (this->engendro) {
if (this->engendro->update()) {
delete this->engendro;
this->engendro = NULL;
}
} else {
if (this->sam->o < 4 && (this->dimoni || info::ctx.num_piramide == 5 || JG_GetCycleCounter() % 2 == 0)) {
if ((this->x - 20) % 65 == 0 && (this->y - 30) % 35 == 0) {
if (this->dimoni) {
if (rand() % 2 == 0) {
if (this->x > this->sam->x) {
this->o = 3;
} else if (this->x < this->sam->x) {
this->o = 2;
} else if (this->y < this->sam->y) {
this->o = 0;
} else if (this->y > this->sam->y) {
this->o = 1;
}
} else {
if (this->y < this->sam->y) {
this->o = 0;
} else if (this->y > this->sam->y) {
this->o = 1;
} else if (this->x > this->sam->x) {
this->o = 3;
} else if (this->x < this->sam->x) {
this->o = 2;
}
}
} else {
this->o = rand() % 4;
}
}
switch (this->o) {
case 0:
if (y < 170) this->y++;
break;
case 1:
if (y > 30) this->y--;
break;
case 2:
if (x < 280) this->x++;
break;
case 3:
if (x > 20) this->x--;
break;
}
if (JG_GetCycleCounter() % this->cycles_per_frame == 0) {
this->cur_frame++;
if (this->cur_frame == entitat.animacions[this->o].frames.size()) this->cur_frame = 0;
}
if (this->x > (this->sam->x - 7) && this->x < (this->sam->x + 7) && this->y > (this->sam->y - 7) && this->y < (this->sam->y + 7)) {
morta = true;
if (this->sam->pergami) {
this->sam->pergami = false;
} else {
info::ctx.vida--;
if (info::ctx.vida == 0) this->sam->o = 5;
}
}
this->engendro.reset();
}
return morta;
}
if (this->next != NULL) {
if (this->next->update()) {
Momia* seguent = this->next->next;
delete this->next;
this->next = seguent;
info::ctx.momies--;
if (this->sam->o < 4 && (this->dimoni || info::ctx.num_piramide == 5 || JG_GetCycleCounter() % 2 == 0)) {
if ((this->x - 20) % 65 == 0 && (this->y - 30) % 35 == 0) {
if (this->dimoni) {
if (rand() % 2 == 0) {
if (this->x > this->sam->x) {
this->o = 3;
} else if (this->x < this->sam->x) {
this->o = 2;
} else if (this->y < this->sam->y) {
this->o = 0;
} else if (this->y > this->sam->y) {
this->o = 1;
}
} else {
if (this->y < this->sam->y) {
this->o = 0;
} else if (this->y > this->sam->y) {
this->o = 1;
} else if (this->x > this->sam->x) {
this->o = 3;
} else if (this->x < this->sam->x) {
this->o = 2;
}
}
} else {
this->o = rand() % 4;
}
}
switch (this->o) {
case 0:
if (y < 170) this->y++;
break;
case 1:
if (y > 30) this->y--;
break;
case 2:
if (x < 280) this->x++;
break;
case 3:
if (x > 20) this->x--;
break;
}
if (JG_GetCycleCounter() % this->cycles_per_frame == 0) {
this->cur_frame++;
if (this->cur_frame == entitat.animacions[this->o].frames.size()) this->cur_frame = 0;
}
if (this->x > (this->sam->x - 7) && this->x < (this->sam->x + 7) && this->y > (this->sam->y - 7) && this->y < (this->sam->y + 7)) {
morta = true;
if (this->sam->pergami) {
this->sam->pergami = false;
} else {
info::ctx.vida--;
if (info::ctx.vida == 0) this->sam->o = 5;
}
}
}
return morta;
}
void Momia::insertar(Momia* momia) {
if (this->next != NULL) {
this->next->insertar(momia);
} else {
this->next = momia;
}
}

View File

@@ -1,5 +1,7 @@
#pragma once
#include <memory>
#include "game/engendro.hpp"
#include "game/info.hpp"
#include "game/prota.hpp"
@@ -7,17 +9,14 @@
class Momia : public Sprite {
public:
Momia(JD8_Surface gfx, bool dimoni, Uint16 x, Uint16 y, Prota* sam);
explicit Momia(JD8_Surface gfx, bool dimoni, Uint16 x, Uint16 y, Prota* sam);
void clear();
void draw();
void draw() override;
bool update();
void insertar(Momia* momia);
bool dimoni;
Momia* next;
protected:
Prota* sam;
Engendro* engendro;
std::unique_ptr<Engendro> engendro;
};

View File

@@ -5,9 +5,9 @@
class Prota : public Sprite {
public:
Prota(JD8_Surface gfx);
explicit Prota(JD8_Surface gfx);
void draw();
void draw() override;
Uint8 update();
Uint8 frame_pejades;

View File

@@ -22,10 +22,10 @@ struct Entitat {
class Sprite {
public:
Sprite(JD8_Surface gfx);
explicit Sprite(JD8_Surface gfx);
virtual ~Sprite() = default;
void draw();
virtual void draw();
Entitat entitat;
Uint8 cur_frame = 0;

View File

@@ -32,7 +32,7 @@ namespace scenes {
// PaletteFade copia internament amb memcpy; alliberem la paleta temporal.
JD8_Palette pal = JD8_LoadPalette("gfx/ffase.gif");
fade_.startFadeTo(pal);
std::free(pal);
delete[] pal;
phase_ = Phase::FadingIn;
remaining_ms_ = 5000;

View File

@@ -16,7 +16,6 @@ namespace scenes {
void onEnter() override;
void tick(int delta_ms) override;
bool done() const override { return done_; }
int nextState() const override { return 1; } // 1 → SceneRegistry::tryCreate(num_piramide=255 → intro)
private:
void render() const;

View File

@@ -29,7 +29,6 @@ namespace scenes {
void onEnter() override;
void tick(int delta_ms) override;
bool done() const override { return phase_ == Phase::Done; }
int nextState() const override { return 1; }
private:
enum class Phase { Rolling,

View File

@@ -37,7 +37,6 @@ namespace scenes {
void onEnter() override;
void tick(int delta_ms) override;
bool done() const override { return phase_ == Phase::Done; }
int nextState() const override { return 1; }
private:
enum class Phase {

View File

@@ -38,7 +38,6 @@ namespace scenes {
void onEnter() override;
void tick(int delta_ms) override;
bool done() const override { return phase_ == Phase::Done; }
int nextState() const override { return 1; }
private:
enum class Phase {

View File

@@ -29,7 +29,6 @@ namespace scenes {
void onEnter() override;
void tick(int delta_ms) override;
bool done() const override { return done_; }
int nextState() const override { return 1; }
private:
SurfaceHandle gfx_;

View File

@@ -21,7 +21,7 @@ namespace scenes {
JD8_Palette pal = JD8_LoadPalette("gfx/menu2.gif");
fade_.startFadeTo(pal);
std::free(pal);
delete[] pal;
phase_ = Phase::FadingIn;
}

View File

@@ -27,7 +27,6 @@ namespace scenes {
void onEnter() override;
void tick(int delta_ms) override;
bool done() const override { return phase_ == Phase::Done; }
int nextState() const override { return 1; }
private:
enum class Phase { FadingIn,

View File

@@ -22,7 +22,7 @@ namespace scenes {
// la paleta temporal immediatament.
JD8_Palette pal = JD8_LoadPalette("gfx/gameover.gif");
fade_.startFadeTo(pal);
std::free(pal);
delete[] pal;
phase_ = Phase::FadingIn;
remaining_ms_ = 10000;

View File

@@ -19,7 +19,6 @@ namespace scenes {
void onEnter() override;
void tick(int delta_ms) override;
bool done() const override { return phase_ == Phase::Done; }
int nextState() const override { return 1; }
private:
enum class Phase { FadingIn,

View File

@@ -37,7 +37,7 @@ namespace {
namespace scenes {
SecretaScene::~SecretaScene() {
if (pal_aux_) std::free(pal_aux_);
delete[] pal_aux_;
// pal_active_ NO s'allibera: propietat de main_palette via SetScreenPalette.
}
@@ -51,7 +51,7 @@ namespace scenes {
gfx_ = SurfaceHandle("gfx/tomba1.gif");
pal_aux_ = JD8_LoadPalette("gfx/tomba1.gif");
pal_active_ = static_cast<JD8_Palette>(std::malloc(768));
pal_active_ = new Color[256];
std::memcpy(pal_active_, pal_aux_, 768);
phase_ = Phase::InitialFadeOut;
@@ -62,7 +62,7 @@ namespace scenes {
JD8_ClearScreen(255);
gfx_.reset("gfx/tomba2.gif");
std::free(pal_aux_);
delete[] pal_aux_;
pal_aux_ = JD8_LoadPalette("gfx/tomba2.gif");
// pal_active_ continua sent el mateix buffer: només actualitzem
// el seu contingut. main_palette ja apunta ací.

View File

@@ -31,7 +31,7 @@ namespace {
namespace scenes {
SlidesScene::~SlidesScene() {
if (pal_aux_) std::free(pal_aux_);
delete[] pal_aux_;
// pal_active_ NO s'allibera: propietat de main_palette via SetScreenPalette.
}
@@ -54,7 +54,7 @@ namespace scenes {
// main_palette després del SetScreenPalette — modificar-la modifica
// main_palette directament. `pal_aux_` es manté intacte per a poder
// restaurar després de cada fade-out intermedi.
pal_active_ = static_cast<JD8_Palette>(std::malloc(768));
pal_active_ = new Color[256];
std::memcpy(pal_active_, pal_aux_, 768);
JD8_SetScreenPalette(pal_active_);