Rewrite de NppClone avec copie conforme du moteur physique de N original
Find a file
Sylvain PILLOT 9e35a4c05c chore : maj saves/stats packs après build + test émulateur (mq)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 16:31:13 +02:00
assets/packs chore : maj saves/stats packs après build + test émulateur (mq) 2026-06-27 16:31:13 +02:00
assets-cg feat : anim flammes rocket — 12 frames cycle 100 ms en vol 2026-05-27 21:51:56 +02:00
assets-pc/sfx audio PC — 19 samples NppFlash extraits (jump/land/death/zap/ragdoll) 2026-05-27 22:13:59 +02:00
build-cg-prof update README.md 2026-05-28 19:15:41 +02:00
DOCS polish phase 6 — doc + re-audit post-polish 2026-05-26 23:19:32 +02:00
pc feat : déblocage progressif des packs + community vide + optim boot 2026-05-28 22:17:33 +02:00
src feat : déblocage progressif des packs + community vide + optim boot 2026-05-28 22:17:33 +02:00
tests feat : déblocage progressif des packs + community vide + optim boot 2026-05-28 22:17:33 +02:00
tools P7.1 — portes intermédiaires v1.0 + fix ragdoll overflow + UX trophées/Tiled 2026-05-26 22:20:19 +02:00
.clang-format P0 — Socle, qualité, harness golden 2026-05-17 23:43:48 +02:00
.gitignore P0 — Socle, qualité, harness golden 2026-05-17 23:43:48 +02:00
build-casio P0 — Socle, qualité, harness golden 2026-05-17 23:43:48 +02:00
build-casio-debug build-casio-debug : script build Casio profilé (libprof) 2026-05-27 08:03:22 +02:00
build-pc P0 — Socle, qualité, harness golden 2026-05-17 23:43:48 +02:00
CHANGELOG.md polish phase 6 — doc + re-audit post-polish 2026-05-26 23:19:32 +02:00
clean.sh P0 — Socle, qualité, harness golden 2026-05-17 23:43:48 +02:00
CMakeLists.txt azur : custom shader bitfont — 1 commande par chaîne (V1.0-grade) 2026-05-27 10:35:09 +02:00
README.md docs : README réécrit (état courant, 2 cibles, formats, contrôles) 2026-05-28 18:54:38 +02:00
run-tests P0 — Socle, qualité, harness golden 2026-05-17 23:43:48 +02:00

Npp Rewrite

Réécriture sur base saine du clone N++ pour CASIO fx-CG50 et PC, calquée sur la cible canonique NppFlash (AS3 Metanet). Objectif : rejouer les 600 niveaux NppFlash (120 épisodes × 5) avec une physique fidèle et déterministe, sur deux cibles partageant le même cœur de simulation portable.

Pierre angulaire. La simulation tourne en pas fixe 40 Hz, découplé du rendu (NppFlash sim_rate = 40). C'est le correctif de l'erreur racine de la v1.0, qui simulait en pas variable → physique dépendante du framerate. Tout le reste (collision, entités, ragdoll) découle de ce choix.

