This commit is contained in:
Guillem George 2026-02-27 20:31:35 +01:00
commit ef85bb4e4b
58 changed files with 1226 additions and 0 deletions

BIN
libzork/client/client.tar Normal file

Binary file not shown.

27
libzork/client/flake.lock generated Normal file
View file

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1751984180,
"narHash": "sha256-LwWRsENAZJKUdD3SpLluwDmdXY9F45ZEgCb0X+xgOL0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9807714d6944a957c2e036f84b0ff8caf9930bc0",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

23
libzork/client/flake.nix Normal file
View file

@ -0,0 +1,23 @@
{
description = "Flake for libzork";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }: {
devShells.x86_64-linux.default = with nixpkgs.legacyPackages.x86_64-linux; mkShell {
buildInputs = [
gcc
cmake
yaml-cpp
curl
nlohmann_json
openssl
cmake
pkg-config
];
};
};
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <stdexcept>
namespace libzork
{
class RunnerQuit : public std::exception
{
public:
RunnerQuit() = default;
~RunnerQuit() override = default;
};
class RunnerInterrupt : public std::runtime_error
{
public:
using super_type = std::runtime_error;
using super_type::super_type;
~RunnerInterrupt() override = default;
};
} // namespace libzork

View file

@ -0,0 +1,21 @@
#pragma once
#include <libzork/runner/interactive.hh>
namespace libzork::runner
{
class ChoiceRunner : public InteractiveRunner
{
public:
using InteractiveRunner::InteractiveRunner;
~ChoiceRunner() override = default;
};
std::unique_ptr<ChoiceRunner>
make_choice_runner(std::unique_ptr<story::Story> story,
std::istream& is = std::cin,
std::ostream& os = std::cout);
} // namespace libzork::runner

View file

@ -0,0 +1,20 @@
#pragma once
#include <libzork/runner/runner.hh>
namespace libzork::runner
{
class HTMLRunner : public Runner
{
public:
using Runner::Runner;
~HTMLRunner() override = default;
};
std::unique_ptr<HTMLRunner>
make_html_runner(std::unique_ptr<story::Story> story,
const fs::path& output_dir);
} // namespace libzork::runner

View file

@ -0,0 +1,30 @@
#pragma once
#include <iostream>
#include <libzork/runner/runner.hh>
namespace libzork::runner
{
class InteractiveRunner : public Runner
{
public:
using Runner::Runner;
InteractiveRunner(std::unique_ptr<story::Story> story,
std::istream& is = std::cin,
std::ostream& os = std::cout);
~InteractiveRunner() override = default;
void run() override;
virtual void print_script() const;
virtual void process_input() = 0;
protected:
std::istream& is_;
std::ostream& os_;
};
} // namespace libzork::runner

View file

@ -0,0 +1,21 @@
#pragma once
#include <libzork/story/story.hh>
namespace libzork::runner
{
class Runner
{
public:
Runner(std::unique_ptr<story::Story> story);
virtual ~Runner() = default;
virtual void run() = 0;
protected:
std::unique_ptr<story::Story> story_;
};
} // namespace libzork::runner

View file

@ -0,0 +1,27 @@
#pragma once
#include <libzork/runner/interactive.hh>
#include <unordered_set>
namespace libzork::runner
{
class SmartRunner : public InteractiveRunner
{
public:
using InteractiveRunner::InteractiveRunner;
~SmartRunner() override = default;
virtual std::unordered_set<std::string>
tokenize(const std::string& str) const = 0;
virtual bool has_unmatched_token(
const std::unordered_set<std::string>& user_tokens,
const std::unordered_set<std::string>& choice_tokens) const = 0;
};
std::unique_ptr<SmartRunner> make_smart_runner(
std::unique_ptr<story::Story> story, const fs::path& synonyms_path,
std::istream& is = std::cin, std::ostream& os = std::cout);
} // namespace libzork::runner

