# Ludus — jeux d'enquête en ligne pour Dolibarr (PEREL) · v0.5.1

Vend et fait jouer des escape games en ligne à partir de Dolibarr : codes d'activation, page de jeu publique, suivi des parties.
Premier scénario fourni : **Opération Noël — Dossier 13**, cinq chapitres jouables de bout en bout, avec deux fins.

## Installation

1. Accueil → Configuration → Modules → onglet **Déployer/installer un module externe** → envoyer `module_ludus-0.5.1.zip`.
   Mise à jour depuis la 0.1 : déployer le nouveau zip, puis désactiver/réactiver le module (ajoute le réglage « Chapitre de départ de la démo »).
2. Activer **Ludus** dans la liste des modules (crée les tables `llx_ludus_*`).
3. Donner les droits aux utilisateurs concernés (voir les codes / générer les codes).

Dolibarr 18 ou plus, PHP 8.1 ou plus.

## Utilisation

- **Menu Ludus → Codes & parties** : générer des codes (quantité, scénario, réf. commande), voir leur statut (vendu, activé, remboursé), l'avancement de chaque partie et le tableau « Où les joueurs bloquent ».
- **Menu Ludus → Jouer (démo)** : ouvre la page publique. Le code de démonstration `DEMO-D13` crée une nouvelle partie à chaque saisie. Pensez à le vider avant la mise en vente.
- **Menu Ludus → Paramètres** : blocage après erreurs, durée de vie des parties, repères pointillés, préfixe des codes, code et scénario de démonstration, **chapitre de départ de la démo** (pour tester un chapitre sans rejouer les précédents).

Page à donner aux joueurs : `https://votre-dolibarr/custom/ludus/public/index.php`. Elle fonctionne sans compte Dolibarr.

## Nouveautés 0.5.1

- L'e-mail d'achat contient la confirmation de commande : quantité, prix payé, date, identité du vendeur (réglage « Identité du vendeur »), rappel de l'accord pour l'accès immédiat et de la renonciation au droit de rétractation, lien des CGV.
- Les traces anti-abus (adresses IP et e-mails hachés) sont effacées au bout de 24 h.

## Nouveautés 0.5 — vente en ligne

- **Page de vente** publique (`public/shop.php`) : accroche, quantité, « Pour qui ? » (imprimé sur la convocation), cases CGV et renonciation au droit de rétractation, FAQ. Textes dans la clé `shop` du scénario.
- **Paiement Stripe Checkout** (page de paiement hébergée par Stripe : carte, Apple Pay, Google Pay selon votre compte Stripe). Codes promo Stripe en option.
- **Livraison automatique** : codes créés (un par enquête achetée), rattachés à l'e-mail d'achat, affichés sur la page de confirmation (avec la convocation PDF à télécharger) et envoyés par e-mail avec les convocations en pièce jointe.
- **Fiable** : la commande est servie par le webhook Stripe ou, à défaut, au retour de l'acheteur sur la page de confirmation. Une commande n'est jamais servie deux fois.
- **Réglages** (Paramètres → Vente en ligne) : activation, enquête vendue, prix, quantité max, codes promo, liens CGV et mentions légales, mode test/production, clés Stripe (ou celles du module Stripe de Dolibarr), signature du webhook. Les adresses de la page de vente et du webhook s'affichent en haut des Paramètres.
- Mise à jour : déployer le zip puis désactiver / réactiver le module (nouvelle table des commandes).

### Brancher Stripe (mode test d'abord)

1. Stripe → Développeurs → Clés API : copier la clé secrète `sk_test_…` dans Paramètres.
2. Stripe → Développeurs → Webhooks → Ajouter un endpoint : coller l'adresse « Webhook Stripe » des Paramètres, cocher `checkout.session.completed` et `checkout.session.async_payment_succeeded`, puis copier la clé de signature `whsec_…` dans Paramètres.
3. Activer la vente en ligne, ouvrir la page de vente, payer avec la carte de test `4242 4242 4242 4242`.
4. Pour vendre : refaire 1 et 2 en mode production (`sk_live_…`, second webhook), passer le mode Stripe sur Production, vider le code de démonstration.

## Nouveautés 0.4.1