En bref

  • Cœur portable pur (src/sim/) : aucune dépendance gint / SDL / Azur, arithmétique virgule fixe Q16.16, testable et identique sur les deux cibles.
  • Physique fidèle : portage ligne à ligne de Ninja.as / Simulator.as (collision cercle r vs segments/arcs, 4 sous-itérations/tick, 22 types d'entités, raycast Q16.16, ragdoll Verlet déterministe).
  • 600 niveaux importés depuis NppFlash via tools/build_pack.py (assets/packs/ep00…ep119.npl).
  • UI pixel-perfect reprise de la version Npp v1.0 : titre, options, browser de packs, écrans Trophées & Stats (49 trophées), éditeur de nom, dialogues in-game.
  • Rendu : SDL2 sur PC ; Azur Render Pipeline + gint sur Casio.
  • Popup trophée temps-réel : un trophée débloqué en cours de partie s'affiche en carte descriptive glissée en haut à droite.
  • Audio : samples NppFlash extraits + sons procéduraux (PC).
  • Formats figés : un seul format par artefact, zéro rétrocompat, parseurs bornés hostile-safe (jamais de crash sur entrée corrompue).

État courant

Branche dev (post-tag v2.0-stable). Toutes les phases roadmap P0P7 sont closes ; depuis, migration complète vers l'Azur Render Pipeline (Casio), ajout de l'audio (PC) et du popup trophée temps-réel.

Cible Statut
PC (tests doctest) 127 cas verts sous -Werror
PC (appli SDL2) pc/build/npp_play jouable
Casio fx-CG50 Npp.g3a — ROM ≈ 629 KiB (30,7 %), RAM ≈ 34 KiB / 491 KiB (+3 MiB extram via AddMoreRAM)

Gates : G1 (déterminisme golden) · G2 (EntitySystem hors god-object) · G3 (600 niveaux chargés, 0 type ignoré) · G4 (release : -Werror 2 cibles ; perf on-device = à mesurer sur matériel réel).

Structure

src/
  config/    constantes paramétrables — 1 header par entité (cf. config/README.md)
  sim/       CŒUR PORTABLE PUR (aucune dép. gint/SDL/Azur) — testable direct
             fixed · vec2 · sim_clock · ninja · simulator · world · seg/edge grid
             entities/ (22 types) · loader · npp_format · pack_format · rng · ragdoll
  render/    model/view UI pixel-perfect v1.0 (PORTABLE, via Renderer abstrait)
             title · options · browser · trophies · trophy_popup · sim_view · sprites · fx
  render_cg/ back-end gint/Azur (fx-CG50)
  screens/   handlers légers d'écran (menu/options/name-edit/trophies) + play_events
  platform/  I/O sûre : fs.h (world-switch Casio) · clock (overclock) · extram
  main_casio.cpp   point d'entrée gint (frontend complet)
pc/sdl/      port SDL2 : npp_play (appli jouable) + sdl_renderer + keyboard + sound
tests/       doctest (vendor/) — golden, sim, formats, fuzz, entités, UI, trophées…
tools/       build_pack.py (Levels.bin → packs .npl) + outils d'assets
assets/packs/  600 niveaux (ep00…ep119.npl) + sauvegardes per-pack (.nps)
DOCS/        analyse, roadmap, audits, docs de design figés

Le cœur src/sim/ ne dépend de rien : il se compile et se teste sur PC sans couche de compatibilité, et tourne tel quel sur Casio. Les vues render/ sont elles aussi portables (elles dessinent via une interface Renderer abstraite) ; seuls render_cg/ et pc/sdl/ connaissent la cible.

Build & test

./run-tests        # compile + lance la suite doctest (pc/build/npp_tests)
./build-pc         # build PC (tests + appli SDL2 si SDL2 présent)
./build-casio      # Npp.g3a (fxSDK) ;  ./build-casio -B  = rebuild complet
./clean.sh         # purge les builds
  • Stack Casio : Azur, gint, fxSDK, cZlib. Stack PC : SDL2 (+ SDL2_image, optionnel pour les sprites), zlib système.
  • Qualité : C++23, -Wall -Wextra -Wpedantic -Werror sur les deux cibles, jamais -fpermissive. G1 (golden) doit rester vert à chaque commit.

Jouer

L'appli PC charge automatiquement les packs depuis assets/packs/ et ouvre le menu titre — pas d'argument :

pc/build/npp_play

Contrôles PC (en jeu) : ←/→ se déplacer · Shift ou sauter · N niveau suivant · R rejouer · O pause/options · K (2 s) suicide · Échap quitter le run · Entrée valider les dialogues. Menus : ↑/↓/←/→ naviguer · Entrée valider · Échap retour · Shift+←/→ changer d'onglet (Trophées/Stats, catégories browser) · F5 rescanner les packs depuis le disque.

Sur Casio, les touches équivalentes gint sont câblées dans main_casio.cpp (flèches, SHIFT/UP saut, F1F5, MENU pause, EXE/EXIT).

Formats de fichiers

Tous les formats sont mono-version, zéro rétrocompat (décision figée) et lus par des parseurs bornés qui refusent proprement magic/bornes/troncature.

Format Magic / version Rôle
.npp / .nzp NPPL / NZPL un niveau (clair / zlib), pack_id = CRC32
.npl NPLP v1 pack de niveaux (concatène des blobs .npp/.nzp)
.nps NPPS v6 sauvegarde par pack (epNN.nps) : complété, top-5 temps, perfect/all-gold, deaths
settings NPCO v4 options joueur (NppClone.cfg) : thème, couleurs, nom, overclock, FPS/Perf
stats NPST v2 compteurs Tier 1/Tier 2 (NppClone.stats) — alimentent les 49 trophées

Les sauvegardes .nps sont per-pack (write borné < ~600 octets quel que soit le nombre de packs installés) ; le pack_id est revalidé au chargement contre l'index NppClone.idx (mismatch ⇒ slice resetée + drapeau d'erreur).

Décisions figées

  • D-STEP : pas fixe 40 Hz, rendu découplé (accumulateur + interpolation).
  • D-COLL : collision NppFlash fidèle (cercle vs segGrid/edgeGrid/objGrid).
  • D-PAR : déterminisme prouvé par golden-test (auto-cohérence Q16.16, pas bit-exact vs double).
  • D-ARCH : EntitySystem dès le départ (pas de god-object Level).
  • D-FMT : un seul format par artefact, zéro rétrocompat.
  • D-MENU : UI = design v1.0, mais model/view séparés.

Documentation