Utiliser Loreline avec C++
Loreline fournit une bibliothèque C++ avec des binaires pré-compilés pour macOS, Linux et Windows. L'API utilise des fonctions de style C avec un seul fichier d'en-tête, ne nécessitant que C++11. 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-cpp.zip depuis la page des releases GitHub. L'archive contient :
loreline/include/Loreline.h: l'en-tête publicloreline/mac/libLoreline.dylib: bibliothèque pré-compilée macOSloreline/linux-arm64/libLoreline.soetloreline/linux-x86_64/libLoreline.so: bibliothèques pré-compilées Linuxloreline/windows/Loreline.dlletloreline/windows/Loreline.lib: bibliothèque pré-compilée WindowsCMakeLists.txt: projet CMake prêt à l'emploimain.cpp: application d'exemple complètestory/: fichiers.lord'exemple
L'archive peut servir de point de départ pour votre propre projet, ou de référence pour intégrer Loreline dans un projet existant.
Configuration du projet avec CMake
Pour ajouter Loreline à un projet CMake existant, pointez vers les répertoires include et lib :
target_include_directories(votre_app PRIVATE /chemin/vers/loreline/include)
target_link_directories(votre_app PRIVATE /chemin/vers/loreline/mac) # ou linux-x86_64, windows
target_link_libraries(votre_app PRIVATE Loreline)
Assurez-vous que la bibliothèque partagée (libLoreline.dylib, libLoreline.so ou Loreline.dll) se trouve à côté de votre exécutable au lancement. Sur macOS et Linux, configurez le rpath :
# macOS
set_target_properties(votre_app PROPERTIES BUILD_RPATH "@executable_path")
# Linux
set_target_properties(votre_app PROPERTIES BUILD_RPATH "$ORIGIN")
Sur Windows, copiez la DLL à côté de votre exécutable en étape post-build.
Initialisation et nettoyage
Avant d'utiliser toute fonction Loreline, appelez Loreline_init(). Une fois terminé, appelez Loreline_dispose() :
#include "Loreline.h"
int main() {
Loreline_init();
// ... utiliser Loreline ...
Loreline_dispose();
return 0;
}
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 :
#include <fstream>
#include <sstream>
#include <string>
std::string readFile(const std::string& path) {
std::ifstream f(path, std::ios::binary);
if (!f.is_open()) return std::string();
std::ostringstream ss;
ss << f.rdbuf();
return ss.str();
}
void onFileRequest(
Loreline_String path,
void (*provide)(Loreline_String content),
void* userData
) {
std::string content = readFile(path.c_str());
provide(content.empty() ? Loreline_String() : Loreline_String(content.c_str()));
}
std::string content = readFile("story/CoffeeShop.lor");
Loreline_Script* script = Loreline_parse(
content.c_str(), "story/CoffeeShop.lor", onFileRequest, NULL
);
Si votre script n'a pas d'instructions import, vous pouvez passer NULL pour le gestionnaire de fichiers :
Loreline_Script* script = Loreline_parse(content.c_str(), "CoffeeShop.lor", NULL, NULL);
Gérer les dialogues
Le gestionnaire de dialogue est un pointeur de fonction C. Il reçoit l'interpréteur, un identifiant de personnage (utilisez isNull() pour vérifier s'il s'agit de texte narratif), le texte du dialogue, les tags et une fonction advance à appeler pour continuer :
void onDialogue(
Loreline_Interpreter* interp,
Loreline_String character,
Loreline_String text,
const Loreline_TextTag* tags,
int tagCount,
void (*advance)(void),
void* userData
) {
if (!character.isNull()) {
// Résoudre le nom d'affichage depuis la définition du personnage
Loreline_Value nameVal = Loreline_getCharacterField(interp, character, "name");
const char* displayName = (nameVal.type == Loreline_StringValue && nameVal.stringValue)
? nameVal.stringValue.c_str()
: character.c_str();
printf("%s : %s\n", displayName, text.c_str());
} else {
// Texte narratif
printf("%s\n", text.c_str());
}
advance();
}
Loreline_String est un type de chaîne à comptage de références, vous n'avez jamais besoin de la libérer manuellement. Utilisez .c_str() pour obtenir une chaîne C terminée par null, et .isNull() pour vérifier s'il s'agit d'une valeur nulle.
Gérer les choix
Le gestionnaire de choix reçoit un tableau de Loreline_ChoiceOption. Chaque option a un champ text (un Loreline_String) et un champ enabled (un bool). Appelez select(index) avec l'index (base 0) de l'option choisie :
void onChoice(
Loreline_Interpreter* interp,
const Loreline_ChoiceOption* options,
int optionCount,
void (*select)(int index),
void* userData
) {
for (int i = 0; i < optionCount; i++) {
if (options[i].enabled) {
printf(" [%d] %s\n", i + 1, options[i].text.c_str());
}
}
// Lire l'entrée du joueur
printf("> ");
fflush(stdout);
char buf[64];
if (fgets(buf, sizeof(buf), stdin)) {
int choice = atoi(buf);
if (choice >= 1 && choice <= optionCount) {
select(choice - 1);
}
}
}
Gérer la fin du script
Le gestionnaire de fin est appelé quand le script atteint sa fin :
void onFinish(Loreline_Interpreter* interp, void* userData) {
printf("--- Fin ---\n");
}
Exemple complet
Voici une application console complète qui charge et exécute un script Loreline :
#include "Loreline.h"
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <string>
static std::string readFile(const std::string& path) {
std::ifstream f(path, std::ios::binary);
if (!f.is_open()) return std::string();
std::ostringstream ss;
ss << f.rdbuf();
return ss.str();
}
static void onFileRequest(
Loreline_String path, void (*provide)(Loreline_String), void*
) {
std::string content = readFile(path.c_str());
provide(content.empty() ? Loreline_String() : Loreline_String(content.c_str()));
}
static void onDialogue(
Loreline_Interpreter* interp, Loreline_String character,
Loreline_String text, const Loreline_TextTag*, int,
void (*advance)(void), void*
) {
if (!character.isNull()) {
Loreline_Value nameVal = Loreline_getCharacterField(interp, character, "name");
const char* name = (nameVal.type == Loreline_StringValue && nameVal.stringValue)
? nameVal.stringValue.c_str() : character.c_str();
printf("%s : %s\n\n", name, text.c_str());
} else {
printf("%s\n\n", text.c_str());
}
advance();
}
static void onChoice(
Loreline_Interpreter*, const Loreline_ChoiceOption* options,
int optionCount, void (*select)(int), void*
) {
for (int i = 0; i < optionCount; i++) {
if (options[i].enabled)
printf(" [%d] %s\n", i + 1, options[i].text.c_str());
}
printf("> ");
fflush(stdout);
char buf[64];
if (fgets(buf, sizeof(buf), stdin)) {
int choice = atoi(buf);
if (choice >= 1 && choice <= optionCount)
select(choice - 1);
}
}
static void onFinish(Loreline_Interpreter*, void*) {
printf("--- Fin ---\n");
}
int main() {
std::string content = readFile("story/CoffeeShop.lor");
if (content.empty()) {
fprintf(stderr, "Erreur : impossible de lire le fichier\n");
return 1;
}
Loreline_init();
Loreline_Script* script = Loreline_parse(
content.c_str(), "story/CoffeeShop.lor", onFileRequest, NULL
);
if (!script) {
fprintf(stderr, "Erreur : échec de l'analyse du script\n");
Loreline_dispose();
return 1;
}
Loreline_Interpreter* interp = Loreline_play(
script, onDialogue, onChoice, onFinish, Loreline_String(), NULL, NULL
);
if (interp) Loreline_releaseInterpreter(interp);
Loreline_releaseScript(script);
Loreline_dispose();
return 0;
}
Aller plus loin
Le téléchargement loreline-cpp.zip inclut des scripts de build par plateforme (build-mac.sh, build-linux.sh, build-windows.bat) et un exemple fonctionnel complet avec une histoire utilisant des définitions de personnages et des imports.