View file

@ -0,0 +1,55 @@
#pragma once
#include <map>
#include <memory>
#include <string>
namespace libzork::story
{
// Forward declaration because of the recursive dependencies
// store.hh -> node.hh -> (action|condition).hh -> store.hh
class Node;
class Story;
} // namespace libzork::story
namespace libzork::store
{
class Store
{
public:
virtual ~Store() = default;
virtual const story::Node* get_active_node() const = 0;
virtual void set_active_node(const story::Node* node) = 0;
virtual bool has_variable(const std::string& name) const = 0;
virtual int get_variable(const std::string& name) const = 0;
virtual void set_variable(const std::string& name, int value) = 0;
virtual std::map<std::string, int> get_inventory() const = 0;
};
std::unique_ptr<Store> make_store();
class UndoStore
{
public:
virtual ~UndoStore() = default;
virtual void new_state() = 0;
virtual bool undo() = 0;
virtual bool redo() = 0;
};
class SaveStore
{
public:
virtual ~SaveStore() = default;
virtual void save(std::ostream& os) const = 0;
virtual void restore(std::istream& is, const story::Story& story) = 0;
};
} // namespace libzork::store

View file

@ -0,0 +1,36 @@
#pragma once
#include <filesystem>
#include <libzork/vars/action.hh>
#include <libzork/vars/condition.hh>
#include <memory>
#include <string>
#include <vector>
namespace fs = std::filesystem;
namespace libzork::story
{
class Node
{
public:
virtual ~Node() = default;
virtual const std::string& get_name() const = 0;
virtual const std::string& get_text() const = 0;
virtual const Node* get_choice(std::size_t index,
bool check_conditions = true) const = 0;
virtual std::vector<std::string>
list_choices(bool check_conditions = true) const = 0;
virtual void add_choice(
const Node* other, const std::string& text,
std::vector<std::unique_ptr<vars::Condition>> conditions = {},
std::vector<std::unique_ptr<vars::Action>> actions = {}) = 0;
};
std::unique_ptr<Node> make_node(const std::string& name,
const fs::path& script_path);
} // namespace libzork::story

View file

@ -0,0 +1,26 @@
#pragma once
#include <filesystem>
#include <libzork/story/node.hh>
#include <memory>
namespace fs = std::filesystem;
namespace libzork::story
{
class Story
{
public:
virtual ~Story() = default;
virtual const std::string& get_title() const = 0;
virtual const Node* get_current() const = 0;
virtual void set_current(const Node* node) = 0;
virtual const store::Store* get_store() const = 0;
virtual std::ostream& display(std::ostream& os) const = 0;
};
std::unique_ptr<Story> make_story(const fs::path& path);
} // namespace libzork::story

View file

@ -0,0 +1,21 @@
#pragma once
#include <libzork/store/store.hh>
#include <string>
namespace libzork::vars
{
class Action
{
public:
virtual ~Action() = default;
virtual void apply() const = 0;
};
std::unique_ptr<Action> make_action(store::Store& store,
const std::string& variable,
const std::string& action, int value);
} // namespace libzork::vars

View file

@ -0,0 +1,23 @@
#pragma once
#include <libzork/store/store.hh>
#include <memory>
#include <string>
namespace libzork::vars
{
class Condition
{
public:
virtual bool apply() const = 0;
virtual ~Condition() = default;
};
std::unique_ptr<Condition> make_condition(const store::Store& store,
const std::string& variable,
const std::string& comparison,
int value);
} // namespace libzork::vars

View file

@ -0,0 +1,6 @@
#include "exceptions.hh"
#include <string>
namespace libzork
{} // namespace libzork

View file

