Vendor libs/hump, sfxrlua, json4lua, narrator as real files
These were committed as empty submodule gitlinks with no .gitmodules, so the folders were never populated and the game could not load (require of libs/hump/timer, libs/sfxrlua/sfxr, narrator.narrator). Checked out each at its pinned commit and vendored the files, matching the existing bundled-libs convention. Removed the junk libs/libs/ tree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e73f63b5d4
commit
03532d29e4
219 changed files with 20254 additions and 252 deletions
19
libs/narrator/example-defold/book.ink
Normal file
19
libs/narrator/example-defold/book.ink
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
- I looked at Monsieur Fogg
|
||||
* ... and I could contain myself no longer.
|
||||
'What is the purpose of our journey, Monsieur?'
|
||||
'A wager,' he replied.
|
||||
* * 'A wager!'[] I returned.
|
||||
He nodded.
|
||||
* * * 'But surely that is foolishness!'
|
||||
* * * 'A most serious matter then!'
|
||||
- - - He nodded again.
|
||||
* * * 'But can we win?'
|
||||
'That is what we will endeavour to find out,' he answered.
|
||||
* * * 'A modest wager, I trust?'
|
||||
'Twenty thousand pounds,' he replied, quite flatly.
|
||||
* * * I asked nothing further of him then[.], and after a final, polite cough, he offered nothing more to me. <>
|
||||
* * 'Ah[.'],' I replied, uncertain what I thought.
|
||||
- - After that, <>
|
||||
* ... but I said nothing[] and <>
|
||||
- we passed the day in silence.
|
||||
- -> END
|
||||
39
libs/narrator/example-defold/examlpe.collection
Normal file
39
libs/narrator/example-defold/examlpe.collection
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
name: "main"
|
||||
scale_along_z: 0
|
||||
embedded_instances {
|
||||
id: "example"
|
||||
data: "components {\n"
|
||||
" id: \"example\"\n"
|
||||
" component: \"/example-defold/example.gui\"\n"
|
||||
" position {\n"
|
||||
" x: 0.0\n"
|
||||
" y: 0.0\n"
|
||||
" z: 0.0\n"
|
||||
" }\n"
|
||||
" rotation {\n"
|
||||
" x: 0.0\n"
|
||||
" y: 0.0\n"
|
||||
" z: 0.0\n"
|
||||
" w: 1.0\n"
|
||||
" }\n"
|
||||
" property_decls {\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
""
|
||||
position {
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.0
|
||||
}
|
||||
rotation {
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
scale3 {
|
||||
x: 1.0
|
||||
y: 1.0
|
||||
z: 1.0
|
||||
}
|
||||
}
|
||||
17
libs/narrator/example-defold/example.font
Normal file
17
libs/narrator/example-defold/example.font
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
font: "/builtins/fonts/vera_mo_bd.ttf"
|
||||
material: "/builtins/fonts/font.material"
|
||||
size: 32
|
||||
antialias: 1
|
||||
alpha: 1.0
|
||||
outline_alpha: 0.0
|
||||
outline_width: 0.0
|
||||
shadow_alpha: 0.0
|
||||
shadow_blur: 0
|
||||
shadow_x: 0.0
|
||||
shadow_y: 0.0
|
||||
extra_characters: ""
|
||||
output_format: TYPE_BITMAP
|
||||
all_chars: false
|
||||
cache_width: 0
|
||||
cache_height: 0
|
||||
render_mode: MODE_SINGLE_LAYER
|
||||
146
libs/narrator/example-defold/example.gui
Normal file
146
libs/narrator/example-defold/example.gui
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
script: "/example-defold/example.gui_script"
|
||||
fonts {
|
||||
name: "example"
|
||||
font: "/example-defold/example.font"
|
||||
}
|
||||
background_color {
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.0
|
||||
w: 0.0
|
||||
}
|
||||
nodes {
|
||||
position {
|
||||
x: 320.0
|
||||
y: 340.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
rotation {
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
scale {
|
||||
x: 0.5
|
||||
y: 0.5
|
||||
z: 0.5
|
||||
w: 1.0
|
||||
}
|
||||
size {
|
||||
x: 800.0
|
||||
y: 0.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
color {
|
||||
x: 0.102
|
||||
y: 0.102
|
||||
z: 0.102
|
||||
w: 1.0
|
||||
}
|
||||
type: TYPE_TEXT
|
||||
blend_mode: BLEND_MODE_ALPHA
|
||||
text: "paragraph"
|
||||
font: "example"
|
||||
id: "paragraph"
|
||||
xanchor: XANCHOR_NONE
|
||||
yanchor: YANCHOR_NONE
|
||||
pivot: PIVOT_N
|
||||
outline {
|
||||
x: 1.0
|
||||
y: 1.0
|
||||
z: 1.0
|
||||
w: 1.0
|
||||
}
|
||||
shadow {
|
||||
x: 1.0
|
||||
y: 1.0
|
||||
z: 1.0
|
||||
w: 1.0
|
||||
}
|
||||
adjust_mode: ADJUST_MODE_FIT
|
||||
line_break: true
|
||||
layer: ""
|
||||
inherit_alpha: true
|
||||
alpha: 1.0
|
||||
outline_alpha: 1.0
|
||||
shadow_alpha: 1.0
|
||||
template_node_child: false
|
||||
text_leading: 1.0
|
||||
text_tracking: 0.0
|
||||
custom_type: 0
|
||||
enabled: false
|
||||
visible: true
|
||||
material: ""
|
||||
}
|
||||
nodes {
|
||||
position {
|
||||
x: 320.0
|
||||
y: 300.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
rotation {
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
scale {
|
||||
x: 0.5
|
||||
y: 0.5
|
||||
z: 0.5
|
||||
w: 1.0
|
||||
}
|
||||
size {
|
||||
x: 800.0
|
||||
y: 0.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
color {
|
||||
x: 0.6
|
||||
y: 0.2
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
type: TYPE_TEXT
|
||||
blend_mode: BLEND_MODE_ALPHA
|
||||
text: "choice"
|
||||
font: "example"
|
||||
id: "choice"
|
||||
xanchor: XANCHOR_NONE
|
||||
yanchor: YANCHOR_NONE
|
||||
pivot: PIVOT_N
|
||||
outline {
|
||||
x: 1.0
|
||||
y: 1.0
|
||||
z: 1.0
|
||||
w: 1.0
|
||||
}
|
||||
shadow {
|
||||
x: 1.0
|
||||
y: 1.0
|
||||
z: 1.0
|
||||
w: 1.0
|
||||
}
|
||||
adjust_mode: ADJUST_MODE_FIT
|
||||
line_break: true
|
||||
layer: ""
|
||||
inherit_alpha: true
|
||||
alpha: 1.0
|
||||
outline_alpha: 1.0
|
||||
shadow_alpha: 1.0
|
||||
template_node_child: false
|
||||
text_leading: 1.0
|
||||
text_tracking: 0.0
|
||||
custom_type: 0
|
||||
enabled: false
|
||||
visible: true
|
||||
material: ""
|
||||
}
|
||||
material: "/builtins/materials/gui.material"
|
||||
adjust_reference: ADJUST_REFERENCE_PARENT
|
||||
max_nodes: 512
|
||||
167
libs/narrator/example-defold/example.gui_script
Normal file
167
libs/narrator/example-defold/example.gui_script
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
local narrator = require('narrator.narrator')
|
||||
|
||||
---@class Self
|
||||
---@field paragraph_template node
|
||||
---@field paragraph_initial_position vector3
|
||||
---@field paragraph_nodes node[]
|
||||
---@field choice_template node
|
||||
---@field choice_initial_position vector3
|
||||
---@field choice_nodes node[]
|
||||
---@field book Narrator.Book
|
||||
---@field story Narrator.Story
|
||||
|
||||
---@param node node
|
||||
---@param text string
|
||||
---@return integer height
|
||||
local function estimated_height(node, text)
|
||||
local font_name = gui.get_font(node)
|
||||
local font = gui.get_font_resource(font_name)
|
||||
|
||||
local metrics = resource.get_text_metrics(font, text, {
|
||||
width = gui.get_size(node).x,
|
||||
line_break = true
|
||||
})
|
||||
|
||||
return metrics.height
|
||||
end
|
||||
|
||||
---@param self Self
|
||||
local function clear_output(self)
|
||||
for index = #self.paragraph_nodes, 1, -1 do
|
||||
local node = self.paragraph_nodes[index]
|
||||
table.remove(self.paragraph_nodes, index)
|
||||
|
||||
gui.animate(node, 'color.w', 0, gui.EASING_LINEAR, 0.5, 0, function(_, node)
|
||||
gui.delete_node(node)
|
||||
end)
|
||||
end
|
||||
|
||||
for index = #self.choice_nodes, 1, -1 do
|
||||
local node = self.choice_nodes[index]
|
||||
table.remove(self.choice_nodes, index)
|
||||
|
||||
gui.animate(node, 'color.w', 0, gui.EASING_LINEAR, 0.5, 0, function(_, node)
|
||||
gui.delete_node(node)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
---@param self Self
|
||||
local function display_output(self)
|
||||
clear_output(self)
|
||||
|
||||
-- Pull all the paragraphs
|
||||
local paragraphs = self.story:continue()
|
||||
|
||||
-- Get the available choices
|
||||
local choices = self.story:get_choices()
|
||||
|
||||
local paragraph_position = vmath.vector3(self.paragraph_initial_position)
|
||||
local choice_position = vmath.vector3(self.choice_initial_position)
|
||||
|
||||
for index = #paragraphs, 1, -1 do
|
||||
local paragraph = paragraphs[index]
|
||||
local node = gui.clone(self.paragraph_template)
|
||||
gui.set_text(node, paragraph.text)
|
||||
|
||||
local height = estimated_height(node, paragraph.text)
|
||||
if index < #paragraphs then
|
||||
paragraph_position.y = paragraph_position.y + height / 2 + 16
|
||||
end
|
||||
|
||||
gui.set_position(node, paragraph_position)
|
||||
gui.set_enabled(node, true)
|
||||
gui.set_alpha(node, 0)
|
||||
gui.animate(node, 'color.w', 1, go.EASING_LINEAR, 0.5, index / 2)
|
||||
|
||||
table.insert(self.paragraph_nodes, node)
|
||||
end
|
||||
|
||||
for index = 1, #choices do
|
||||
local choice = choices[index]
|
||||
local node = gui.clone(self.choice_template)
|
||||
gui.set_text(node, choice.text)
|
||||
|
||||
local height = estimated_height(node, choice.text)
|
||||
if index > 1 then
|
||||
choice_position.y = choice_position.y - height / 2 - 16
|
||||
end
|
||||
|
||||
gui.set_enabled(node, true)
|
||||
gui.set_position(node, choice_position)
|
||||
|
||||
local size = gui.get_size(node)
|
||||
size.y = height
|
||||
gui.set_size(node, size)
|
||||
|
||||
gui.set_alpha(node, 0)
|
||||
gui.animate(node, 'color.w', 1, go.EASING_LINEAR, 0.5, (#paragraphs + 1) / 2)
|
||||
|
||||
table.insert(self.choice_nodes, node)
|
||||
end
|
||||
end
|
||||
|
||||
---@param self Self
|
||||
function init(self)
|
||||
msg.post('@render:', 'clear_color', { color = vmath.vector4(1, 1, 1, 1)})
|
||||
msg.post('.', 'acquire_input_focus')
|
||||
|
||||
self.paragraph_template = gui.get_node('paragraph')
|
||||
self.paragraph_initial_position = gui.get_position(self.paragraph_template)
|
||||
self.paragraph_nodes = {}
|
||||
|
||||
self.choice_template = gui.get_node('choice')
|
||||
self.choice_initial_position = gui.get_position(self.choice_template)
|
||||
self.choice_nodes = {}
|
||||
|
||||
-- Parse and save a book
|
||||
self.book = narrator.parse_file('example-defold.book', { save = true })
|
||||
|
||||
-- Or load and parse the Ink file from the custom resources
|
||||
-- local content = sys.load_resource('/example-defold/book.ink')
|
||||
-- self.book = narrator.parseBook(content)
|
||||
|
||||
-- Or load a book from the saved lua module
|
||||
-- self.book = require('example-defold.book')
|
||||
|
||||
-- Or parse a book from the string with Ink content
|
||||
-- self.book = narrator.parseBook('Hello world!')
|
||||
|
||||
-- Init a story
|
||||
self.story = narrator.init_story(self.book)
|
||||
|
||||
-- Begin the story
|
||||
self.story:begin()
|
||||
|
||||
display_output(self)
|
||||
end
|
||||
|
||||
---@param self Self
|
||||
---@param action_id hash|string
|
||||
---@param action table
|
||||
function on_input(self, action_id, action)
|
||||
if action_id ~= hash 'touch' or not action.pressed then
|
||||
return
|
||||
end
|
||||
|
||||
if not self.story:can_choose() then
|
||||
-- Begin a new story
|
||||
self.story = narrator.init_story(self.book)
|
||||
self.story:begin()
|
||||
|
||||
display_output(self)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
for index, node in ipairs(self.choice_nodes) do
|
||||
if gui.pick_node(node, action.x, action.y) then
|
||||
-- Make a choice
|
||||
self.story:choose(index)
|
||||
|
||||
display_output(self)
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue