1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-27 16:49:31 +00:00

Compare commits

..

No commits in common. "77c6ac6ba29daaa4d7e6b7c5888baf11c6ff68a9" and "ed7fe3485390c4e8f8ece45f488be24c1fb61840" have entirely different histories.

11 changed files with 70 additions and 425 deletions

View file

@ -5,56 +5,8 @@ local Event = ast.abstract.Event
local operator_priority = require("anselme.common").operator_priority
--- ChoiceEventData represent the data returned by an event with the type `"choice"`.
-- See the [language documentation](language.md#choices) for more details on how to create a choice event.
--
-- A ChoiceEventData contains a list of [LuaText](#luatext), each LuaText representing a separate choice of the choice event.
--
-- For example, the following Anselme script:
--
-- ```
-- *| Yes!
-- *| No.
-- ```
-- will return a choice event containing two LuaTexts, the first containing the text "Yes!" and the second "No.".
--
-- Usage:
-- ```lua
-- current_choice = nil
-- waiting_for_choice = false
--
-- -- in your anselem event handling loop:
-- if not waiting_for_choice then
-- local event_type, event_data = run_state:step()
-- if event_type == "choice" then
-- -- event_data is a ChoiceEventData, i.e. a list of LuaText
-- for i, luatext in ipairs(event_data) do
-- write(("Choice number %s:"):format(i))
-- -- luatext is a list of text parts { text = "text string", tags = { ... } }
-- for _, textpart in ipairs(luatext) do
-- write_choice_part_with_color(textpart.text, textpart.tags.color)
-- end
-- else
-- -- handle other event types...
-- end
-- current_choice = event_data
-- waiting_for_choice = true
-- end
-- end
--
-- -- somewhere in your code where choices are selected
-- current_choice:select(choice_number)
-- waiting_for_choice = false
-- ```
-- @title ChoiceEventData
local ChoiceEventData = class {
-- [1] = LuaText, ...
_selected = nil,
--- Choose the choice at position `choice` (number).
--
-- A choice must be selected after receiving a choice event and before calling `:step` again.
choose = function(self, choice)
self._selected = choice
end
@ -84,7 +36,7 @@ Choice = ast.abstract.Runtime(Event) {
build_event_data = function(self, state, event_buffer)
local l = ChoiceEventData:new()
for _, c in event_buffer:iter(state) do
table.insert(l, c.text:to_lua(state))
table.insert(l, c.text)
end
return l
end,

View file

@ -102,7 +102,7 @@ Struct = ast.abstract.Runtime {
to_lua = function(self, state)
local l = {}
for _, e in pairs(self.table) do
for _, e in ipairs(self.table) do
l[e[1]:to_lua(state)] = e[2]:to_lua(state)
end
return l

View file

@ -5,101 +5,16 @@ local ArgumentTuple, Struct
local to_anselme = require("anselme.common.to_anselme")
--- A Lua-friendly representation of an Anselme Text value.
-- They appear in both TextEventData and ChoiceEventData to represent the text that has to be shown.
--
-- It contains a list of _text parts_, which are parts of a single text, each part potentially having differrent tags attached.
-- A text will typically only consist of a single part unless it was built using text interpolation.
--
-- Each text part is a table containing `text` (string) and `tags` (table) properties, for example: `{ text = "text part string", tags = { color = "red" } }`.
-- @title LuaText
-- @defer lua text
local LuaText
LuaText = class {
-- [1] = { text = "string", tags = { tag_name = value, ... } }, ...
_state = nil,
--- Anselme Text value this was created from. For advanced usage only. See the source file [Text.lua](anselme/ast/Text.lua) for more information.
-- @defer lua text
raw = nil,
init = function(self, text, state)
self._state = state
self.raw = text
for _, e in ipairs(text.list) do
table.insert(self, { text = e[1]:to_lua(state), tags = e[2]:to_lua(state) })
end
end,
--- Returns a text representation of the LuaText, using Anselme's default formatting. Useful for debugging.
--
-- Usage: `print(luatext)`
-- @defer lua text
__tostring = function(self)
return self.raw:format(self._state)
end
}
--- TextEventData represent the data returned by an event with the type `"text"`.
-- See the [language documentation](language.md#texts) for more details on how to create a text event.
--
-- A TextEventData contains a list of [LuaText](#luatext), each LuaText representing a separate line of the text event.
--
-- For example, the following Anselme script:
--
-- ```
-- | Hi!
-- | My name's John.
-- ```
-- will return a text event containing two LuaTexts, the first containing the text "Hi!" and the second "My name's John.".
--
-- Usage:
-- ```lua
-- local event_type, event_data = run_state:step()
-- if event_type == "text" then
-- -- event_data is a TextEventData, i.e. a list of LuaText
-- for _, luatext in ipairs(event_data) do
-- -- luatext is a list of text parts { text = "text string", tags = { ... } }
-- for _, textpart in ipairs(luatext) do
-- write_text_part_with_color(textpart.text, textpart.tags.color)
-- end
-- write_text("\n") -- for example, if we want a newline between each text line
-- end
-- else
-- -- handle other event types...
-- end
-- ```
-- @title TextEventData
local TextEventData
TextEventData = class {
-- [1] = LuaText, ...
--- Returns a list of TextEventData where the first part of each LuaText of each TextEventData has the same value for the tag `tag_name`.
--
-- In other words, this groups all the LuaTexts contained in this TextEventData using the `tag_name` tag and returns a list containing these groups.
--
-- For example, with the following Anselme script:
-- ```
-- speaker: "John" #
-- | A
-- | B
-- speaker: "Lana" #
-- | C
-- speaker: "John" #
-- | D
-- ```
-- calling `text_event_data:group_by("speaker")` will return a list of three TextEventData:
-- * the first with the texts "A" and "B"; both with the tag `speaker="John"`
-- * the second with the text "C"; with the tag `speaker="Lana"`
-- * the last with the text "D"; wiith the tag `speaker="John"`
-- returns a list of TextEventData where the first element of each text of each TextEventData has the same value for the tag tag_name
group_by = function(self, tag_name)
local l = {}
local current_group
local tag_key = to_anselme(tag_name)
local last_value
for _, luatext in ipairs(self) do
local list = luatext.raw.list
for _, event in ipairs(self) do
local list = event.list
if #list > 0 then
local value = list[1][2]:get_strict(tag_key)
if (not current_group) or (last_value == nil and value) or (last_value and value == nil) or (last_value and value and last_value:hash() ~= value:hash()) then -- new group
@ -107,11 +22,11 @@ TextEventData = class {
table.insert(l, current_group)
last_value = value
end
table.insert(current_group, luatext) -- add to current group
table.insert(current_group, event) -- add to current group
end
end
return l
end
end,
}
local Text
@ -153,10 +68,6 @@ Text = Runtime(Event) {
return ("| %s |"):format(table.concat(t, " "))
end,
to_lua = function(self, state)
return LuaText:new(self, state)
end,
-- autocall when used directly as a statement
eval_statement = function(self, state)
return self:call(state, ArgumentTuple:new())
@ -166,8 +77,8 @@ Text = Runtime(Event) {
build_event_data = function(self, state, event_buffer)
local l = TextEventData:new()
for _, text in event_buffer:iter(state) do
table.insert(l, text:to_lua(state))
for _, event in event_buffer:iter(state) do
table.insert(l, event)
end
return l
end,

View file

@ -13,20 +13,25 @@
-- local state = anselme.new()
-- state:load_stdlib()
--
-- -- load an anselme script file in a new branch
-- -- read an anselme script file
-- local f = assert(io.open("script.ans"))
-- local script = anselme.parse(f:read("a"), "script.ans")
-- f:close()
--
-- -- load the script in a new branch
-- local run_state = state:branch()
-- run_state:run_file("script.ans")
-- run_state:run(script)
--
-- -- run the script
-- while run_state:active() do
-- local e, data = run_state:step()
-- if e == "text" then
-- for _, l in ipairs(data) do
-- print(l)
-- print(l:format(run_state))
-- end
-- elseif e == "choice" then
-- for i, l in ipairs(data) do
-- print(("%s> %s"):format(i, l))
-- print(("%s> %s"):format(i, l:format(run_state)))
-- end
-- local choice = tonumber(io.read("l"))
-- data:choose(choice)

View file

@ -1,6 +1,5 @@
local expression_to_ast = require("anselme.parser.expression.to_ast")
local utf8 = utf8 or require("lua-utf8")
local ast = require("anselme.ast")
local PartialScope, Block, Call, Identifier = ast.PartialScope, ast.Block, ast.Call, ast.Identifier

View file

@ -7,11 +7,11 @@ local tag_manager = require("anselme.state.tag_manager")
local event_manager = require("anselme.state.event_manager")
local translation_manager = require("anselme.state.translation_manager")
local persistent_manager = require("anselme.state.persistent_manager")
local uuid = require("anselme.common").uuid
local parser = require("anselme.parser")
local binser = require("anselme.lib.binser")
local common = require("anselme.common")
local uuid, assert0, operator_priority = common.uuid, common.assert0, common.operator_priority
local to_anselme = require("anselme.common.to_anselme")
local assert0 = require("anselme.common").assert0
local operator_priority = require("anselme.common").operator_priority
local anselme
local Identifier, Return, Node
@ -178,13 +178,12 @@ State = class {
--- Load a script in this branch. It will become the active script.
--
-- `code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
-- `tags` is an optional Lua table; its content will be added to the tags for the duration of the script.
--
-- Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State.
run = function(self, code, source, tags)
run = function(self, code, source)
assert(not self:active(), "a script is already active")
self._coroutine = coroutine.create(function()
local r = assert0(self:eval_local(code, source, tags))
local r = assert0(self:eval_local(code, source))
event_manager:complete_flush(self)
if Return:is(r) then r = r.expression end
return "return", r
@ -192,19 +191,17 @@ State = class {
end,
--- Same as `:run`, but read the code from a file.
-- `source` will be set as the file path.
run_file = function(self, path, tags)
run_file = function(self, path)
local f = assert(io.open(path, "r"))
local block = parser(f:read("a"), path)
f:close()
return self:run(block, nil, tags)
return self:run(block)
end,
--- When a script is active, will resume running it until the next event.
--
-- Will error if no script is active.
--
-- Returns `event type string, event data`.
--
-- See the [events](#events) section for details on event data types for built-in events.
step = function(self)
assert(self:active(), "trying to step but no script is currently active")
local success, type, data = coroutine.resume(self._coroutine)
@ -221,17 +218,16 @@ State = class {
--
-- Will error if no script is active.
--
-- `code`, `source` and `tags` are all optional and have the same behaviour as in `:run`.
-- If they are given, the script will not be disabled but instead will be immediately replaced with this new script.
-- If `code` is given, the script will not be disabled but instead will be immediately replaced with this new script.
-- The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script.
--
-- If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution.
interrupt = function(self, code, source, tags)
interrupt = function(self, code, source)
assert(self:active(), "trying to interrupt but no script is currently active")
local called_from_script = self:state() == "running"
if code then
self._coroutine = coroutine.create(function()
local r = assert0(self:eval_local(code, source, tags))
local r = assert0(self:eval_local(code, source))
event_manager:complete_flush(self)
self.scope:reset() -- scope stack is probably messed up after the switch
if Return:is(r) then r = r.expression end
@ -248,24 +244,19 @@ State = class {
--
-- This can be called from outside a running script, but an error will be triggered the expression raise any event other than return.
--
-- `code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
-- `tags` is an optional Lua table; its content will be added to the tags for the duration of the expression.
--
-- * returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value.
-- * returns `nil, error message` in case of error.
eval = function(self, code, source, tags)
eval = function(self, code, source)
self.scope:push_global()
local r, e = self:eval_local(code, source, tags)
local r, e = self:eval_local(code, source)
self.scope:pop()
return r, e
end,
--- Same as `:eval`, but evaluate the expression in the current scope.
eval_local = function(self, code, source, tags)
eval_local = function(self, code, source)
if type(code) == "string" then code = parser(code, source) end
local stack_size = self.scope:size()
if tags then tag_manager:push(self, to_anselme(tags)) end
local s, e = pcall(code.eval, code, self)
if tags then tag_manager:pop(self) end
if not s then
self.scope:reset(stack_size)
return nil, e

View file

@ -56,7 +56,7 @@ return [[
:@arrondi = stdlib.round
:@aléatoire = stdlib.rand
:@est égal = stdlib.is equal
:@égal = stdlib.equal
:@est = stdlib.is
:@est une ancre = stdlib.is anchor
:@est un booléen = stdlib.is boolean

View file

@ -1,6 +1,6 @@
This document describes how to use the main Anselme modules. This is generated automatically from the source files.
Note that this file only describes the `anselme` and `state.State` modules, as well as the `TextEventData` and `ChoiceEventData` classes, which are only a selection of what I consider to be the "public API" of Anselme that I will try to keep stable.
Note that this file only describes the `anselme` and `state.State` modules, which are only a selection of what I consider to be the "public API" of Anselme that I will try to keep stable.
If you need more advanced control on Anselme, feel free to look into the other source files to find more; the most useful functions should all be reasonably commented.
# anselme
@ -15,20 +15,25 @@ local anselme = require("anselme")
local state = anselme.new()
state:load_stdlib()
-- load an anselme script file in a new branch
-- read an anselme script file
local f = assert(io.open("script.ans"))
local script = anselme.parse(f:read("a"), "script.ans")
f:close()
-- load the script in a new branch
local run_state = state:branch()
run_state:run_file("script.ans")
run_state:run(script)
-- run the script
while run_state:active() do
local e, data = run_state:step()
if e == "text" then
for _, l in ipairs(data) do
print(l)
print(l:format(run_state))
end
elseif e == "choice" then
for i, l in ipairs(data) do
print(("%s> %s"):format(i, l))
print(("%s> %s"):format(i, l:format(run_state)))
end
local choice = tonumber(io.read("l"))
data:choose(choice)
@ -51,31 +56,31 @@ Anselme expects that `require("anselme.module")` will try loading both `anselme/
Global version string. Follow semver.
_defined at line 53 of [anselme/init.lua](../anselme/init.lua):_ `version = "2.0.0-rc1",`
_defined at line 58 of [anselme/init.lua](../anselme/init.lua):_ `version = "2.0.0-rc1",`
### .versions
Table containing per-category version numbers. Incremented by one for any change that may break compatibility.
_defined at line 56 of [anselme/init.lua](../anselme/init.lua):_ `versions = {`
_defined at line 61 of [anselme/init.lua](../anselme/init.lua):_ `versions = {`
#### .language
Version number for language and standard library changes.
_defined at line 58 of [anselme/init.lua](../anselme/init.lua):_ `language = 31,`
_defined at line 63 of [anselme/init.lua](../anselme/init.lua):_ `language = 31,`
#### .save
Version number for save/AST format changes.
_defined at line 60 of [anselme/init.lua](../anselme/init.lua):_ `save = 7,`
_defined at line 65 of [anselme/init.lua](../anselme/init.lua):_ `save = 7,`
#### .api
Version number for Lua API changes.
_defined at line 62 of [anselme/init.lua](../anselme/init.lua):_ `api = 10`
_defined at line 67 of [anselme/init.lua](../anselme/init.lua):_ `api = 10`
### .parse (code, source)
@ -89,14 +94,14 @@ local ast = anselme.parse("1 + 2", "test")
ast:eval(state)
```
_defined at line 74 of [anselme/init.lua](../anselme/init.lua):_ `parse = function(code, source)`
_defined at line 79 of [anselme/init.lua](../anselme/init.lua):_ `parse = function(code, source)`
### .parse_file (path)
Same as `:parse`, but reads the code from a file.
`source` will be set as the file path.
_defined at line 79 of [anselme/init.lua](../anselme/init.lua):_ `parse_file = function(path)`
_defined at line 84 of [anselme/init.lua](../anselme/init.lua):_ `parse_file = function(path)`
### .generate_translation_template (code, source)
@ -104,20 +109,20 @@ Generates and return Anselme code (as a string) that can be used as a base for a
This will include every translatable element found in this code.
`source` is an optional string; it will be used as the code source name in translation contexts.
_defined at line 88 of [anselme/init.lua](../anselme/init.lua):_ `generate_translation_template = function(code, source)`
_defined at line 93 of [anselme/init.lua](../anselme/init.lua):_ `generate_translation_template = function(code, source)`
### .generate_translation_template_file (path)
Same as `:generate_translation_template`, but reads the code from a file.
`source` will be set as the file path.
_defined at line 93 of [anselme/init.lua](../anselme/init.lua):_ `generate_translation_template_file = function(path)`
_defined at line 98 of [anselme/init.lua](../anselme/init.lua):_ `generate_translation_template_file = function(path)`
### .new ()
Return a new [State](#state).
_defined at line 97 of [anselme/init.lua](../anselme/init.lua):_ `new = function()`
_defined at line 102 of [anselme/init.lua](../anselme/init.lua):_ `new = function()`
# State
@ -244,23 +249,22 @@ Returns `"inactive"` if no script is loaded.
_defined at line 171 of [anselme/state/State.lua](../anselme/state/State.lua):_ `state = function(self)`
### :run (code, source, tags)
### :run (code, source)
Load a script in this branch. It will become the active script.
`code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
`tags` is an optional Lua table; its content will be added to the tags for the duration of the script.
Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State.
_defined at line 184 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run = function(self, code, source, tags)`
_defined at line 183 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run = function(self, code, source)`
### :run_file (path, tags)
### :run_file (path)
Same as `:run`, but read the code from a file.
`source` will be set as the file path.
_defined at line 195 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run_file = function(self, path, tags)`
_defined at line 194 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run_file = function(self, path)`
### :step ()
@ -270,218 +274,42 @@ Will error if no script is active.
Returns `event type string, event data`.
See the [events](#events) section for details on event data types for built-in events.
_defined at line 205 of [anselme/state/State.lua](../anselme/state/State.lua):_ `step = function(self)`
_defined at line 208 of [anselme/state/State.lua](../anselme/state/State.lua):_ `step = function(self)`
### :interrupt (code, source, tags)
### :interrupt (code, source)
Stops the currently active script.
Will error if no script is active.
`code`, `source` and `tags` are all optional and have the same behaviour as in `:run`.
If they are given, the script will not be disabled but instead will be immediately replaced with this new script.
If `code` is given, the script will not be disabled but instead will be immediately replaced with this new script.
The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script.
If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution.
_defined at line 229 of [anselme/state/State.lua](../anselme/state/State.lua):_ `interrupt = function(self, code, source, tags)`
_defined at line 225 of [anselme/state/State.lua](../anselme/state/State.lua):_ `interrupt = function(self, code, source)`
### :eval (code, source, tags)
### :eval (code, source)
Evaluate an expression in the global scope.
This can be called from outside a running script, but an error will be triggered the expression raise any event other than return.
`code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
`tags` is an optional Lua table; its content will be added to the tags for the duration of the expression.
* returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value.
* returns `nil, error message` in case of error.
_defined at line 256 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval = function(self, code, source, tags)`
_defined at line 249 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval = function(self, code, source)`
### :eval_local (code, source, tags)
### :eval_local (code, source)
Same as `:eval`, but evaluate the expression in the current scope.
_defined at line 263 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval_local = function(self, code, source, tags)`
_defined at line 256 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval_local = function(self, code, source)`
If you want to perform more advanced manipulation of the resulting AST nodes, look at the `ast` modules.
In particular, every Node inherits the methods from [ast.abstract.Node](../ast/abstract/Node.lua).
Otherwise, each Node has its own module file defined in the [ast/](../ast) directory.
# Events
Anselme scripts communicate with the game by sending events. See the [language documentation](language.md#events) for more details on events.
Custom events can be defined; to do so, simply yield the coroutine with your custom event type (using `coroutine.yield("event type", event_data)`) from a function called in the anselme script.
For example, to add a `wait` event that pauses the script for some time, you could do something along these lines:
```lua
state:define("wait", "(duration::is number)", function(duration) coroutine.yield("wait", duration) end)
waiting = false
-- and edit your Anselme event handler with something like:
if not waiting then
local event_type, event_data = run_state = run_state:step()
if e == "wait" then
waiting = true
call_after_duration(event_data, function() waiting = false end)
else
-- handle other event types...
end
end
```
And then from your Anselme script:
```
| Hello...
---
wait(5)
| ...world !
```
## TextEventData
TextEventData represent the data returned by an event with the type `"text"`.
See the [language documentation](language.md#texts) for more details on how to create a text event.
A TextEventData contains a list of [LuaText](#luatext), each LuaText representing a separate line of the text event.
For example, the following Anselme script:
```
| Hi!
| My name's John.
```
will return a text event containing two LuaTexts, the first containing the text "Hi!" and the second "My name's John.".
Usage:
```lua
local event_type, event_data = run_state:step()
if event_type == "text" then
-- event_data is a TextEventData, i.e. a list of LuaText
for _, luatext in ipairs(event_data) do
-- luatext is a list of text parts { text = "text string", tags = { ... } }
for _, textpart in ipairs(luatext) do
write_text_part_with_color(textpart.text, textpart.tags.color)
end
write_text("\n") -- for example, if we want a newline between each text line
end
else
-- handle other event types...
end
```
_defined at line 74 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `local TextEventData`
### :group_by (tag_name)
Returns a list of TextEventData where the first part of each LuaText of each TextEventData has the same value for the tag `tag_name`.
In other words, this groups all the LuaTexts contained in this TextEventData using the `tag_name` tag and returns a list containing these groups.
For example, with the following Anselme script:
```
speaker: "John" #
| A
| B
speaker: "Lana" #
| C
speaker: "John" #
| D
```
calling `text_event_data:group_by("speaker")` will return a list of three TextEventData:
* the first with the texts "A" and "B"; both with the tag `speaker="John"`
* the second with the text "C"; with the tag `speaker="Lana"`
* the last with the text "D"; wiith the tag `speaker="John"`
_defined at line 96 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `group_by = function(self, tag_name)`
## ChoiceEventData
ChoiceEventData represent the data returned by an event with the type `"choice"`.
See the [language documentation](language.md#choices) for more details on how to create a choice event.
A ChoiceEventData contains a list of [LuaText](#luatext), each LuaText representing a separate choice of the choice event.
For example, the following Anselme script:
```
*| Yes!
*| No.
```
will return a choice event containing two LuaTexts, the first containing the text "Yes!" and the second "No.".
Usage:
```lua
current_choice = nil
waiting_for_choice = false
-- in your anselem event handling loop:
if not waiting_for_choice then
local event_type, event_data = run_state:step()
if event_type == "choice" then
-- event_data is a ChoiceEventData, i.e. a list of LuaText
for i, luatext in ipairs(event_data) do
write(("Choice number %s:"):format(i))
-- luatext is a list of text parts { text = "text string", tags = { ... } }
for _, textpart in ipairs(luatext) do
write_choice_part_with_color(textpart.text, textpart.tags.color)
end
else
-- handle other event types...
end
current_choice = event_data
waiting_for_choice = true
end
end
-- somewhere in your code where choices are selected
current_choice:select(choice_number)
waiting_for_choice = false
```
_defined at line 50 of [anselme/ast/Choice.lua](../anselme/ast/Choice.lua):_ `local ChoiceEventData = class {`
### :choose (choice)
Choose the choice at position `choice` (number).
A choice must be selected after receiving a choice event and before calling `:step` again.
_defined at line 58 of [anselme/ast/Choice.lua](../anselme/ast/Choice.lua):_ `choose = function(self, choice)`
## LuaText
A Lua-friendly representation of an Anselme Text value.
They appear in both TextEventData and ChoiceEventData to represent the text that has to be shown.
It contains a list of _text parts_, which are parts of a single text, each part potentially having differrent tags attached.
A text will typically only consist of a single part unless it was built using text interpolation.
Each text part is a table containing `text` (string) and `tags` (table) properties, for example: `{ text = "text part string", tags = { color = "red" } }`.
_defined at line 17 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `local LuaText`
### .raw
Anselme Text value this was created from. For advanced usage only. See the source file [Text.lua](anselme/ast/Text.lua) for more information.
_defined at line 25 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `raw = nil,`
### :__tostring ()
Returns a text representation of the LuaText, using Anselme's default formatting. Useful for debugging.
Usage: `print(luatext)`
_defined at line 39 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `__tostring = function(self)`
---
_file generated at 2024-11-11T13:33:43Z_
_file generated at 2024-11-09T17:00:43Z_

View file

@ -1,6 +1,6 @@
This document describes how to use the main Anselme modules. This is generated automatically from the source files.
Note that this file only describes the `anselme` and `state.State` modules, as well as the `TextEventData` and `ChoiceEventData` classes, which are only a selection of what I consider to be the "public API" of Anselme that I will try to keep stable.
Note that this file only describes the `anselme` and `state.State` modules, which are only a selection of what I consider to be the "public API" of Anselme that I will try to keep stable.
If you need more advanced control on Anselme, feel free to look into the other source files to find more; the most useful functions should all be reasonably commented.
# anselme
@ -10,40 +10,3 @@ If you need more advanced control on Anselme, feel free to look into the other s
# State
{{anselme/state/State.lua}}
# Events
Anselme scripts communicate with the game by sending events. See the [language documentation](language.md#events) for more details on events.
Custom events can be defined; to do so, simply yield the coroutine with your custom event type (using `coroutine.yield("event type", event_data)`) from a function called in the anselme script.
For example, to add a `wait` event that pauses the script for some time, you could do something along these lines:
```lua
state:define("wait", "(duration::is number)", function(duration) coroutine.yield("wait", duration) end)
waiting = false
-- and edit your Anselme event handler with something like:
if not waiting then
local event_type, event_data = run_state = run_state:step()
if e == "wait" then
waiting = true
call_after_duration(event_data, function() waiting = false end)
else
-- handle other event types...
end
end
```
And then from your Anselme script:
```
| Hello...
---
wait(5)
| ...world !
```
{{anselme/ast/Text.lua}}
{{anselme/ast/Choice.lua}}
{{:lua text}}

View file

@ -887,8 +887,6 @@ A text event value can be created using the [text literal](#text). A text is wri
text!
```
How the data returned by a Text event is structured is detailled in the [API documentation](api.md#texteventdata).
### Choices
Choice events are intended to represent a player choice in the host game. Each choice event in the buffer list is intended to represent a distinct choice.
@ -904,8 +902,6 @@ A choice event can be written to the buffer using the `*_` operator on a text ev
| Choice B has been selected.
```
How the data returned by a Text event is structured is detailled in the [API documentation](api.md#choiceeventdata).
### Tags
Text and choice events can also carry metadata through tags. Tags are stored as a [struct](#struct).

View file

@ -38,14 +38,14 @@ local function run_loop(run_state, write_output, interactive)
for _, v in ipairs(grouped) do
if groups then write_output(":: group ::") end
for _, l in ipairs(v) do
write_output(l.raw:format(run_state))
write_output(l:format(run_state))
end
end
elseif e == "choice" then
local choice
if interactive then
for i, l in ipairs(data) do
write_output(("%s> %s"):format(i, l.raw:format(run_state)))
write_output(("%s> %s"):format(i, l:format(run_state)))
end
io.write(("Select choice (1-%s): "):format(#data))
choice = tonumber(io.read("l"))
@ -53,9 +53,9 @@ local function run_loop(run_state, write_output, interactive)
choice = assert(run_state:eval_local("choice"), "no choice selected"):to_lua()
for i, l in ipairs(data) do
if i == choice then
write_output(("=> %s"):format(l.raw:format(run_state)))
write_output(("=> %s"):format(l:format(run_state)))
else
write_output((" > %s"):format(l.raw:format(run_state)))
write_output((" > %s"):format(l:format(run_state)))
end
end
end