@ -0,0 +1,19 @@
#ifndef EXCEPTIONS_HH
#define EXCEPTIONS_HH
#include <stdexcept>
namespace libzork
{
class NotImplemented : public std::runtime_error
{
public:
NotImplemented(const char* file = __builtin_FILE(),
int line = __builtin_LINE())
: std::runtime_error(std::string{ "Unimplemented function: " }
+ file + ":" + std::to_string(line))
{}
};
} // namespace libzork
#endif // !EXCEPTIONS_HH

View file

@ -0,0 +1,19 @@
#include <libzork/runner/choice.hh>
#include "exceptions.hh"
#include "runner/choice_impl.hh"
namespace libzork::runner
{
std::unique_ptr<ChoiceRunner>
make_choice_runner(std::unique_ptr<story::Story> story, std::istream& is,
std::ostream& os)
{
(void)story;
(void)is;
(void)os;
throw NotImplemented();
}
} // namespace libzork::runner

View file

@ -0,0 +1,21 @@
#include "runner/choice_impl.hh"
#include <libzork/exceptions.hh>
#include <sstream>
#include "exceptions.hh"
namespace libzork::runner
{
void ChoiceRunnerImpl::print_script() const
{
throw NotImplemented();
}
void ChoiceRunnerImpl::process_input()
{
throw NotImplemented();
}
} // namespace libzork::runner

View file

@ -0,0 +1,19 @@
#ifndef CHOICE_IMPL_HH
#define CHOICE_IMPL_HH
#include <libzork/runner/choice.hh>
namespace libzork::runner
{
class ChoiceRunnerImpl : public ChoiceRunner
{
public:
~ChoiceRunnerImpl() override = default;
void print_script() const override;
void process_input() override;
};
} // namespace libzork::runner
#endif // !CHOICE_IMPL_HH

View file

@ -0,0 +1,18 @@
#include <libzork/runner/html.hh>
#include "exceptions.hh"
#include "runner/html_impl.hh"
namespace libzork::runner
{
std::unique_ptr<HTMLRunner>
make_html_runner(std::unique_ptr<story::Story> story,
const fs::path& output_dir)
{
(void)story;
(void)output_dir;
throw NotImplemented();
}
} // namespace libzork::runner

View file

@ -0,0 +1,13 @@
#include "runner/html_impl.hh"
#include "exceptions.hh"
namespace libzork::runner
{
void HTMLRunnerImpl::run()
{
throw NotImplemented();
}
} // namespace libzork::runner

View file

@ -0,0 +1,18 @@
#ifndef HTML_IMPL_HH
#define HTML_IMPL_HH
#include <libzork/runner/html.hh>
namespace libzork::runner
{
class HTMLRunnerImpl : public HTMLRunner
{
public:
~HTMLRunnerImpl() override = default;
void run() override;
};
} // namespace libzork::runner
#endif // !HTML_IMPL_HH

View file

@ -0,0 +1,26 @@
#include <libzork/exceptions.hh>
#include <libzork/runner/interactive.hh>
#include "exceptions.hh"
namespace libzork::runner
{
InteractiveRunner::InteractiveRunner(std::unique_ptr<story::Story> story,
std::istream& is, std::ostream& os)
: Runner(std::move(story))
, is_(is)
, os_(os)
{}
void InteractiveRunner::print_script() const
{
throw NotImplemented();
}
void InteractiveRunner::run()
{
throw NotImplemented();
}
} // namespace libzork::runner

View file

@ -0,0 +1,14 @@
#include <libzork/runner/runner.hh>
#include "exceptions.hh"
namespace libzork::runner
{
Runner::Runner(std::unique_ptr<story::Story> story)
{
(void)story;
throw NotImplemented();
}
} // namespace libzork::runner

View file

@ -0,0 +1,21 @@
#include <libzork/runner/smart.hh>
#include "exceptions.hh"
#include "runner/smart_impl.hh"
namespace libzork::runner
{
std::unique_ptr<SmartRunner>
make_smart_runner(std::unique_ptr<story::Story> story,
const fs::path& synonyms_path, std::istream& is,
std::ostream& os)
{
(void)story;
(void)synonyms_path;
(void)is;
(void)os;
throw NotImplemented();
}
} // namespace libzork::runner