- **Validité des codes** (Paramètres, en mois ; 0 = sans limite). Pendant la validité, l'enquête se joue, se reprend et se rejoue à volonté ; la date de fin est imprimée sur la convocation. Un code expiré est refusé à l'activation.
- **Destinataires** (facultatif) et **e-mail de l'acheteur** saisis à la génération, modifiables ensuite (icône crayon). Les destinataires s'impriment sur la convocation ; sinon une ligne reste à remplir à la main.
- **Code perdu ?** sur la page du jeu : le joueur saisit l'e-mail d'achat et reçoit ses codes valides avec les convocations en PDF. La réponse est toujours la même, qu'une adresse soit connue ou non.
- **Renvoyer au client** (icône enveloppe) depuis la liste des codes.
- **Limitation des essais** : 20 codes erronés par heure et par adresse IP ; 5 demandes « code perdu » par heure et par IP, 3 par jour et par adresse e-mail.
- Mise à jour depuis une version précédente : déployer le zip puis **désactiver / réactiver** le module (ajout des colonnes destinataires et e-mail).
- Les e-mails partent via la configuration e-mail de Dolibarr (expéditeur réglable dans Paramètres).

## Nouveautés 0.4

- **Convocation imprimable (carte-cadeau)** : une page A4 par code, avec le code, l'adresse du jeu et un QR code qui ouvre la page d'activation avec le code déjà saisi. Textes dans la clé `gift` du scénario.
- Dans **Codes & parties** : icône PDF sur chaque code, bouton « Convocations PDF de ces codes » juste après une génération, et cases à cocher pour imprimer une sélection (un PDF de plusieurs pages, pratique pour un lot CSE).

## Nouveautés 0.3

- **Convocation d'ouverture** avant le chapitre 1 (clé `prologue` du scénario) : le canal Octave démarre quand les joueurs acceptent la mission.
- **Bilan de fin d'enquête** (clé `epilogue`) : la fin obtenue, le récapitulatif des choix de chaque chapitre, la confiance d'Octave, le total des erreurs et des notes, et un bouton pour revenir à la décision finale et découvrir l'autre fin.
- **Sur téléphone**, le canal Octave devient un tiroir : bouton flottant avec le nombre de messages non lus, ouverture automatique quand Octave pose une question ou quand on transmet une réponse.

## Principes

- **Le serveur décide.** Le navigateur n'envoie que des intentions (positions des bandes, repère, choix). Les solutions, les déclencheurs et les notes non ouvertes ne quittent jamais le serveur.
- **Le scénario est une donnée** : `scenarios/<id>/scenario.json.php`. Un nouveau dossier = un nouveau sous-dossier. La première ligne PHP empêche toute lecture directe du fichier par le web : ne pas la retirer.
- **Une session = une équipe.** Le lien `?s=…` se partage ; tout le monde joue la même progression.

## Format du scénario (résumé)

| Clé du chapitre | Rôle |
|---|---|
| `documents` | Pièces ; `open: false` = scellée jusqu'à un `unlock`. |
| `notes` | Notes de Madeleine (indices), servies une par une. |
| `workbenches` | Établis du chapitre (type + affichage, jamais de solution). Un établi n'est envoyé au navigateur qu'à l'étape qui l'utilise. |
| `steps` | Étapes à valider dans l'ordre : `bench`, `check` (solution), `on_success`, `fail_lines` (avec `{right}`/`{total}`), `fail_rules` (échec spécifique). |
| `triggers` | `start`, `on:*` (déclenchables par le navigateur : `on:first_drag:B`, `on:doc_opened:3D`), les autres côté serveur uniquement. |
| `asks` | Choix narratifs : `add` / `set` sur les variables, puis `then`. |

Actions : `say`+`text`, `sys`, `sound` (clack, signal32, alarm, pulse), `unlock`, `wb` (lock, set, marks, reveal, show), `helpline`, `ask`, `add`, `set`, `if`/`then`/`else`, `goto`, `end` (+ `title`).
Vérifications : `tape_offsets`, `pin_time`, `fields` (correspondance champ par champ, compte les bonnes réponses), `text`, `number`.
Établis disponibles :

| Type | Usage dans Dossier 13 |
|---|---|
| `tape_align` | Bandes à caler sur une référence, repère à poser (ch. 1 et 3) |
| `sort_cards` | Cartes à classer en colonnes ou sur un plan (ch. 1 affirmations, ch. 2 plan de l'atelier) |
| `dial` | Cadran à N positions, phases photographiées (ch. 4, séquence 5–5–3) |
| `control_panel` | Pupitre : canal, mesures, séquenceur, procédure ordonnée (ch. 5) |

## Pour plus tard

`LudusStore::createCode()` est prévu pour être appelé par un webhook Stripe ou par un déclencheur « facture payée » (champs `fk_soc`, `fk_facture`, `order_ref`).
