import db def ensure_schema(slug: str) -> None: """Crée les tables de ce module si elles n'existent pas encore — les jeux créés avant l'ajout de cette fonctionnalité n'ont pas besoin d'être migrés manuellement, la première visite d'un écran de ce jeu suffit.""" conn = db.connect(slug) conn.executescript( """ CREATE TABLE IF NOT EXISTS _screens ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, order_index INTEGER NOT NULL DEFAULT 0, is_template INTEGER NOT NULL DEFAULT 0, created_at TEXT DEFAULT CURRENT_TIMESTAMP ); """ ) screen_cols = {r["name"] for r in conn.execute("PRAGMA table_info(_screens)").fetchall()} if "is_template" not in screen_cols: # Un écran-modèle héberge le contenu d'un élément de jeu réutilisable # (voir template_screen_id ci-dessus) : il n'apparaît jamais dans la # liste des écrans du jeu, ni dans le mode jouable, ni dans les # menus "aller à cet écran" — seul son contenu (les éléments qu'il # contient) est utilisé, jamais l'écran lui-même. conn.execute("ALTER TABLE _screens ADD COLUMN is_template INTEGER NOT NULL DEFAULT 0") if "preview_aspect" not in screen_cols: # Format d'aperçu choisi pour cet écran (Portrait 9/16, Paysage 16/9, # ou Carré 1/1) — mémorisé par écran pour qu'il reste le même après # un ajout/suppression d'élément ou un changement d'élément # sélectionné (ces actions redemandent le panneau au serveur, qui # doit donc connaître le choix déjà fait, sinon il repart sur la # valeur par défaut à chaque fois). Sert aussi en mode Jouer, pour # garder la zone de jeu à la bonne proportion quelle que soit la # forme réelle de la fenêtre du joueur (voir #playFrame dans # play.html) — sans ça, les positions/tailles en % se déforment dès # que la fenêtre du joueur n'a pas la même proportion que celle # utilisée à la conception. conn.execute("ALTER TABLE _screens ADD COLUMN preview_aspect TEXT NOT NULL DEFAULT '9/16'") if "background_music_url" not in screen_cols: # Phase 6 — musique de fond de cet écran (URL) : démarrée en boucle # à l'affichage de l'écran, arrêtée au changement d'écran (voir # runScreenBackgroundMusic() dans static/js/play/screens.js). # Indépendante de l'action "Jouer un son" (effet sonore ponctuel, # non bouclé, sur n'importe quel déclencheur). conn.execute("ALTER TABLE _screens ADD COLUMN background_music_url TEXT") if "scene_width" not in screen_cols: # Fondations multi-éditeurs — jeux "jeu_2d" (voir db/games/ # get_game_type.py) : une scène a une taille FIXE en pixels # (contrairement à un écran "document", positionné en % fluides # via preview_aspect ci-dessus) — indispensable pour la collision # et l'animation de sprites. Sans effet sur un écran "document" # (jamais lu par son rendu) — voir screens/scenes/. conn.execute("ALTER TABLE _screens ADD COLUMN scene_width INTEGER NOT NULL DEFAULT 960") conn.execute("ALTER TABLE _screens ADD COLUMN scene_height INTEGER NOT NULL DEFAULT 540") if "kind" not in screen_cols: # Un seul moteur d'écran désormais : "jeu_2d" (scène pixels — voir # db/games/get_game_type.py, conservé pour la rétro-compatibilité # d'un jeu créé avant l'existence de cette colonne). conn.execute("ALTER TABLE _screens ADD COLUMN kind TEXT NOT NULL DEFAULT 'jeu_2d'") conn.execute("UPDATE _screens SET kind = ?", (db.get_game_type(slug),)) if "_screen_triggers" not in screen_cols: # Déclencheurs D'ÉCRAN (voir screens/rendering/screen_triggers.py) — # section "Déclencheurs de l'écran" de l'éditeur de scène : SANS # objet propriétaire, contrairement à _collision_rules (porté par # un objet, colonne JSON dans _scene_objects.attributes). NULL # (aucune règle) pour tout écran créé avant l'ajout de cette # fonctionnalité, comme pour les autres colonnes ci-dessus. conn.execute("ALTER TABLE _screens ADD COLUMN _screen_triggers TEXT") conn.commit() conn.close()