View file

@ -0,0 +1,29 @@
#include "runner/smart_impl.hh"
#include "exceptions.hh"
namespace libzork::runner
{
void SmartRunnerImpl::process_input()
{
throw NotImplemented();
}
std::unordered_set<std::string>
SmartRunnerImpl::tokenize(const std::string& str) const
{
(void)str;
throw NotImplemented();
}
bool SmartRunnerImpl::has_unmatched_token(
const std::unordered_set<std::string>& user_tokens,
const std::unordered_set<std::string>& choice_tokens) const
{
(void)user_tokens;
(void)choice_tokens;
throw NotImplemented();
}
} // namespace libzork::runner

View file

@ -0,0 +1,22 @@
#ifndef SMART_IMPL_HH
#define SMART_IMPL_HH
#include <libzork/runner/smart.hh>
namespace libzork::runner
{
class SmartRunnerImpl : public SmartRunner
{
public:
void process_input() override;
virtual std::unordered_set<std::string>
tokenize(const std::string& str) const override;
virtual bool
has_unmatched_token(const std::unordered_set<std::string>& user_tokens,
const std::unordered_set<std::string>&
choice_tokens) const override;
};
} // namespace libzork::runner
#endif // !SMART_IMPL_HH

View file

@ -0,0 +1,14 @@
#include <libzork/store/store.hh>
#include "exceptions.hh"
#include "store/store_impl.hh"
namespace libzork::store
{
std::unique_ptr<Store> make_store()
{
throw NotImplemented();
}
} // namespace libzork::store

View file

@ -0,0 +1,43 @@
#include "store/store_impl.hh"
#include "exceptions.hh"
namespace libzork::store
{
const story::Node* StoreImpl::get_active_node() const
{
throw NotImplemented();
}
void StoreImpl::set_active_node(const story::Node* node)
{
(void)node;
throw NotImplemented();
}
bool StoreImpl::has_variable(const std::string& name) const
{
(void)name;
throw NotImplemented();
}
int StoreImpl::get_variable(const std::string& name) const
{
(void)name;
throw NotImplemented();
}
void StoreImpl::set_variable(const std::string& name, int value)
{
(void)name;
(void)value;
throw NotImplemented();
}
std::map<std::string, int> StoreImpl::get_inventory() const
{
throw NotImplemented();
}
} // namespace libzork::store

View file

@ -0,0 +1,24 @@
#ifndef STORE_IMPL_HH
#define STORE_IMPL_HH
#include <libzork/store/store.hh>
namespace libzork::store
{
class StoreImpl : public Store
{
public:
~StoreImpl() override = default;
const story::Node* get_active_node() const override;
void set_active_node(const story::Node* node) override;
bool has_variable(const std::string& name) const override;
int get_variable(const std::string& name) const override;
void set_variable(const std::string& name, int value) override;
std::map<std::string, int> get_inventory() const override;
};
} // namespace libzork::store
#endif // !STORE_IMPL_HH

View file

@ -0,0 +1,4 @@
#include "story/choice.hh"
namespace libzork::story
{} // namespace libzork::story

View file

@ -0,0 +1,11 @@
#ifndef CHOICE_HH
#define CHOICE_HH
namespace libzork::story
{
class Choice
{};
} // namespace libzork::story
#endif // !CHOICE_HH

View file

@ -0,0 +1,17 @@
#include <libzork/story/node.hh>
#include "exceptions.hh"
#include "story/node_impl.hh"
namespace libzork::story
{
std::unique_ptr<Node> make_node(const std::string& name,
const fs::path& script_path)
{
(void)name;
(void)script_path;
throw NotImplemented();
}
} // namespace libzork::story

View file

@ -0,0 +1,56 @@
#include "story/node_impl.hh"
#include <fstream>
#include "exceptions.hh"
namespace libzork::story
{
const std::string& NodeImpl::get_name() const
{
throw NotImplemented();
}
const std::string& NodeImpl::get_text() const
{
throw NotImplemented();
}
const Node* NodeImpl::get_choice(size_t index, bool check_conditions) const
{
(void)check_conditions;
(void)index;
throw NotImplemented();
}
std::vector<std::string> NodeImpl::list_choices(bool check_conditions) const
{
(void)check_conditions;
throw NotImplemented();
}
void NodeImpl::add_choice(
const Node* other, const std::string& text,
std::vector<std::unique_ptr<vars::Condition>> conditions,
std::vector<std::unique_ptr<vars::Action>> actions)
{
(void)other;
(void)text;
(void)conditions;
(void)actions;
throw NotImplemented();
}
const NodeImpl& to_impl(const Node& node)
{
(void)node;
throw NotImplemented();
}
NodeImpl& to_impl(Node& node)
{
(void)node;
throw NotImplemented();
}
} // namespace libzork::story

View file

@ -0,0 +1,31 @@
#ifndef NODE_IMPL_HH
#define NODE_IMPL_HH
#include <libzork/story/node.hh>
namespace libzork::story
{
class NodeImpl : public Node
{
public:
~NodeImpl() override = default;
const std::string& get_name() const override;
const std::string& get_text() const override;
const Node* get_choice(std::size_t index,
bool check_conditions = true) const override;
std::vector<std::string>
list_choices(bool check_conditions = true) const override;
void add_choice(
const Node* other, const std::string& text,
std::vector<std::unique_ptr<vars::Condition>> conditions = {},
std::vector<std::unique_ptr<vars::Action>> actions = {}) override;
};
const NodeImpl& to_impl(const Node& node);
NodeImpl& to_impl(Node& node);
} // namespace libzork::story
#endif // !NODE_IMPL_HH

View file

@ -0,0 +1,15 @@
#include <libzork/story/story.hh>
#include "exceptions.hh"
#include "story/story_impl.hh"
namespace libzork::story
{
std::unique_ptr<Story> make_story(const fs::path& path)
{
(void)path;
throw NotImplemented();
}
} // namespace libzork::story

View file

@ -0,0 +1,35 @@
#include "story/story_impl.hh"
#include "exceptions.hh"
namespace libzork::story
{
const std::string& StoryImpl::get_title() const
{
throw NotImplemented();
}
const Node* StoryImpl::get_current() const
{
throw NotImplemented();
}
void StoryImpl::set_current(const Node* node)
{
(void)node;
throw NotImplemented();
}
const store::Store* StoryImpl::get_store() const
{
throw NotImplemented();
}
std::ostream& StoryImpl::display(std::ostream& os) const
{
(void)os;
throw NotImplemented();
}
} // namespace libzork::story

View file

@ -0,0 +1,25 @@
#ifndef STORY_IMPL_HH
#define STORY_IMPL_HH
#include <libzork/story/story.hh>
namespace libzork::story
{
class StoryImpl : public Story
{
public:
~StoryImpl() override = default;
const std::string& get_title() const override;
const Node* get_current() const override;
void set_current(const Node* node) override;
const store::Store* get_store() const override;
std::ostream& display(std::ostream& os) const override;
};
const StoryImpl& to_impl(const Story& story);
StoryImpl& to_impl(Story& story);
} // namespace libzork::story
#endif // !STORY_IMPL_HH

View file

@ -0,0 +1,20 @@
#include <libzork/vars/action.hh>
#include "exceptions.hh"
#include "vars/action_impl.hh"
namespace libzork::vars
{
std::unique_ptr<Action> make_action(store::Store& store,
const std::string& variable,
const std::string& action, int value)
{
(void)store;
(void)variable;
(void)action;
(void)value;
throw NotImplemented();
}
} // namespace libzork::vars

