Utiliser Loreline avec Lua

Loreline fournit un module Lua compatible avec Lua 5.1 et versions ultérieures, sans dépendances externes. Ce guide montre comment configurer un projet, charger un script .lor, et gérer les dialogues, les choix et la fin du script.

Installer la bibliothèque

Téléchargez loreline-lua.zip depuis la page des releases GitHub. L'archive contient :

Copiez le dossier loreline/ dans votre projet pour que require("loreline") puisse le trouver.

Charger un script

Utilisez loreline.parse() pour analyser une chaîne .lor. Le troisième argument est un gestionnaire de fichiers pour résoudre les instructions import dans votre script :

local loreline = require("loreline")

local function handle_file(path, provide)
    local f = io.open(path, "r")
    if f then
        provide(f:read("*a"))
        f:close()
    else
        provide("")
    end
end

local f = io.open("story/CoffeeShop.lor", "r")
local content = f:read("*a")
f:close()

local script = loreline.parse(content, "story/CoffeeShop.lor", handle_file)
loreline.play(script, on_dialogue, on_choice, on_finish)

Si votre script n'a pas d'instructions import, vous pouvez omettre le gestionnaire de fichiers :

local script = loreline.parse(content)

Gérer les dialogues

Le gestionnaire de dialogue reçoit l'interpréteur, un identifiant de personnage (ou nil pour du texte narratif), le texte du dialogue, les tags éventuels, et un callback pour faire avancer le script :

local function on_dialogue(interp, character, text, tags, advance)
    if character ~= nil then
        -- Résoudre le nom d'affichage depuis la définition du personnage
        local name = interp:get_character_field(character, "name")
        print((name or character) .. " : " .. text)
    else
        -- Texte narratif (pas de personnage)
        print(text)
    end
    advance()
end

Dans une application avec interface graphique, vous afficheriez typiquement le texte et appelleriez advance() quand le joueur est prêt à continuer.

Gérer les choix

Le gestionnaire de choix reçoit une liste d'options (une table Lua indexée à partir de 1). Chaque option a un champ text et un champ enabled. Appelez le callback avec l'index du choix sélectionné (indexé à partir de 0) :

local function on_choice(interp, options, select)
    for i, opt in ipairs(options) do
        if opt.enabled then
            print("  [" .. i .. "] " .. opt.text)
        end
    end

    -- Dans une vraie application, vous afficheriez des boutons et appelleriez select(index) au clic
    select(0)  -- sélectionner la première option (indexé à partir de 0)
end

Notez que la table options est indexée à partir de 1 (standard Lua), mais le callback select attend un index commençant à 0.

Gérer la fin du script

Le gestionnaire de fin est appelé quand le script atteint sa fin :

local function on_finish(interp)
    print("--- Fin ---")
end

Exemple complet

Voici une application console complète qui charge et joue un script Loreline :

local loreline = require("loreline")

local function read_file(path)
    local f = io.open(path, "r")
    if not f then return "" end
    local content = f:read("*a")
    f:close()
    return content
end

local function script_dir()
    local info = debug.getinfo(1, "S")
    local path = info.source:match("^@(.*/)")
    return path or "./"
end

local function handle_file(path, provide)
    provide(read_file(path))
end

local function on_dialogue(interp, character, text, tags, advance)
    local formatted = text:gsub("\n", "\n  ")
    if character ~= nil then
        local name = interp:get_character_field(character, "name")
        io.write("  " .. (name or character) .. " : " .. formatted .. "\n")
    else
        io.write("  " .. formatted .. "\n")
    end
    advance()
end

local function on_choice(interp, options, select)
    io.write("\n")
    local enabled = {}
    for i, opt in ipairs(options) do
        if opt.enabled then
            enabled[#enabled + 1] = i - 1  -- indexé à partir de 0 pour select()
            io.write("  " .. #enabled .. ". " .. opt.text .. "\n")
        end
    end

    while true do
        io.write("\n> ")
        io.flush()
        local raw = io.read("*l")
        if raw == nil then break end
        local choice = tonumber(raw:match("^%s*(.-)%s*$"))
        if choice and choice >= 1 and choice <= #enabled then
            select(enabled[choice])
            return
        end
        io.write("  Veuillez entrer un numéro de choix valide.\n")
    end
end

local function on_finish(interp)
    io.write("\n--- Fin ---\n")
end

local story_dir = script_dir() .. "story/"
local story_path = story_dir .. "CoffeeShop.lor"

local source = read_file(story_path)
if source == "" then
    io.stderr:write("Erreur : impossible de lire " .. story_path .. "\n")
    os.exit(1)
end

local script = loreline.parse(source, story_path, handle_file)
if script == nil then
    io.stderr:write("Erreur : impossible d'analyser le script\n")
    os.exit(1)
end

io.write("=== CoffeeShop ===\n\n")
loreline.play(script, on_dialogue, on_choice, on_finish)

Aller plus loin

Le téléchargement loreline-lua.zip inclut un exemple complet avec une histoire utilisant des définitions de personnages et des imports. Téléchargez-le depuis la page des releases GitHub.