View file

@ -0,0 +1,13 @@
#include "vars/action_impl.hh"
#include "exceptions.hh"
namespace libzork::vars
{
void ActionImpl::apply() const
{
throw NotImplemented();
}
} // namespace libzork::vars

View file

@ -0,0 +1,18 @@
#ifndef ACTION_IMPL_HH
#define ACTION_IMPL_HH
#include <libzork/vars/action.hh>
namespace libzork::vars
{
class ActionImpl : public Action
{
public:
~ActionImpl() override = default;
void apply() const override;
};
} // namespace libzork::vars
#endif // !ACTION_IMPL_HH

View file

@ -0,0 +1,21 @@
#include <libzork/store/store.hh>
#include <libzork/vars/condition.hh>
#include "exceptions.hh"
namespace libzork::vars
{
std::unique_ptr<Condition> make_condition(const store::Store& store,
const std::string& variable,
const std::string& comparison,
int value)
{
(void)store;
(void)variable;
(void)comparison;
(void)value;
throw NotImplemented();
}
} // namespace libzork::vars

View file

@ -0,0 +1,16 @@
#include "vars/condition_impl.hh"
#include <algorithm>
#include <map>
#include "exceptions.hh"
namespace libzork::vars
{
bool ConditionImpl::apply() const
{
throw NotImplemented();
}
} // namespace libzork::vars

View file

@ -0,0 +1,18 @@
#ifndef CONDITION_IMPL_HH
#define CONDITION_IMPL_HH
#include <libzork/vars/condition.hh>
namespace libzork::vars
{
class ConditionImpl : public Condition
{
public:
~ConditionImpl() override = default;
bool apply() const override;
};
} // namespace libzork::vars
#endif // !CONDITION_IMPL_HH

59
libzork/src/main.cc Normal file
View file

@ -0,0 +1,59 @@
#include <iostream>
#include <libzork/exceptions.hh>
#include <libzork/runner/choice.hh>
#include <libzork/runner/html.hh>
#include <libzork/runner/smart.hh>
#include "options.hh"
std::unique_ptr<libzork::story::Story> get_story(const Config& config)
{
return libzork::story::make_story(config.story_path);
}
std::unique_ptr<libzork::runner::Runner>
get_runner(const Config& config, std::unique_ptr<libzork::story::Story> story)
{
switch (config.story_type)
{
case StoryType::Choice:
return libzork::runner::make_choice_runner(std::move(story));
case StoryType::Smart:
return libzork::runner::make_smart_runner(std::move(story),
config.story_arg);
case StoryType::HTML:
return libzork::runner::make_html_runner(std::move(story),
config.story_arg);
default:
return nullptr;
}
}
int main(int argc, char** argv)
{
Config config;
try
{
config = parse_options(argc, argv);
}
catch (const std::invalid_argument& exc)
{
std::cerr << "invalid options: " << exc.what() << "\n";
return 1;
}
std::unique_ptr<libzork::runner::Runner> runner;
auto story = get_story(config);
story->display(std::cout);
// runner = get_runner(config, std::move(story));
//
// try
// {
// runner->run();
// }
// catch (const libzork::RunnerQuit&)
// {}
return 0;
}

57
libzork/src/options.cc Normal file
View file

@ -0,0 +1,57 @@
#include "options.hh"
#include <getopt.h>
#include <iostream>
namespace
{
constexpr option options[] = {
{ "story", required_argument, nullptr, 's' },
{ "smart", required_argument, nullptr, 'm' },
{ "html", required_argument, nullptr, 'h' },
};
std::string usage(const std::string& name)
{
return "usage: " + name
+ " (--story <story.yml>)"
" [--smart <synonyms.yml> | --html <directory/>]";
};
} // namespace
Config parse_options(int argc, char** argv)
{
Config config;
int opt;
while ((opt = getopt_long(argc, argv, "s:m:h:t:u:o:n:r:", options, nullptr))
!= -1)
{
switch (opt)
{
case 's': // --story
config.story_path = optarg;
break;
case 'm': // --smart
if (config.story_type == StoryType::HTML)
throw std::invalid_argument(
"incompatble options: `--smart` and `--html`");
config.story_type = StoryType::Smart;
config.story_arg = optarg;
break;
case 'h': // --html
if (config.story_type == StoryType::Smart)
throw std::invalid_argument(
"incompatible options: `--smart` and `--html`");
config.story_type = StoryType::HTML;
config.story_arg = optarg;
break;
default:
throw std::invalid_argument(usage(argv[0]));
}
};
if (config.story_path.empty())
throw std::invalid_argument("option '--story' is mandatory");
return config;
}

22
libzork/src/options.hh Normal file
View file

@ -0,0 +1,22 @@
#pragma once
#include <filesystem>
#include <optional>
namespace fs = std::filesystem;
enum class StoryType
{
Choice,
Smart,
HTML,
};
struct Config
{
std::filesystem::path story_path;
StoryType story_type = StoryType::Choice;
fs::path story_arg; /** Undefined if story_type is StoryType::BASIC */
};
Config parse_options(int argc, char** argv);

View file

@ -0,0 +1,3 @@
You enter the castle.
A large dragon blocks your path, preventing you from proceeding further.
A sword is on your left.

View file

@ -0,0 +1,3 @@
You enter the castle.
A large dragon blocks your path, preventing you from proceeding further.
To your right, there is a forge. Perhaps there are weapons there ?

View file

@ -0,0 +1,4 @@
You find yourself in a vast, lush forest.
In the distance, you spot a prince perched atop a tower of a castle.
He appears to be in desperate need of assistance.
To your right lies a house.

View file

@ -0,0 +1,2 @@
There is a bed, worn out from fatigue, you collapse onto it and take a nap.
The end.

View file

@ -0,0 +1,2 @@
You slay the dragon, climb the tower, and find the prince safe and sound.
The end.

View file

@ -0,0 +1 @@
This is a dark cave

View file

@ -0,0 +1 @@
This is a large forest

View file

@ -0,0 +1 @@
Hello, world!

View file

@ -0,0 +1,51 @@
title: A dynamic story
scripts-path: ../../scripts/little_quest
variables:
- name: health
value: 10
- name: sword_taken
value: 0
story:
- name: forest
script: forest.txt
choices:
- text: Enter the house
target: house
- text: Enter the castle
target: castle
- text: Eat a fruit
target: forest
actions:
- name: health
operation: add
value: 10
- name: house
script: house.txt
choices: []
- name: castle
script: castle_weapon.txt
choices:
- text: Flee
target: forest
- text: Take the sword
target: castle
conditions:
- name: sword_taken
comparison: equal
value: 0
actions:
- name: sword_taken
operation: add
value: 1
- text: Kill the dragon
target: tower
conditions:
- name: sword_taken
comparison: equal
value: 1
- name: health
comparison: greater
value: 10
- name: tower
script: tower.txt
choices: []

View file

@ -0,0 +1,25 @@
title: A long static story
scripts-path: ../../scripts/little_quest
story:
- name: forest
script: forest.txt
choices:
- text: Enter the house
target: house
- text: Enter the castle
target: castle
- text: Eat a fruit
target: forest
- name: house
script: house.txt
choices: []
- name: castle
script: castle.txt
choices:
- text: Flee
target: forest
- text: Kill the dragon
target: tower
- name: tower
script: tower.txt
choices: []

View file

@ -0,0 +1,16 @@
title: A short static story
scripts-path: ../../scripts/short_static
story:
- name: welcome
script: welcome.txt
choices:
- text: Explore the cave
target: cave
- text: Go in the forest
target: forest
- name: cave
script: cave.txt
choices: []
- name: forest
script: forest.txt
choices: []