draw more UI

This commit is contained in:
Zack Buhman 2026-05-26 18:20:52 -05:00
parent ce5d9fccba
commit 06db7983ca
20 changed files with 1091 additions and 596 deletions

View File

@ -7,7 +7,7 @@ OBJARCH = elf64-x86-64
UNAME := $(shell uname -s)
OPT += -O0 -march=x86-64-v3
OPT += -O3 -march=x86-64-v3
DEBUG = -g
@ -24,10 +24,14 @@ CFLAGS += -I./include
CFLAGS += -I./data
CFLAGS += -I../SDL3-dist/include
CFLAGS += -fpic
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
#FLAGS += -fstack-protector -fstack-protector-all -fno-omit-frame-pointer -fsanitize=address
LDFLAGS += -lm
LDFLAGS += -Wl,--gc-sections
#-Wl,--print-gc-sections
ifeq ($(UNAME),Linux)
LDFLAGS += -Wl,-z noexecstack
endif
@ -36,6 +40,16 @@ LDFLAGS += -framework Foundation -framework Cocoa -framework IOKit -framework AV
LDFLAGS += -lstdc++
endif
# src/collada/scene/vulkan.o \
# src/collada/scene/reload.o \
# src/collada/scene.o \
# src/collada/node_state.o \
# src/collada/animate.o \
# src/minecraft/world.o \
# src/minecraft/entry_table.o \
# src/minecraft/vulkan.o \
# src/minecraft/vulkan/per_world.o \
OBJS = \
src/main.o \
src/view.o \
@ -43,19 +57,12 @@ OBJS = \
src/file.o \
src/pack.o \
src/dds/validate.o \
src/tga/tga.o \
src/vulkan_helper.o \
src/collada/scene/vulkan.o \
src/collada/scene/reload.o \
src/collada/scene.o \
src/collada/node_state.o \
src/collada/animate.o \
src/minecraft/world.o \
src/minecraft/entry_table.o \
src/minecraft/vulkan.o \
src/minecraft/vulkan/per_world.o \
src/tga/tga.o \
src/font/outline.o \
src/renpy/vulkan.o
src/renpy/vulkan.o \
src/renpy/script.o \
src/renpy/interpreter.o
WORLDS = \
data/minecraft/midnightmeadow/inthash.o \

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -2,7 +2,7 @@
# Declare characters used by this game. The color argument colorizes the
# name of the character.
image bgwhite = "bg/white.png"
image bgwhite = "#ffffff"
image bgforest1 = "bg/forest1.png"
image bgforest2 = "bg/forest2.png"
image bgflower1 = "bg/flowerfield1.png"
@ -303,7 +303,7 @@ label start:
with Dissolve(3.0)
n "After their encounter with the weird cat, the mice scurry out of the flower field and into the nearby meadow"
scene forest2
scene bgforest2
with Dissolve(3.0)
show ei at right
@ -539,4 +539,3 @@ label start:
return

View File

@ -1,8 +1,8 @@
shader/font.spv
data/font/outline/uncial_antiqua_36.data
data/font/outline/medieval_sharp_24.data
shader/renpy.spv
data/renpy/images/bg/white.dds
data/renpy/images/flowers.dds
data/renpy/images/bg/forest1.dds
data/renpy/images/bg/forest2.dds
data/renpy/images/bg/flowerfield1.dds

1
font.sh Normal file
View File

@ -0,0 +1 @@
~/dreamcast/tools/ttf_outline 20 7f 24 0 little ~/mouse2/mousegirl4/game/fonts/MedievalSharp-Regular.ttf ~/vulkan/data/font/outline/medieval_sharp_24.data

View File

@ -2,6 +2,7 @@
#include "outline_types.h"
#include "vulkan_helper.h"
#include "renpy/interpreter.h"
namespace font::outline {
@ -9,12 +10,15 @@ namespace font::outline {
char const * const path;
};
font_desc const uncial_antiqua[] = {
font_desc const medieval_sharp[] = {
{
.path = "data/font/outline/uncial_antiqua_36.data",
.path = "data/font/outline/medieval_sharp_24.data",
},
};
int const uncial_antiqua_length = (sizeof (uncial_antiqua)) / (sizeof (font_desc));
int const medieval_sharp_length = (sizeof (medieval_sharp)) / (sizeof (font_desc));
constexpr uint32_t textboxLeft = 410;
constexpr uint32_t textboxWidth = 450;
struct AllocatedImage {
VkImage image;
@ -100,8 +104,21 @@ namespace font::outline {
void create_instance_buffers();
void create_pipeline();
void create_glyphs_buffer(types::font const * const font, types::glyph const * const glyphs);
void emit_line(int frameIndex,
char const * const string,
uint32_t x, uint32_t y,
int& outputIndex,
int startIndex,
int endIndex,
uint32_t color);
void centered(int frameIndex, char const * const string, uint32_t& x, uint32_t& y,
uint32_t minX,
uint32_t maxWidth,
int& outputIndex,
uint32_t color);
void draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex);
uint32_t frameIndex,
renpy::interpreter const& state);
LoadedFont load_font(font_desc const& desc);
};

View File

@ -1,4 +1,8 @@
#pragma once
#include <stdint.h>
#include "renpy/language.h"
namespace renpy {
struct top_left {
@ -6,22 +10,42 @@ namespace renpy {
uint32_t left;
};
static const top_left transforms[] = {
static constexpr top_left transforms[] = {
[language::transform::left] = { .top = 192, .left = 0 },
[language::transform::centerleft] = { .top = 192, .left = 240 },
[language::transform::center] = { .top = 192, .left = 416 },
[language::transform::centerright] = { .top = 192, .left = 588 },
[language::transform::right] = { .top = 192, .left = 828 },
};
static constexpr int transformsCount = (sizeof (transforms)) / (sizeof (transforms[0]));
struct shownImage {
uint32_t imageIndex;
uint32_t transformIndex;
};
static constexpr int maximumShownImagesCount = 16;
struct interpreter {
uint32_t pc;
uint32_t backgroundIndex;
shownImage shownImages[16];
uint32_t backgroundColor;
shownImage shownImages[maximumShownImagesCount];
uint32_t shownImagesCount;
struct {
uint32_t stringIndex;
uint32_t characterIndex;
} say;
struct {
uint32_t count;
uint32_t optionIndex;
} menu;
uint32_t findImage(uint32_t imageIndex);
void showImage(uint32_t imageIndex, uint32_t transformIndex);
void hideImage(uint32_t imageIndex);
void reset();
void interpret_one();
void interpret();
};
}

View File

@ -1,3 +1,5 @@
#pragma once
#include <stdint.h>
namespace renpy::language {
@ -18,6 +20,7 @@ namespace renpy::language {
struct character {
char const * const characterName;
uint32_t color;
};
struct audio {
@ -37,12 +40,14 @@ namespace renpy::language {
_return,
say,
scene,
scene_color,
show,
voice,
with,
stop,
pause,
hide,
dissolve,
};
struct jump {
@ -71,6 +76,10 @@ namespace renpy::language {
uint32_t imageIndex;
};
struct scene_color {
uint32_t color;
};
struct show {
uint32_t imageIndex;
uint32_t transformIndex;
@ -95,6 +104,10 @@ namespace renpy::language {
uint32_t imageIndex;
};
struct dissolve {
float duration;
};
struct statement {
enum type type;
union {
@ -103,11 +116,13 @@ namespace renpy::language {
renpy::language::play play;
renpy::language::say say;
renpy::language::scene scene;
renpy::language::scene_color scene_color;
renpy::language::show show;
renpy::language::voice voice;
renpy::language::stop stop;
renpy::language::pause pause;
renpy::language::hide hide;
renpy::language::dissolve dissolve;
};
};
}

View File

@ -1,477 +1,22 @@
#include "renpy/language.h"
namespace renpy::script {
using namespace renpy::language;
char const * const strings[] = {
"Far over the mountains of Almystice", // 0
"Beyond the tumultuous waters of the Lilac Bay", // 1
"And across the vast fields of Alysen", // 2
"Tiny minstrels can be heard amongst the trees", // 3
"Are we almost there?", // 4
"Hmmm... Not really", // 5
"How much further have we to go?", // 6
"About two more moons", // 7
"We are still sooo far awayyy", // 8
"And it will be even further if you dont stop complaining", // 9
"Easy for you to say, all you have to carry is a little memory pipe!", // 10
"I'm tired ><", // 11
"Don't start whining now!", // 12
"You need to remember why we have come all this way", // 13
"I understand... I suppose it is for an important purpose", // 14
"We're almost out of the forest, we can take a little break once we clear the tree line", // 15
"Is that where the flora field is?", // 16
"Why yes, If I remember correctly, it should be just up ahead", // 17
"As the minstrel mice girls continue along the path, the forest opens up into a beautiful field of flowers", // 18
"Look at all the butterflies! They are all so pretty!", // 19
"This place is like a dream...", // 20
"There are so many flowers this time of year", // 21
"I told you it would be worth the journey!", // 22
"Can we stop for a bit now?", // 23
"Of course", // 24
"Ya know, Its a shame we didnt save some of those giant strawberries you found", // 25
"I told you not to eat them all!", // 26
"Yah yah", // 27
"Anyways, shall I recite a tale?", // 28
"Why dont you sing the story of Eleanor the Hero!", // 29
"Sure", // 30
"...", // 31
"Serves you right for scaring those elephant-dogs", // 32
"They were asking for it, you know", // 33
"Rawrrrr", // 34
"AHHHHHHHHHH!!!!!", // 35
"Nyanyanyanya", // 36
"Well, what do we have here? If it isn't two little meowse girls, all alone amongst the flowers", // 37
"Please don't eat us!!!", // 38
"Alice don't run, our only chance is through pleading!", // 39
"Please don't eat us, miss kitty cat!!! ><", // 40
"I'm not gonna eat you nyanyanya", // 41
"I just want to know what two little meowses are doing so very far away from home", // 42
"Also, are you minstrels?", // 43
"Y-Yes", // 44
"W-We are on a quest to Castle Alysen...", // 45
"Shh don't tell her that", // 46
"The Castle of Alysen you say?!?", // 47
"Why, that's where I am headed!", // 48
"You don't say...", // 49
"Yah, I do actually", // 50
"So... Why might you be traveling to the castle?", // 51
"I belong to the lineage of Agrepen", // 52
"And what might that mean?", // 53
"The Agrepens are a long line of felines loyal to the crown of corvidae", // 54
"Really? That must mean you are a noble?", // 55
"Well, not really...", // 56
"My father was one of the queens knights many years ago", // 57
"Ah I see", // 58
"So do you live at the castle or something?", // 59
"Well, no...", // 60
"Then why are you traveling to Castle Alysen?", // 61
"uhhh", // 62
"I DONT NEED TO BE PRESSURED BY LITTLE MICE TO SAY ANYTHING!!!!", // 63
"GOOD DAY!", // 64
"Wha...", // 65
"Phew, I was scared she was gonna follow us the whole way", // 66
"She didn't seem so bad", // 67
"Are you kidding? She's a crazy kitty!", // 68
"After their encounter with the weird cat, the mice scurry out of the flower field and into the nearby meadow", // 69
"I think this is the right way...", // 70
"Then where did the path go?", // 71
"How am I supposed to know?", // 72
"Did you hear that?!?!", // 73
"Hey there...", // 74
"I apologize", // 75
"I didn't mean to storm off like that", // 76
"Ha ha, no problem...", // 77
"So... Why are you traveling to Castle Alysen?", // 78
"Alice!!!", // 79
"If you must know, I have been summoned by the queen", // 80
"I suspect that my poor reputation amongst the locals of Eastern Nidus has come back to haunt me", // 81
"Though I know not what what she has summoned me for", // 82
"Ahhhhhh", // 83
"So then...", // 84
"Why are YOU traveling to the Castle?", // 85
"We are delivering a feather!!!", // 86
"Alice no!", // 87
"A feather that belonged to the queen herself!!!", // 88
"Why you little...", // 89
"A feather you say? One of the queens?", // 90
"How on the face of Al Mot might you have aquired such a thing?", // 91
"If it is authentic, that is...", // 92
"Since Alice cannot keep a secret, I shall tell you", // 93
"Seven moons ago, our town was attacked by three owls and a band of mice from the northern principalities", // 94
"Eventually word spread to greater nearby settlements, and so", // 95
"Messengers from the keep in Musia sent for aid from the Ravens", // 96
"Four moons ago, the request was answered", // 97
"And a small group of mice accompanied by two ravens a fox, and three squirrels set out to the northern principalities", // 98
"Anyways, long story short, we drove those barbaric rats out of their home", // 99
"They arent actual rats you know", // 100
"Obviously, but you wont catch me speaking kindly of them", // 101
"And you forgot the most important part", // 102
"Yah yah, I am getting there", // 103
"So, essentially, my brother is trained in archery, and...", // 104
"Speed it up already", // 105
"You tell it then!", // 106
"My cousin found this feather in one of the highest towers of a castle far to the north", // 107
"How do you know it belongs to the queen?", // 108
"It said so itself above the display on the wall", // 109
"Supposedly, it was in a room filled with treasures!", // 110
"That is very nice and all, but what are the two of you doing out here all alone?", // 111
"Do you expect every bird in Avia to respect your alliance with Castle Alysen?", // 112
"What do you mean?", // 113
"I mean, the two of you probably look like walking dinner to most creatures", // 114
"I could go for some dinner...", // 115
"Anyways...", // 116
"To answer your question, upon returning to the village, the feather was taken from my brother by the needle guild", // 117
"So... Yesterday, after sundown", // 118
"We stole the feather from the guild hall before vanishing into the night", // 119
"Can you imagine the look on their stupid faces, when they woke up, and not only is the feather missing", // 120
"But so are we!", // 121
"Hahahaha", // 122
"Are the two of you mad?", // 123
"I assume you are attempting to return the Queens feather?", // 124
"Yes, we intend to deliver the feather to its rightful owner", // 125
"Absolute madness!", // 126
"I will follow the two of you", // 127
"To keep you safe, that is", // 128
"Alright!", // 129
"Ha ha... Okay...", // 130
"Great! Follow me, I know a shortcut! :3", // 131
"Sounds good!", // 132
"Oh dear!", // 133
"And so the mice girls follow the noble cat further towards their destination", // 134
"Nya", // 135
"Look, your right, the castle is just up ahead!", // 136
"Wait up", // 137
"I told you I knew a shortcut!", // 138
"Most people take the long way around", // 139
"Yah because these are royal wheatfields!", // 140
"Who cares?", // 141
"Are you trying to get us killed?", // 142
"Its trespassing on royal land!", // 143
"Calm down, I have done this a million times", // 144
"That doesnt make me calm!", // 145
"How can the rolling fields of wheat not calm your spirit?", // 146
"You little mice truly are mad!", // 147
"I like the wheat!", // 148
"Shut up!", // 149
"Sounds like someone needs a nap!", // 150
"Why? because I'm not insane like you?", // 151
"Yah, your so sane, that you decided to steal from your town and then run off alone to the country of birds", // 152
"The power of friendship wont protect the two of you from becoming dinner", // 153
"And that, is why I feel obligated to accompany you!", // 154
"Hey, we have a good reason!", // 155
"And what might that be?", // 156
"My brother found the feather, not the town guild, its a matter of family pride!", // 157
"Pride has touched the chosen meouse", // 158
"Flies she towards the Castle", // 159
"But her ambition burns far too bright, and silly myice dont have any wings to myelt", // 160
"What?", // 161
"Nyanyanya", // 162
"Nyevermind", // 163
"Sing me a song little minstrels!", // 164
"Very Nyice!", // 165
"Now tell me little minstrels, what are your names?", // 166
"My name is Alice", // 167
"And my name is Eily", // 168
"What is your name?", // 169
"My name is Leona!", // 170
"And so, the odd trio walked through the wheatfields and towards the castle walls", // 171
"Upon approaching the castle walls", // 172
};
extern char const * const strings[];
extern const int strings_length;
constexpr int strings_length = (sizeof (strings)) / (sizeof (strings[0]));
extern const language::character characters[];
extern const int characters_length;
const character characters[] = {
{ .characterName = "Alice" }, // 0
{ .characterName = "Cat" }, // 1
{ .characterName = "Eily" }, // 2
{ .characterName = "Mouse Girls" }, // 3
{ .characterName = "Narrator" }, // 4
{ .characterName = "Leona" }, // 5
};
extern const language::audio audio[];
extern const int audio_length;
constexpr int characters_length = (sizeof (characters)) / (sizeof (characters[0]));
extern const language::image images[];
extern const int images_length;
const audio audio[] = {
{ .path = "sfx/Chime.opus" }, // 0 sfx/Chime.ogg
{ .path = "sfx/MistAmbience.opus" }, // 1 sfx/MistAmbience.ogg
{ .path = "music/TinyForestMinstrels.opus" }, // 2 music/TinyForestMinstrels.ogg
{ .path = "n5test.opus" }, // 3 n5test.ogg
{ .path = "music/PhrygianButterflies.opus" }, // 4 music/PhrygianButterflies.ogg
{ .path = "music/Poem1.opus" }, // 5 music/Poem1.ogg
{ .path = "placeholdermeow.opus" }, // 6 placeholdermeow.mp3
{ .path = "music/ScaredMice.opus" }, // 7 music/ScaredMice.ogg
{ .path = "music/WheatFields.opus" }, // 8 music/WheatFields.ogg
};
extern const language::option options[];
extern const int options_length;
constexpr int audio_length = (sizeof (audio)) / (sizeof (audio[0]));
const image images[] = {
{ .path = "data/renpy/images/bg/white.dds" }, // 0 bg/white.png
{ .path = "data/renpy/images/bg/forest1.dds" }, // 1 bg/forest1.png
{ .path = "data/renpy/images/bg/forest2.dds" }, // 2 bg/forest2.png
{ .path = "data/renpy/images/bg/flowerfield1.dds" }, // 3 bg/flowerfield1.png
{ .path = "data/renpy/images/bg/wheatfield1.dds" }, // 4 bg/wheatfield1.png
{ .path = "data/renpy/images/ch/cat.dds" }, // 5 ch/cat.png
{ .path = "data/renpy/images/ch/catw.dds" }, // 6 ch/catw.png
{ .path = "data/renpy/images/ch/Eily.dds" }, // 7 ch/Eily.png
{ .path = "data/renpy/images/ch/Alice.dds" }, // 8 ch/Alice.png
};
constexpr int images_length = (sizeof (images)) / (sizeof (images[0]));
const option options[] = {
{ .string = "Complain", .statementIndex = 18 }, // 0
{ .string = "Rationalize", .statementIndex = 26 }, // 1
{ .string = "Good idea", .statementIndex = 54 }, // 2
{ .string = "I am too tired", .statementIndex = 61 }, // 3
{ .string = "Beg for mercy", .statementIndex = 78 }, // 4
{ .string = "Run", .statementIndex = 80 }, // 5
};
constexpr int options_length = (sizeof (options)) / (sizeof (options[0]));
const statement statements[] = {
{ .type = type::play, .play = { .audioIndex = 0, /* FIXME channel */ } }, // 0 sfx/Chime.ogg
{ .type = type::play, .play = { .audioIndex = 1, /* FIXME channel */ } }, // 1 sfx/MistAmbience.ogg
{ .type = type::scene, .scene = { .imageIndex = 0 } }, // 2 bgwhite
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 0 } }, // 4 n "Far over the mountains of Almystice"
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 1 } }, // 5 n "Beyond the tumultuous waters of the Lilac Bay"
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 2 } }, // 6 n "And across the vast fields of Alysen"
{ .type = type::play, .play = { .audioIndex = 2, /* FIXME channel */ } }, // 7 music/TinyForestMinstrels.ogg
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 3 } }, // 8 n "Tiny minstrels can be heard amongst the trees"
{ .type = type::scene, .scene = { .imageIndex = 1 } }, // 9 bgforest1
{ .type = type::show, .show = { .imageIndex = 8, .transformIndex = transform::left } }, // 11 al
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 4 } }, // 12 a "Are we almost there?"
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::right } }, // 13 ei
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 5 } }, // 14 e "Hmmm... Not really"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 6 } }, // 15 a "How much further have we to go?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 7 } }, // 16 e "About two more moons"
{ .type = type::menu, .menu = { .count = 2, .optionIndex = 0 } }, // 17 "Complain", "Rationalize"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 8 } }, // 18 a "We are still sooo far awayyy"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 9 } }, // 19 e "And it will be even further if you dont stop complaining"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 10 } }, // 20 a "Easy for you to say, all you have to carry is a little memory pipe!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 11 } }, // 21 a "I'm tired ><"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 12 } }, // 22 e "Don't start whining now!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 13 } }, // 23 e "You need to remember why we have come all this way"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 14 } }, // 24 a "I understand... I suppose it is for an important purpose"
{ .type = type::jump, .jump = { .statementIndex = 28 } }, // 25 internal jump (b'__menu_end', 0)
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 14 } }, // 26 a "I understand... I suppose it is for an important purpose"
{ .type = type::jump, .jump = { .statementIndex = 28 } }, // 27 internal jump (b'__menu_end', 0)
{ .type = type::jump, .jump = { .statementIndex = 29 } }, // 28 mainbranch1
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 15 } }, // 29 e "We're almost out of the forest, we can take a little break once we clear the tree line"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 16 } }, // 30 a "Is that where the flora field is?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 17 } }, // 31 e "Why yes, If I remember correctly, it should be just up ahead"
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 32
{ .type = type::scene, .scene = { .imageIndex = 0 } }, // 33 bgwhite
{ .type = type::play, .play = { .audioIndex = 0, /* FIXME channel */ } }, // 34 sfx/Chime.ogg
{ .type = type::voice, .voice = { .audioIndex = 3 } }, // 36 n5test.ogg
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 18 } }, // 37 n "As the minstrel mice girls continue along the path, the forest opens up into a beautiful field of flowers"
{ .type = type::play, .play = { .audioIndex = 4, /* FIXME channel */ } }, // 38 music/PhrygianButterflies.ogg
{ .type = type::scene, .scene = { .imageIndex = 3 } }, // 39 bgflower1
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::right } }, // 41 ei
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 19 } }, // 42 e "Look at all the butterflies! They are all so pretty!"
{ .type = type::show, .show = { .imageIndex = 8, .transformIndex = transform::left } }, // 43 al
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 20 } }, // 44 a "This place is like a dream..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 21 } }, // 45 e "There are so many flowers this time of year"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 22 } }, // 46 e "I told you it would be worth the journey!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 23 } }, // 47 a "Can we stop for a bit now?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 24 } }, // 48 e "Of course"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 25 } }, // 49 e "Ya know, Its a shame we didnt save some of those giant strawberries you found"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 26 } }, // 50 a "I told you not to eat them all!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 27 } }, // 51 e "Yah yah"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 28 } }, // 52 e "Anyways, shall I recite a tale?"
{ .type = type::menu, .menu = { .count = 2, .optionIndex = 2 } }, // 53 "Good idea", "I am too tired"
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 54
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 29 } }, // 55 a "Why dont you sing the story of Eleanor the Hero!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 30 } }, // 56 e "Sure"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 31 } }, // 57 a "..."
{ .type = type::play, .play = { .audioIndex = 5, /* FIXME channel */ } }, // 58 music/Poem1.ogg
{ .type = type::pause, .pause = { .duration = 40 } }, // 59
{ .type = type::jump, .jump = { .statementIndex = 65 } }, // 60 internal jump (b'__menu_end', 1)
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 32 } }, // 61 e "Serves you right for scaring those elephant-dogs"
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 62
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 33 } }, // 63 a "They were asking for it, you know"
{ .type = type::jump, .jump = { .statementIndex = 65 } }, // 64 internal jump (b'__menu_end', 1)
{ .type = type::jump, .jump = { .statementIndex = 66 } }, // 65 mainbranch2
{ .type = type::hide, .hide = { .imageIndex = 7 } }, // 66 ei
{ .type = type::show, .show = { .imageIndex = 6, .transformIndex = transform::right } }, // 67 catw
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::centerleft } }, // 68 ei
{ .type = type::voice, .voice = { .audioIndex = 6 } }, // 69 placeholdermeow.mp3
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 34 } }, // 70 c "Rawrrrr"
{ .type = type::hide, .hide = { .imageIndex = 6 } }, // 71 catw
{ .type = type::show, .show = { .imageIndex = 5, .transformIndex = transform::right } }, // 72 cat
{ .type = type::play, .play = { .audioIndex = 7, /* FIXME channel */ } }, // 73 music/ScaredMice.ogg
{ .type = type::say, .say = { .characterIndex = 3, .stringIndex = 35 } }, // 74 mg "AHHHHHHHHHH!!!!!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 36 } }, // 75 c "Nyanyanyanya"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 37 } }, // 76 c "Well, what do we have here? If it isn't two little meowse girls, all alone amongst the flowers"
{ .type = type::menu, .menu = { .count = 2, .optionIndex = 4 } }, // 77 "Beg for mercy", "Run"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 38 } }, // 78 a "Please don't eat us!!!"
{ .type = type::jump, .jump = { .statementIndex = 83 } }, // 79 internal jump (b'__menu_end', 2)
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 39 } }, // 80 e "Alice don't run, our only chance is through pleading!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 40 } }, // 81 e "Please don't eat us, miss kitty cat!!! ><"
{ .type = type::jump, .jump = { .statementIndex = 83 } }, // 82 internal jump (b'__menu_end', 2)
{ .type = type::jump, .jump = { .statementIndex = 84 } }, // 83 mainbranch3
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 84
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 41 } }, // 85 c "I'm not gonna eat you nyanyanya"
{ .type = type::play, .play = { .audioIndex = 2, /* FIXME channel */ } }, // 86 music/TinyForestMinstrels.ogg
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 42 } }, // 87 c "I just want to know what two little meowses are doing so very far away from home"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 43 } }, // 88 c "Also, are you minstrels?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 44 } }, // 89 e "Y-Yes"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 45 } }, // 90 a "W-We are on a quest to Castle Alysen..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 46 } }, // 91 e "Shh don't tell her that"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 47 } }, // 92 c "The Castle of Alysen you say?!?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 48 } }, // 93 c "Why, that's where I am headed!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 49 } }, // 94 e "You don't say..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 50 } }, // 95 c "Yah, I do actually"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 51 } }, // 96 e "So... Why might you be traveling to the castle?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 52 } }, // 97 c "I belong to the lineage of Agrepen"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 53 } }, // 98 e "And what might that mean?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 54 } }, // 99 c "The Agrepens are a long line of felines loyal to the crown of corvidae"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 55 } }, // 100 e "Really? That must mean you are a noble?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 56 } }, // 101 c "Well, not really..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 57 } }, // 102 c "My father was one of the queens knights many years ago"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 58 } }, // 103 e "Ah I see"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 59 } }, // 104 e "So do you live at the castle or something?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 60 } }, // 105 c "Well, no..."
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 61 } }, // 106 a "Then why are you traveling to Castle Alysen?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 62 } }, // 107 c "uhhh"
{ .type = type::play, .play = { .audioIndex = 1, /* FIXME channel */ } }, // 108 sfx/MistAmbience.ogg
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 109
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 63 } }, // 110 c "I DONT NEED TO BE PRESSURED BY LITTLE MICE TO SAY ANYTHING!!!!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 64 } }, // 111 c "GOOD DAY!"
{ .type = type::hide, .hide = { .imageIndex = 5 } }, // 112 cat
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 65 } }, // 113 a "Wha..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 66 } }, // 114 e "Phew, I was scared she was gonna follow us the whole way"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 67 } }, // 115 a "She didn't seem so bad"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 68 } }, // 116 e "Are you kidding? She's a crazy kitty!"
{ .type = type::scene, .scene = { .imageIndex = 0 } }, // 117 bgwhite
{ .type = type::play, .play = { .audioIndex = 0, /* FIXME channel */ } }, // 118 sfx/Chime.ogg
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 69 } }, // 120 n "After their encounter with the weird cat, the mice scurry out of the flower field and into the nearby meadow"
{ .type = type::scene, .scene = { .imageIndex = 2 } }, // 121 bgforest2
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::right } }, // 123 ei
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 70 } }, // 124 e "I think this is the right way..."
{ .type = type::show, .show = { .imageIndex = 8, .transformIndex = transform::left } }, // 125 al
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 71 } }, // 126 a "Then where did the path go?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 72 } }, // 127 e "How am I supposed to know?"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 73 } }, // 128 a "Did you hear that?!?!"
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::centerleft } }, // 129 ei
{ .type = type::show, .show = { .imageIndex = 5, .transformIndex = transform::right } }, // 130 cat
{ .type = type::play, .play = { .audioIndex = 4, /* FIXME channel */ } }, // 131 music/PhrygianButterflies.ogg
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 74 } }, // 132 c "Hey there..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 75 } }, // 133 c "I apologize"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 76 } }, // 134 c "I didn't mean to storm off like that"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 77 } }, // 135 e "Ha ha, no problem..."
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 78 } }, // 136 a "So... Why are you traveling to Castle Alysen?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 79 } }, // 137 e "Alice!!!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 80 } }, // 138 c "If you must know, I have been summoned by the queen"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 81 } }, // 139 c "I suspect that my poor reputation amongst the locals of Eastern Nidus has come back to haunt me"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 82 } }, // 140 c "Though I know not what what she has summoned me for"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 83 } }, // 141 a "Ahhhhhh"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 84 } }, // 142 c "So then..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 85 } }, // 143 c "Why are YOU traveling to the Castle?"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 86 } }, // 144 a "We are delivering a feather!!!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 87 } }, // 145 e "Alice no!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 88 } }, // 146 a "A feather that belonged to the queen herself!!!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 89 } }, // 147 e "Why you little..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 90 } }, // 148 c "A feather you say? One of the queens?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 91 } }, // 149 c "How on the face of Al Mot might you have aquired such a thing?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 92 } }, // 150 c "If it is authentic, that is..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 93 } }, // 151 e "Since Alice cannot keep a secret, I shall tell you"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 94 } }, // 152 e "Seven moons ago, our town was attacked by three owls and a band of mice from the northern principalities"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 95 } }, // 153 e "Eventually word spread to greater nearby settlements, and so"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 96 } }, // 154 e "Messengers from the keep in Musia sent for aid from the Ravens"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 97 } }, // 155 e "Four moons ago, the request was answered"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 98 } }, // 156 e "And a small group of mice accompanied by two ravens a fox, and three squirrels set out to the northern principalities"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 99 } }, // 157 e "Anyways, long story short, we drove those barbaric rats out of their home"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 100 } }, // 158 a "They arent actual rats you know"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 101 } }, // 159 e "Obviously, but you wont catch me speaking kindly of them"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 102 } }, // 160 a "And you forgot the most important part"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 103 } }, // 161 e "Yah yah, I am getting there"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 104 } }, // 162 e "So, essentially, my brother is trained in archery, and..."
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 105 } }, // 163 a "Speed it up already"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 106 } }, // 164 e "You tell it then!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 107 } }, // 165 a "My cousin found this feather in one of the highest towers of a castle far to the north"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 108 } }, // 166 c "How do you know it belongs to the queen?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 109 } }, // 167 e "It said so itself above the display on the wall"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 110 } }, // 168 a "Supposedly, it was in a room filled with treasures!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 111 } }, // 169 c "That is very nice and all, but what are the two of you doing out here all alone?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 112 } }, // 170 c "Do you expect every bird in Avia to respect your alliance with Castle Alysen?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 113 } }, // 171 e "What do you mean?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 114 } }, // 172 c "I mean, the two of you probably look like walking dinner to most creatures"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 115 } }, // 173 a "I could go for some dinner..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 116 } }, // 174 e "Anyways..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 117 } }, // 175 e "To answer your question, upon returning to the village, the feather was taken from my brother by the needle guild"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 118 } }, // 176 e "So... Yesterday, after sundown"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 119 } }, // 177 e "We stole the feather from the guild hall before vanishing into the night"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 120 } }, // 178 e "Can you imagine the look on their stupid faces, when they woke up, and not only is the feather missing"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 121 } }, // 179 e "But so are we!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 122 } }, // 180 a "Hahahaha"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 123 } }, // 181 c "Are the two of you mad?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 124 } }, // 182 c "I assume you are attempting to return the Queens feather?"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 125 } }, // 183 a "Yes, we intend to deliver the feather to its rightful owner"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 126 } }, // 184 c "Absolute madness!"
{ .type = type::say, .say = { .characterIndex = 3, .stringIndex = 31 } }, // 185 mg "..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 127 } }, // 186 c "I will follow the two of you"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 128 } }, // 187 c "To keep you safe, that is"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 129 } }, // 188 a "Alright!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 130 } }, // 189 e "Ha ha... Okay..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 131 } }, // 190 c "Great! Follow me, I know a shortcut! :3"
{ .type = type::hide, .hide = { .imageIndex = 5 } }, // 191 cat
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 132 } }, // 192 a "Sounds good!"
{ .type = type::hide, .hide = { .imageIndex = 8 } }, // 193 al
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 194
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 133 } }, // 195 e "Oh dear!"
{ .type = type::hide, .hide = { .imageIndex = 7 } }, // 196 ei
{ .type = type::scene, .scene = { .imageIndex = 0 } }, // 197 bgwhite
{ .type = type::play, .play = { .audioIndex = 0, /* FIXME channel */ } }, // 198 sfx/Chime.ogg
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 134 } }, // 200 n "And so the mice girls follow the noble cat further towards their destination"
{ .type = type::scene, .scene = { .imageIndex = 4 } }, // 201 bgwheatfield1
{ .type = type::play, .play = { .audioIndex = 8, /* FIXME channel */ } }, // 202 music/WheatFields.ogg
{ .type = type::show, .show = { .imageIndex = 5, .transformIndex = transform::right } }, // 203 cat
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 135 } }, // 205 c "Nya"
{ .type = type::show, .show = { .imageIndex = 8, .transformIndex = transform::left } }, // 206 al
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 136 } }, // 207 a "Look, your right, the castle is just up ahead!"
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::centerleft } }, // 208 ei
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 137 } }, // 209 e "Wait up"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 138 } }, // 210 c "I told you I knew a shortcut!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 139 } }, // 211 c "Most people take the long way around"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 140 } }, // 212 e "Yah because these are royal wheatfields!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 141 } }, // 213 a "Who cares?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 142 } }, // 214 e "Are you trying to get us killed?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 143 } }, // 215 e "Its trespassing on royal land!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 144 } }, // 216 c "Calm down, I have done this a million times"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 145 } }, // 217 e "That doesnt make me calm!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 146 } }, // 218 c "How can the rolling fields of wheat not calm your spirit?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 147 } }, // 219 c "You little mice truly are mad!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 148 } }, // 220 a "I like the wheat!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 149 } }, // 221 e "Shut up!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 150 } }, // 222 c "Sounds like someone needs a nap!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 151 } }, // 223 e "Why? because I'm not insane like you?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 152 } }, // 224 c "Yah, your so sane, that you decided to steal from your town and then run off alone to the country of birds"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 153 } }, // 225 c "The power of friendship wont protect the two of you from becoming dinner"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 154 } }, // 226 c "And that, is why I feel obligated to accompany you!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 155 } }, // 227 e "Hey, we have a good reason!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 156 } }, // 228 c "And what might that be?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 157 } }, // 229 e "My brother found the feather, not the town guild, its a matter of family pride!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 158 } }, // 230 c "Pride has touched the chosen meouse"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 159 } }, // 231 c "Flies she towards the Castle"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 160 } }, // 232 c "But her ambition burns far too bright, and silly myice dont have any wings to myelt"
{ .type = type::say, .say = { .characterIndex = 3, .stringIndex = 161 } }, // 233 mg "What?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 162 } }, // 234 c "Nyanyanya"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 163 } }, // 235 c "Nyevermind"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 164 } }, // 236 c "Sing me a song little minstrels!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 165 } }, // 237 c "Very Nyice!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 166 } }, // 238 c "Now tell me little minstrels, what are your names?"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 167 } }, // 239 a "My name is Alice"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 168 } }, // 240 e "And my name is Eily"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 169 } }, // 241 e "What is your name?"
{ .type = type::say, .say = { .characterIndex = 5, .stringIndex = 170 } }, // 242 l "My name is Leona!"
{ .type = type::scene, .scene = { .imageIndex = 0 } }, // 243 bgwhite
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 171 } }, // 245 n "And so, the odd trio walked through the wheatfields and towards the castle walls"
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 172 } }, // 246 n "Upon approaching the castle walls"
{ .type = type::_return }, // 247
};
constexpr int statements_length = (sizeof (statements)) / (sizeof (statements[0]));
extern const language::statement statements[];
extern const int statements_length;
}

View File

@ -1,3 +1,7 @@
#pragma once
#include "renpy/interpreter.h"
namespace renpy {
struct Image {
VkImage image;
@ -7,17 +11,19 @@ namespace renpy {
struct ImageInstance {
struct {
uint16_t width;
uint16_t height;
int16_t width;
int16_t height;
} size;
struct {
uint16_t x;
uint16_t y;
int16_t x;
int16_t y;
} topLeft;
uint16_t imageIndex;
uint32_t color;
int16_t imageIndex;
int16_t _padding;
};
static_assert((sizeof (ImageInstance)) == 10);
static_assert((sizeof (ImageInstance)) == 16);
struct vulkan {
static constexpr int perVertexSize = (4) * 2;
@ -75,7 +81,8 @@ namespace renpy {
void create_pipeline();
void create_instance_buffers();
void draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex);
uint32_t frameIndex,
renpy::interpreter const& state);
};
}

View File

@ -3,17 +3,20 @@ import lex
import parse
from dataclasses import dataclass
from pprint import pprint
from itertools import chain
import generate
@dataclass
class State:
images: list
colors: list
characters: list
statements: list
menus: list
entries: dict
images_lookup: dict[str, int] # identifier to image index
colors_lookup: dict[str, int] # identifier to image index
characters_lookup: dict[str, int] # identifier to character index
labels_lookup: dict[str, int] # identifier to statement index
audio_lookup: dict[str, int]
@ -53,8 +56,12 @@ def pass1(state, ast):
key = lhs_key(ast.name)
assert key not in state.global_identifiers
state.global_identifiers.add(key)
state.images_lookup[key] = len(state.images)
state.images.append(ast)
if ast.path.lexeme.startswith(b"#"):
state.colors_lookup[key] = len(state.colors)
state.colors.append(ast)
else:
state.images_lookup[key] = len(state.images)
state.images.append(ast)
elif type(ast) is parse.Define:
key = lhs_key(ast.name)
assert key not in state.global_identifiers
@ -118,6 +125,12 @@ transforms_set = {
b"right",
}
def parse_color(b):
assert b.startswith(b"#"), b
assert len(b) == 7
color = int(b[1:].decode('utf-8'), 16)
return color
def pass2_statement(state, pc, statement):
if type(statement) is parse.Play:
comment = statement.path.lexeme.decode('utf-8')
@ -125,12 +138,22 @@ def pass2_statement(state, pc, statement):
yield f"{{ .type = type::play, .play = {{ .audioIndex = {audio_index}, /* FIXME channel */ }} }}, // {pc} {comment}"
elif type(statement) is parse.Scene:
key = lhs_key(statement.name)
image_index = state.images_lookup[key]
comment = ".".join(k.decode('utf-8') for k in key)
yield f"{{ .type = type::scene, .scene = {{ .imageIndex = {image_index} }} }}, // {pc} {comment}"
if key in state.images_lookup:
image_index = state.images_lookup[key]
comment = ".".join(k.decode('utf-8') for k in key)
yield f"{{ .type = type::scene, .scene = {{ .imageIndex = {image_index} }} }}, // {pc} {comment}"
else:
color_index = state.colors_lookup[key]
color = parse_color(state.colors[color_index].path.lexeme)
comment = ".".join(k.decode('utf-8') for k in key)
yield f"{{ .type = type::scene_color, .scene_color = {{ .color = 0x{color:06x} }} }}, // {pc} {comment}"
elif type(statement) is parse.With:
print(f"not implemented: {statement}", file=sys.stderr)
pass
#print(f"not implemented: {statement}", file=sys.stderr)
if statement.function_call.name.lexeme == b'Dissolve':
duration, = statement.function_call.args
yield f"{{ .type = type::dissolve, .dissolve = {{ .duration = {duration.lexeme} }} }}, // {pc}"
else:
assert False, (pc, statement)
elif type(statement) is parse.Voice:
comment = statement.path.lexeme.decode('utf-8')
audio_index = state.audio_lookup[statement.path.lexeme]
@ -181,29 +204,32 @@ def pass2_statement(state, pc, statement):
assert False, (type(statement), statement)
def pass2_statements(state):
yield "const statement statements[] = {"
yield "const language::statement statements[] = {"
for pc, statement in enumerate(state.statements):
print(pc, statement, file=sys.stderr)
yield from pass2_statement(state, pc, statement)
yield "};"
yield "constexpr int statements_length = (sizeof (statements)) / (sizeof (statements[0]));"
yield "const int statements_length = (sizeof (statements)) / (sizeof (statements[0]));"
def pass2_strings(state):
yield "char const * const strings[] = {"
for string, i in sorted(state.string_lookup.items(), key=lambda kv: kv[1]):
yield f"\"{string.decode('utf-8')}\", // {i}"
yield "};"
yield "constexpr int strings_length = (sizeof (strings)) / (sizeof (strings[0]));"
yield "const int strings_length = (sizeof (strings)) / (sizeof (strings[0]));"
def pass2_characters(state):
yield "const character characters[] = {"
yield "const language::character characters[] = {"
for i, character in enumerate(state.characters):
character_name, = character.value.args
yield f"{{ .characterName = \"{character_name.lexeme.decode('utf-8')}\" }}, // {i}"
color, = (value.lexeme for key, value in character.value.kwargs if key.lexeme == b'color')
color = int(color.decode('utf-8'), 16)
yield f"{{ .characterName = \"{character_name.lexeme.decode('utf-8')}\", .color = 0x{color:06x} }}, // {i}"
yield "};"
yield "constexpr int characters_length = (sizeof (characters)) / (sizeof (characters[0]));"
yield "const int characters_length = (sizeof (characters)) / (sizeof (characters[0]));"
def pass2_audio(state):
yield "const audio audio[] = {"
yield "const language::audio audio[] = {"
for audio, i in sorted(state.audio_lookup.items(), key=lambda kv: kv[1]):
orig_path = audio.decode('utf-8')
path = orig_path
@ -215,10 +241,10 @@ def pass2_audio(state):
assert False, path
yield f"{{ .path = \"{path}.opus\" }}, // {i} {orig_path}"
yield "};"
yield "constexpr int audio_length = (sizeof (audio)) / (sizeof (audio[0]));"
yield "const int audio_length = (sizeof (audio)) / (sizeof (audio[0]));"
def pass2_images(state):
yield "const image images[] = {"
yield "const language::image images[] = {"
for i, image in enumerate(state.images):
orig_path = image.path.lexeme.decode('utf-8')
path = orig_path
@ -228,17 +254,18 @@ def pass2_images(state):
assert False, path
yield f"{{ .path = \"data/renpy/images/{path}.dds\" }}, // {i} {orig_path}"
yield "};"
yield "constexpr int images_length = (sizeof (images)) / (sizeof (images[0]));"
yield "const int images_length = (sizeof (images)) / (sizeof (images[0]));"
def pass2_options(state):
yield "const option options[] = {"
yield "const language::option options[] = {"
for i, (lexeme, statement_index) in sorted(state.entries.items(), key=lambda kv: kv[0]):
yield f"{{ .string = \"{lexeme.decode('utf-8')}\", .statementIndex = {statement_index} }}, // {i}"
yield "};"
yield "constexpr int options_length = (sizeof (options)) / (sizeof (options[0]));"
yield "const int options_length = (sizeof (options)) / (sizeof (options[0]));"
def pass2(state):
yield "#include \"renpy/language.h\""
yield "#include \"renpy/script.h\""
yield ""
yield "namespace renpy::script {"
yield "using namespace renpy::language;"
@ -251,17 +278,22 @@ def pass2(state):
yield "}"
def main():
preamble = b"""
image _internal_flowers = "flowers.png"
"""
with open(sys.argv[1], 'rb') as f:
mem = memoryview(f.read())
mem = memoryview(bytes(chain(preamble, f.read())))
tokens = list(lex.tokenize(mem))
state = State(
images = list(),
colors = list(),
characters = list(),
statements = list(),
menus = list(),
entries = dict(),
images_lookup = dict(),
colors_lookup = dict(),
characters_lookup = dict(),
labels_lookup = dict(),
audio_lookup = dict(),

View File

@ -23,12 +23,13 @@ struct VSOutput
{
float4 Position : SV_POSITION;
float2 Texture : NORMAL0;
float4 Color : Color;
};
[shader("vertex")]
VSOutput VSMain(VSInput input)
{
float2 inverseTexel = float2(1.0 / 256.0, 1.0 / 256.0);
float2 inverseTexel = float2(1.0 / 128.0, 1.0 / 256.0);
float2 inversePixel = float2(1.0 / 1280.0, 1.0 / 720.0);
int index = input.InstanceGlyph;
@ -36,6 +37,7 @@ VSOutput VSMain(VSInput input)
float2 position = (input.Texture * Glyphs[index].Size + input.InstancePosition) * inversePixel;
output.Position = float4(position * 2.0 - 1.0, 0, 1);
output.Texture = (input.Texture * Glyphs[index].Size + Glyphs[index].Position) * inverseTexel;
output.Color = input.InstanceColor.zyxw;
return output;
}
@ -44,5 +46,7 @@ VSOutput VSMain(VSInput input)
float4 PSMain(VSOutput input) : SV_TARGET
{
float4 color = FontTexture.Sample(ClosestSampler, input.Texture);
return float4(color.xxx, 1.0);
if (color.x == 0)
discard;
return float4(input.Color.xyz, color.x);
}

View File

@ -6,32 +6,90 @@ struct VSInput
float2 Position : POSITION0;
float2 Texture : TEXCOORD0;
// per-instance
uint2 Size : Size;
uint2 TopLeft : TopLeft;
uint TextureIndex : TextureIndex;
int2 Size : Size;
int2 TopLeft : TopLeft;
float4 Color : Color;
int TextureIndex : TextureIndex;
};
struct VSOutput
{
float4 Position : SV_POSITION;
float2 Texture : NORMAL0;
uint TextureIndex : TextureIndex;
float4 Color : Color;
int TextureIndex : TextureIndex;
};
[shader("vertex")]
VSOutput VSMain(VSInput input)
{
float2 inversePixel = float2(1.0 / 1280.0, 1.0 / 720.0);
float2 size = abs(input.Size);
float2 texture = float2(input.Size.x < 0 ? 1.0 - input.Texture.x : input.Texture.x,
input.Size.y < 0 ? 1.0 - input.Texture.y : input.Texture.y);
VSOutput output = (VSOutput)0;
output.Position = float4(input.Position, 0, 1);
output.Texture = input.Texture;
float2 position = (input.Texture * size + input.TopLeft) * inversePixel;
output.Position = float4(position * 2.0 - 1.0, 0, 1);
output.Texture = texture;
output.TextureIndex = input.TextureIndex;
output.Color = input.Color;
return output;
}
float4 PSGradient1(VSOutput input) : SV_TARGET
{
float a = smoothstep(0.05, 0.2, input.Texture.x);
float b = 1.0 - smoothstep(0.8, 0.95, input.Texture.x);
float c = smoothstep(0.05, 0.2, input.Texture.y);
float d = a * b * c * 0.5;
float3 color = float3(1.0, 1.0, 1.0);
return float4(color, d);
}
float4 PSGradient2(VSOutput input) : SV_TARGET
{
float a = smoothstep(0.05, 0.2, input.Texture.x);
float b = 1.0 - smoothstep(0.8, 0.95, input.Texture.x);
float d = a * b * 0.5;
float3 color = float3(1.0, 1.0, 1.0);
return float4(color, d);
}
float4 PSGradient3(VSOutput input) : SV_TARGET
{
float a = smoothstep(0.02, 0.1, input.Texture.x);
float b = 1.0 - smoothstep(0.9, 0.98, input.Texture.x);
float d = a * b * 0.5;
float3 color = float3(1.0, 1.0, 1.0);
return float4(color, d);
}
[shader("pixel")]
float4 PSMain(VSOutput input) : SV_TARGET
{
float4 color = Texture[input.TextureIndex].Sample(ClosestSampler, input.Texture);
return float4(color.xyz, 1.0);
float4 color;
if (input.TextureIndex >= 0) {
color = Texture[input.TextureIndex].Sample(ClosestSampler, input.Texture);
} else if (input.TextureIndex == -1) {
color = float4(input.Color.xyz, 1.0);
} else if (input.TextureIndex == -2) {
return PSGradient1(input);
} else if (input.TextureIndex == -3) {
return PSGradient2(input);
} else if (input.TextureIndex == -4) {
return PSGradient2(input);
} else {
return float4(1, 0, 0, 1);
}
if (color.w == 0.0)
discard;
float gamma = 2.2;
color.xyz = pow(color.xyz, float3(gamma.xxx));
return float4(color.xyzw);
}

View File

@ -12,6 +12,7 @@
#include "font/outline.h"
#include "font/outline_types.h"
#include "renpy/script.h"
namespace font::outline {
static const _Float16 vertexData[] = {
@ -57,7 +58,7 @@ namespace font::outline {
load_vertex_index_buffer();
load_shader();
create_descriptor_sets();
loadedFont = load_font(uncial_antiqua[0]);
loadedFont = load_font(medieval_sharp[0]);
create_glyphs_buffer(loadedFont.font, loadedFont.glyphs);
write_descriptor_sets(loadedFont.allocatedImage.imageView);
create_instance_buffers();
@ -184,7 +185,14 @@ namespace font::outline {
};
VkPipelineColorBlendAttachmentState blendAttachment{
.colorWriteMask = 0xF
.blendEnable = VK_TRUE,
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.alphaBlendOp = VK_BLEND_OP_ADD,
.colorWriteMask = 0xF,
};
VkPipelineColorBlendStateCreateInfo colorBlendState{
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
@ -603,41 +611,130 @@ namespace font::outline {
vkUnmapMemory(device, glyphsMemory);
}
//////////////////////////////////////////////////////////////////////
// draw
//////////////////////////////////////////////////////////////////////
void font::draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex)
void font::emit_line(int frameIndex,
char const * const string,
uint32_t x, uint32_t y,
int& outputIndex,
int startIndex,
int endIndex,
uint32_t color)
{
// transfer
const char * string = "so when Nico wants to run this game on his\n4K monitor, he gets a dinky little 1280x720\nwindow instead?";
int outputIndex = 0;
int stringIndex = 0;
for (int i = startIndex; i < endIndex; i++) {
char c = string[i];
types::glyph const& glyph = loadedFont.glyphs[c - 32];
if (c != ' ' && c != '\n') {
instanceMappedData[maximumGlyphCount * frameIndex + outputIndex++] = {
(uint16_t)((x + glyph.metrics.horiBearingX) >> 6),
(uint16_t)((y - glyph.metrics.horiBearingY) >> 6),
(uint32_t)(c - 32),
color,
};
}
x += glyph.metrics.horiAdvance;
}
}
void font::centered(int frameIndex, char const * const string, uint32_t& x, uint32_t& y,
uint32_t minX,
uint32_t maxWidth,
int& outputIndex,
uint32_t color)
{
int stringIndex = 0;
int lineStart = stringIndex;
int lineWidth = 0;
uint32_t leftOffset = 0;
uint32_t x = 64 << 6;
uint32_t y = 64 << 6;
while (true) {
char c = string[stringIndex++];
if (c == 0)
break;
if (c != ' ') {
instanceMappedData[maximumGlyphCount * frameIndex + outputIndex++] = {
(uint16_t)((x + loadedFont.glyphs[c - 32].metrics.horiBearingX) >> 6),
(uint16_t)((y - loadedFont.glyphs[c - 32].metrics.horiBearingY) >> 6),
(uint32_t)(c - 32),
0xaabbccdd,
};
if (c == '\n') {
continue;
}
if (c == '\n') {
types::glyph const& glyph = loadedFont.glyphs[c - 32];
if (lineWidth == 0) {
leftOffset = glyph.metrics.horiBearingX;
}
lineWidth += glyph.metrics.horiAdvance;
if ((lineWidth - leftOffset) + loadedFont.font->face_metrics.max_advance > (maxWidth << 6)) {
while (string[stringIndex] != ' ') {
char c = string[--stringIndex];
types::glyph const& glyph = loadedFont.glyphs[c - 32];
lineWidth -= glyph.metrics.horiAdvance;
}
uint32_t center = (minX + (maxWidth / 2)) << 6;
uint32_t left = center - (lineWidth / 2);
emit_line(frameIndex, string, left - leftOffset, y, outputIndex, lineStart, stringIndex, color);
while (string[stringIndex] == ' ') stringIndex++;
lineStart = stringIndex;
lineWidth = 0;
y += loadedFont.font->face_metrics.height * 1.2;
x = 64 << 6;
} else {
x += loadedFont.glyphs[c - 32].metrics.horiAdvance;
x = minX << 6;
}
};
if (stringIndex != lineStart) {
uint32_t center = (minX + (maxWidth / 2)) << 6;
uint32_t left = center - (lineWidth / 2);
emit_line(frameIndex, string, left - leftOffset, y, outputIndex, lineStart, stringIndex, color);
y += loadedFont.font->face_metrics.height * 1.2;
x = minX << 6;
}
}
//////////////////////////////////////////////////////////////////////
// draw
//////////////////////////////////////////////////////////////////////
void font::draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex,
renpy::interpreter const& state)
{
// transfer
int outputIndex = 0;
if (state.menu.count == 0) {
if (state.say.stringIndex != -1u) {
char const * const string = renpy::script::strings[state.say.stringIndex];
uint32_t x = textboxLeft << 6;
uint32_t y = 590 << 6;
centered(frameIndex, string,
x, y,
textboxLeft, textboxWidth,
outputIndex,
0x000000);
}
if (state.say.characterIndex != -1u) {
const renpy::language::character & character = renpy::script::characters[state.say.characterIndex];
char const * const string = character.characterName;
uint32_t x = 580 << 6;
uint32_t y = 550 << 6;
centered(frameIndex, string,
x, y,
580, 118,
outputIndex,
character.color);
}
} else {
for (uint32_t i = 0; i < state.menu.count; i++) {
uint32_t x = 400 << 6;
uint32_t y = (100 * i + 130) << 6;
centered(frameIndex, renpy::script::options[state.menu.optionIndex + i].string,
x, y,
400, 480,
outputIndex,
0x000000);
}
}
// flush
constexpr int mappedMemoryRangesCount = 1;
VkMappedMemoryRange mappedMemoryRanges[mappedMemoryRangesCount]{

View File

@ -22,6 +22,7 @@
#include "minecraft/vulkan.h"
#include "font/outline.h"
#include "renpy/vulkan.h"
#include "renpy/interpreter.h"
#include "scenes/shadow_test/shadow_test.h"
#include "scenes/eidelwind/eidelwind.h"
@ -716,6 +717,14 @@ int main()
textureSamplers[2]);
renpy_state.init();
//////////////////////////////////////////////////////////////////////
// interpreter
//////////////////////////////////////////////////////////////////////
renpy::interpreter interpreter_state;
interpreter_state.reset();
interpreter_state.interpret();
//////////////////////////////////////////////////////////////////////
// initialize view
//////////////////////////////////////////////////////////////////////
@ -1073,8 +1082,8 @@ int main()
//minecraft_state.draw(commandBuffer, frameIndex);
renpy_state.draw(commandBuffer, frameIndex);
font_state.draw(commandBuffer, frameIndex);
renpy_state.draw(commandBuffer, frameIndex, interpreter_state);
font_state.draw(commandBuffer, frameIndex, interpreter_state);
vkCmdEndRendering(commandBuffer);

134
src/renpy/interpreter.cpp Normal file
View File

@ -0,0 +1,134 @@
#include <assert.h>
#include <stdio.h>
#include "renpy/script.h"
#include "renpy/interpreter.h"
namespace renpy {
void interpreter::reset()
{
pc = 0;
backgroundIndex = -1;
backgroundColor = 0;
shownImagesCount = 0;
say.stringIndex = -1;
say.characterIndex = -1;
menu.count = 0;
}
uint32_t interpreter::findImage(uint32_t imageIndex)
{
for (uint32_t i = 0; i < shownImagesCount; i++) {
if (shownImages[i].imageIndex == imageIndex) {
return i;
}
}
return ~0u;
}
void interpreter::showImage(uint32_t imageIndex, uint32_t transformIndex)
{
uint32_t shownImageIndex = findImage(imageIndex);
if (shownImageIndex == ~0u) {
shownImageIndex = shownImagesCount;
shownImagesCount += 1;
}
shownImages[shownImageIndex].imageIndex = imageIndex;
shownImages[shownImageIndex].transformIndex = transformIndex;
assert(shownImagesCount <= maximumShownImagesCount);
printf("shownImagesCount: %d\n", shownImagesCount);
}
void interpreter::hideImage(uint32_t imageIndex)
{
uint32_t shownImageIndex = findImage(imageIndex);
if (shownImageIndex == ~0u)
return;
for (uint32_t i = shownImageIndex; i < (shownImagesCount - 1); i++) {
shownImages[i] = shownImages[i+1];
printf("here\n");
}
printf("return\n");
shownImagesCount -= 1;
}
void interpreter::interpret_one()
{
assert(pc < (uint32_t)script::statements_length);
language::statement const& statement = script::statements[pc];
switch (statement.type) {
case language::type::play:
fprintf(stderr, "interpret_one[%d]: play\n", pc);
pc += 1;
break;
case language::type::scene_color:
fprintf(stderr, "interpret_one[%d]: scene_color\n", pc);
backgroundIndex = -1;
backgroundColor = statement.scene_color.color;
pc += 1;
break;
case language::type::scene:
fprintf(stderr, "interpret_one[%d]: scene\n", pc);
assert(statement.scene.imageIndex < (uint32_t)script::images_length);
backgroundIndex = statement.scene.imageIndex;
shownImagesCount = 0;
say.stringIndex = -1;
say.characterIndex = -1;
pc += 1;
break;
case language::type::say:
fprintf(stderr, "interpret_one[%d]: say\n", pc);
assert(statement.say.stringIndex < (uint32_t)script::strings_length);
say.stringIndex = statement.say.stringIndex;
say.characterIndex = statement.say.characterIndex;
pc += 1;
break;
case language::type::hide:
fprintf(stderr, "interpret_one[%d]: hide\n", pc);
assert(statement.show.imageIndex < (uint32_t)script::images_length);
assert(statement.show.transformIndex < transformsCount);
hideImage(statement.show.imageIndex);
pc += 1;
break;
case language::type::show:
fprintf(stderr, "interpret_one[%d]: show\n", pc);
assert(statement.show.imageIndex < (uint32_t)script::images_length);
assert(statement.show.transformIndex < transformsCount);
showImage(statement.show.imageIndex, statement.show.transformIndex);
pc += 1;
break;
case language::type::menu:
fprintf(stderr, "interpret_one[%d]: menu\n", pc);
assert(statement.menu.optionIndex < (uint32_t)script::options_length);
assert(statement.menu.count > 0);
menu.count = statement.menu.count;
menu.optionIndex = statement.menu.optionIndex;
pc += 1;
break;
default:
fprintf(stderr, "unknown statement type at pc %d\n", pc);
pc += 1;
break;
}
}
void interpreter::interpret()
{
while (true) {
uint32_t last_pc = pc;
interpret_one();
assert(pc != last_pc);
if (pc == 17) {
break;
}
//if (stop)
//break;
}
}
};

488
src/renpy/script.cpp Normal file
View File

@ -0,0 +1,488 @@
#include "renpy/language.h"
#include "renpy/script.h"
namespace renpy::script {
using namespace renpy::language;
char const * const strings[] = {
"Far over the mountains of Almystice", // 0
"Beyond the tumultuous waters of the Lilac Bay", // 1
"And across the vast fields of Alysen", // 2
"Tiny minstrels can be heard amongst the trees", // 3
"Are we almost there?", // 4
"Hmmm... Not really", // 5
"How much further have we to go?", // 6
"About two more moons", // 7
"We are still sooo far awayyy", // 8
"And it will be even further if you dont stop complaining", // 9
"Easy for you to say, all you have to carry is a little memory pipe!", // 10
"I'm tired ><", // 11
"Don't start whining now!", // 12
"You need to remember why we have come all this way", // 13
"I understand... I suppose it is for an important purpose", // 14
"We're almost out of the forest, we can take a little break once we clear the tree line", // 15
"Is that where the flora field is?", // 16
"Why yes, If I remember correctly, it should be just up ahead", // 17
"As the minstrel mice girls continue along the path, the forest opens up into a beautiful field of flowers", // 18
"Look at all the butterflies! They are all so pretty!", // 19
"This place is like a dream...", // 20
"There are so many flowers this time of year", // 21
"I told you it would be worth the journey!", // 22
"Can we stop for a bit now?", // 23
"Of course", // 24
"Ya know, Its a shame we didnt save some of those giant strawberries you found", // 25
"I told you not to eat them all!", // 26
"Yah yah", // 27
"Anyways, shall I recite a tale?", // 28
"Why dont you sing the story of Eleanor the Hero!", // 29
"Sure", // 30
"...", // 31
"Serves you right for scaring those elephant-dogs", // 32
"They were asking for it, you know", // 33
"Rawrrrr", // 34
"AHHHHHHHHHH!!!!!", // 35
"Nyanyanyanya", // 36
"Well, what do we have here? If it isn't two little meowse girls, all alone amongst the flowers", // 37
"Please don't eat us!!!", // 38
"Alice don't run, our only chance is through pleading!", // 39
"Please don't eat us, miss kitty cat!!! ><", // 40
"I'm not gonna eat you nyanyanya", // 41
"I just want to know what two little meowses are doing so very far away from home", // 42
"Also, are you minstrels?", // 43
"Y-Yes", // 44
"W-We are on a quest to Castle Alysen...", // 45
"Shh don't tell her that", // 46
"The Castle of Alysen you say?!?", // 47
"Why, that's where I am headed!", // 48
"You don't say...", // 49
"Yah, I do actually", // 50
"So... Why might you be traveling to the castle?", // 51
"I belong to the lineage of Agrepen", // 52
"And what might that mean?", // 53
"The Agrepens are a long line of felines loyal to the crown of corvidae", // 54
"Really? That must mean you are a noble?", // 55
"Well, not really...", // 56
"My father was one of the queens knights many years ago", // 57
"Ah I see", // 58
"So do you live at the castle or something?", // 59
"Well, no...", // 60
"Then why are you traveling to Castle Alysen?", // 61
"uhhh", // 62
"I DONT NEED TO BE PRESSURED BY LITTLE MICE TO SAY ANYTHING!!!!", // 63
"GOOD DAY!", // 64
"Wha...", // 65
"Phew, I was scared she was gonna follow us the whole way", // 66
"She didn't seem so bad", // 67
"Are you kidding? She's a crazy kitty!", // 68
"After their encounter with the weird cat, the mice scurry out of the flower field and into the nearby meadow", // 69
"I think this is the right way...", // 70
"Then where did the path go?", // 71
"How am I supposed to know?", // 72
"Did you hear that?!?!", // 73
"Hey there...", // 74
"I apologize", // 75
"I didn't mean to storm off like that", // 76
"Ha ha, no problem...", // 77
"So... Why are you traveling to Castle Alysen?", // 78
"Alice!!!", // 79
"If you must know, I have been summoned by the queen", // 80
"I suspect that my poor reputation amongst the locals of Eastern Nidus has come back to haunt me", // 81
"Though I know not what what she has summoned me for", // 82
"Ahhhhhh", // 83
"So then...", // 84
"Why are YOU traveling to the Castle?", // 85
"We are delivering a feather!!!", // 86
"Alice no!", // 87
"A feather that belonged to the queen herself!!!", // 88
"Why you little...", // 89
"A feather you say? One of the queens?", // 90
"How on the face of Al Mot might you have aquired such a thing?", // 91
"If it is authentic, that is...", // 92
"Since Alice cannot keep a secret, I shall tell you", // 93
"Seven moons ago, our town was attacked by three owls and a band of mice from the northern principalities", // 94
"Eventually word spread to greater nearby settlements, and so", // 95
"Messengers from the keep in Musia sent for aid from the Ravens", // 96
"Four moons ago, the request was answered", // 97
"And a small group of mice accompanied by two ravens a fox, and three squirrels set out to the northern principalities", // 98
"Anyways, long story short, we drove those barbaric rats out of their home", // 99
"They arent actual rats you know", // 100
"Obviously, but you wont catch me speaking kindly of them", // 101
"And you forgot the most important part", // 102
"Yah yah, I am getting there", // 103
"So, essentially, my brother is trained in archery, and...", // 104
"Speed it up already", // 105
"You tell it then!", // 106
"My cousin found this feather in one of the highest towers of a castle far to the north", // 107
"How do you know it belongs to the queen?", // 108
"It said so itself above the display on the wall", // 109
"Supposedly, it was in a room filled with treasures!", // 110
"That is very nice and all, but what are the two of you doing out here all alone?", // 111
"Do you expect every bird in Avia to respect your alliance with Castle Alysen?", // 112
"What do you mean?", // 113
"I mean, the two of you probably look like walking dinner to most creatures", // 114
"I could go for some dinner...", // 115
"Anyways...", // 116
"To answer your question, upon returning to the village, the feather was taken from my brother by the needle guild", // 117
"So... Yesterday, after sundown", // 118
"We stole the feather from the guild hall before vanishing into the night", // 119
"Can you imagine the look on their stupid faces, when they woke up, and not only is the feather missing", // 120
"But so are we!", // 121
"Hahahaha", // 122
"Are the two of you mad?", // 123
"I assume you are attempting to return the Queens feather?", // 124
"Yes, we intend to deliver the feather to its rightful owner", // 125
"Absolute madness!", // 126
"I will follow the two of you", // 127
"To keep you safe, that is", // 128
"Alright!", // 129
"Ha ha... Okay...", // 130
"Great! Follow me, I know a shortcut! :3", // 131
"Sounds good!", // 132
"Oh dear!", // 133
"And so the mice girls follow the noble cat further towards their destination", // 134
"Nya", // 135
"Look, your right, the castle is just up ahead!", // 136
"Wait up", // 137
"I told you I knew a shortcut!", // 138
"Most people take the long way around", // 139
"Yah because these are royal wheatfields!", // 140
"Who cares?", // 141
"Are you trying to get us killed?", // 142
"Its trespassing on royal land!", // 143
"Calm down, I have done this a million times", // 144
"That doesnt make me calm!", // 145
"How can the rolling fields of wheat not calm your spirit?", // 146
"You little mice truly are mad!", // 147
"I like the wheat!", // 148
"Shut up!", // 149
"Sounds like someone needs a nap!", // 150
"Why? because I'm not insane like you?", // 151
"Yah, your so sane, that you decided to steal from your town and then run off alone to the country of birds", // 152
"The power of friendship wont protect the two of you from becoming dinner", // 153
"And that, is why I feel obligated to accompany you!", // 154
"Hey, we have a good reason!", // 155
"And what might that be?", // 156
"My brother found the feather, not the town guild, its a matter of family pride!", // 157
"Pride has touched the chosen meouse", // 158
"Flies she towards the Castle", // 159
"But her ambition burns far too bright, and silly myice dont have any wings to myelt", // 160
"What?", // 161
"Nyanyanya", // 162
"Nyevermind", // 163
"Sing me a song little minstrels!", // 164
"Very Nyice!", // 165
"Now tell me little minstrels, what are your names?", // 166
"My name is Alice", // 167
"And my name is Eily", // 168
"What is your name?", // 169
"My name is Leona!", // 170
"And so, the odd trio walked through the wheatfields and towards the castle walls", // 171
"Upon approaching the castle walls", // 172
};
const int strings_length = (sizeof (strings)) / (sizeof (strings[0]));
const language::character characters[] = {
{ .characterName = "Alice", .color = 0x00765e }, // 0
{ .characterName = "Cat", .color = 0x590093 }, // 1
{ .characterName = "Eily", .color = 0x0b6092 }, // 2
{ .characterName = "Mouse Girls", .color = 0x000000 }, // 3
{ .characterName = "Narrator", .color = 0x000000 }, // 4
{ .characterName = "Leona", .color = 0x590093 }, // 5
};
const int characters_length = (sizeof (characters)) / (sizeof (characters[0]));
const language::audio audio[] = {
{ .path = "sfx/Chime.opus" }, // 0 sfx/Chime.ogg
{ .path = "sfx/MistAmbience.opus" }, // 1 sfx/MistAmbience.ogg
{ .path = "music/TinyForestMinstrels.opus" }, // 2 music/TinyForestMinstrels.ogg
{ .path = "n5test.opus" }, // 3 n5test.ogg
{ .path = "music/PhrygianButterflies.opus" }, // 4 music/PhrygianButterflies.ogg
{ .path = "music/Poem1.opus" }, // 5 music/Poem1.ogg
{ .path = "placeholdermeow.opus" }, // 6 placeholdermeow.mp3
{ .path = "music/ScaredMice.opus" }, // 7 music/ScaredMice.ogg
{ .path = "music/WheatFields.opus" }, // 8 music/WheatFields.ogg
};
const int audio_length = (sizeof (audio)) / (sizeof (audio[0]));
const language::image images[] = {
{ .path = "data/renpy/images/flowers.dds" }, // 0 flowers.png
{ .path = "data/renpy/images/bg/forest1.dds" }, // 1 bg/forest1.png
{ .path = "data/renpy/images/bg/forest2.dds" }, // 2 bg/forest2.png
{ .path = "data/renpy/images/bg/flowerfield1.dds" }, // 3 bg/flowerfield1.png
{ .path = "data/renpy/images/bg/wheatfield1.dds" }, // 4 bg/wheatfield1.png
{ .path = "data/renpy/images/ch/cat.dds" }, // 5 ch/cat.png
{ .path = "data/renpy/images/ch/catw.dds" }, // 6 ch/catw.png
{ .path = "data/renpy/images/ch/Eily.dds" }, // 7 ch/Eily.png
{ .path = "data/renpy/images/ch/Alice.dds" }, // 8 ch/Alice.png
};
const int images_length = (sizeof (images)) / (sizeof (images[0]));
const language::option options[] = {
{ .string = "Complain", .statementIndex = 18 }, // 0
{ .string = "Rationalize", .statementIndex = 26 }, // 1
{ .string = "Good idea", .statementIndex = 54 }, // 2
{ .string = "I am too tired", .statementIndex = 61 }, // 3
{ .string = "Beg for mercy", .statementIndex = 78 }, // 4
{ .string = "Run", .statementIndex = 80 }, // 5
};
const int options_length = (sizeof (options)) / (sizeof (options[0]));
const language::statement statements[] = {
{ .type = type::play, .play = { .audioIndex = 0, /* FIXME channel */ } }, // 0 sfx/Chime.ogg
{ .type = type::play, .play = { .audioIndex = 1, /* FIXME channel */ } }, // 1 sfx/MistAmbience.ogg
{ .type = type::scene_color, .scene_color = { .color = 0xffffff } }, // 2 bgwhite
{ .type = type::dissolve, .dissolve = { .duration = 3.0 } }, // 3
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 0 } }, // 4 n "Far over the mountains of Almystice"
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 1 } }, // 5 n "Beyond the tumultuous waters of the Lilac Bay"
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 2 } }, // 6 n "And across the vast fields of Alysen"
{ .type = type::play, .play = { .audioIndex = 2, /* FIXME channel */ } }, // 7 music/TinyForestMinstrels.ogg
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 3 } }, // 8 n "Tiny minstrels can be heard amongst the trees"
{ .type = type::scene, .scene = { .imageIndex = 1 } }, // 9 bgforest1
{ .type = type::dissolve, .dissolve = { .duration = 3.0 } }, // 10
{ .type = type::show, .show = { .imageIndex = 8, .transformIndex = transform::left } }, // 11 al
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 4 } }, // 12 a "Are we almost there?"
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::right } }, // 13 ei
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 5 } }, // 14 e "Hmmm... Not really"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 6 } }, // 15 a "How much further have we to go?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 7 } }, // 16 e "About two more moons"
{ .type = type::menu, .menu = { .count = 2, .optionIndex = 0 } }, // 17 "Complain", "Rationalize"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 8 } }, // 18 a "We are still sooo far awayyy"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 9 } }, // 19 e "And it will be even further if you dont stop complaining"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 10 } }, // 20 a "Easy for you to say, all you have to carry is a little memory pipe!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 11 } }, // 21 a "I'm tired ><"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 12 } }, // 22 e "Don't start whining now!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 13 } }, // 23 e "You need to remember why we have come all this way"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 14 } }, // 24 a "I understand... I suppose it is for an important purpose"
{ .type = type::jump, .jump = { .statementIndex = 28 } }, // 25 internal jump (b'__menu_end', 0)
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 14 } }, // 26 a "I understand... I suppose it is for an important purpose"
{ .type = type::jump, .jump = { .statementIndex = 28 } }, // 27 internal jump (b'__menu_end', 0)
{ .type = type::jump, .jump = { .statementIndex = 29 } }, // 28 mainbranch1
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 15 } }, // 29 e "We're almost out of the forest, we can take a little break once we clear the tree line"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 16 } }, // 30 a "Is that where the flora field is?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 17 } }, // 31 e "Why yes, If I remember correctly, it should be just up ahead"
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 32
{ .type = type::scene_color, .scene_color = { .color = 0xffffff } }, // 33 bgwhite
{ .type = type::play, .play = { .audioIndex = 0, /* FIXME channel */ } }, // 34 sfx/Chime.ogg
{ .type = type::dissolve, .dissolve = { .duration = 1.0 } }, // 35
{ .type = type::voice, .voice = { .audioIndex = 3 } }, // 36 n5test.ogg
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 18 } }, // 37 n "As the minstrel mice girls continue along the path, the forest opens up into a beautiful field of flowers"
{ .type = type::play, .play = { .audioIndex = 4, /* FIXME channel */ } }, // 38 music/PhrygianButterflies.ogg
{ .type = type::scene, .scene = { .imageIndex = 3 } }, // 39 bgflower1
{ .type = type::dissolve, .dissolve = { .duration = 1.0 } }, // 40
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::right } }, // 41 ei
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 19 } }, // 42 e "Look at all the butterflies! They are all so pretty!"
{ .type = type::show, .show = { .imageIndex = 8, .transformIndex = transform::left } }, // 43 al
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 20 } }, // 44 a "This place is like a dream..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 21 } }, // 45 e "There are so many flowers this time of year"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 22 } }, // 46 e "I told you it would be worth the journey!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 23 } }, // 47 a "Can we stop for a bit now?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 24 } }, // 48 e "Of course"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 25 } }, // 49 e "Ya know, Its a shame we didnt save some of those giant strawberries you found"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 26 } }, // 50 a "I told you not to eat them all!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 27 } }, // 51 e "Yah yah"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 28 } }, // 52 e "Anyways, shall I recite a tale?"
{ .type = type::menu, .menu = { .count = 2, .optionIndex = 2 } }, // 53 "Good idea", "I am too tired"
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 54
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 29 } }, // 55 a "Why dont you sing the story of Eleanor the Hero!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 30 } }, // 56 e "Sure"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 31 } }, // 57 a "..."
{ .type = type::play, .play = { .audioIndex = 5, /* FIXME channel */ } }, // 58 music/Poem1.ogg
{ .type = type::pause, .pause = { .duration = 40 } }, // 59
{ .type = type::jump, .jump = { .statementIndex = 65 } }, // 60 internal jump (b'__menu_end', 1)
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 32 } }, // 61 e "Serves you right for scaring those elephant-dogs"
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 62
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 33 } }, // 63 a "They were asking for it, you know"
{ .type = type::jump, .jump = { .statementIndex = 65 } }, // 64 internal jump (b'__menu_end', 1)
{ .type = type::jump, .jump = { .statementIndex = 66 } }, // 65 mainbranch2
{ .type = type::hide, .hide = { .imageIndex = 7 } }, // 66 ei
{ .type = type::show, .show = { .imageIndex = 6, .transformIndex = transform::right } }, // 67 catw
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::centerleft } }, // 68 ei
{ .type = type::voice, .voice = { .audioIndex = 6 } }, // 69 placeholdermeow.mp3
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 34 } }, // 70 c "Rawrrrr"
{ .type = type::hide, .hide = { .imageIndex = 6 } }, // 71 catw
{ .type = type::show, .show = { .imageIndex = 5, .transformIndex = transform::right } }, // 72 cat
{ .type = type::play, .play = { .audioIndex = 7, /* FIXME channel */ } }, // 73 music/ScaredMice.ogg
{ .type = type::say, .say = { .characterIndex = 3, .stringIndex = 35 } }, // 74 mg "AHHHHHHHHHH!!!!!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 36 } }, // 75 c "Nyanyanyanya"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 37 } }, // 76 c "Well, what do we have here? If it isn't two little meowse girls, all alone amongst the flowers"
{ .type = type::menu, .menu = { .count = 2, .optionIndex = 4 } }, // 77 "Beg for mercy", "Run"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 38 } }, // 78 a "Please don't eat us!!!"
{ .type = type::jump, .jump = { .statementIndex = 83 } }, // 79 internal jump (b'__menu_end', 2)
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 39 } }, // 80 e "Alice don't run, our only chance is through pleading!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 40 } }, // 81 e "Please don't eat us, miss kitty cat!!! ><"
{ .type = type::jump, .jump = { .statementIndex = 83 } }, // 82 internal jump (b'__menu_end', 2)
{ .type = type::jump, .jump = { .statementIndex = 84 } }, // 83 mainbranch3
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 84
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 41 } }, // 85 c "I'm not gonna eat you nyanyanya"
{ .type = type::play, .play = { .audioIndex = 2, /* FIXME channel */ } }, // 86 music/TinyForestMinstrels.ogg
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 42 } }, // 87 c "I just want to know what two little meowses are doing so very far away from home"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 43 } }, // 88 c "Also, are you minstrels?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 44 } }, // 89 e "Y-Yes"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 45 } }, // 90 a "W-We are on a quest to Castle Alysen..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 46 } }, // 91 e "Shh don't tell her that"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 47 } }, // 92 c "The Castle of Alysen you say?!?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 48 } }, // 93 c "Why, that's where I am headed!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 49 } }, // 94 e "You don't say..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 50 } }, // 95 c "Yah, I do actually"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 51 } }, // 96 e "So... Why might you be traveling to the castle?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 52 } }, // 97 c "I belong to the lineage of Agrepen"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 53 } }, // 98 e "And what might that mean?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 54 } }, // 99 c "The Agrepens are a long line of felines loyal to the crown of corvidae"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 55 } }, // 100 e "Really? That must mean you are a noble?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 56 } }, // 101 c "Well, not really..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 57 } }, // 102 c "My father was one of the queens knights many years ago"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 58 } }, // 103 e "Ah I see"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 59 } }, // 104 e "So do you live at the castle or something?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 60 } }, // 105 c "Well, no..."
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 61 } }, // 106 a "Then why are you traveling to Castle Alysen?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 62 } }, // 107 c "uhhh"
{ .type = type::play, .play = { .audioIndex = 1, /* FIXME channel */ } }, // 108 sfx/MistAmbience.ogg
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 109
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 63 } }, // 110 c "I DONT NEED TO BE PRESSURED BY LITTLE MICE TO SAY ANYTHING!!!!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 64 } }, // 111 c "GOOD DAY!"
{ .type = type::hide, .hide = { .imageIndex = 5 } }, // 112 cat
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 65 } }, // 113 a "Wha..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 66 } }, // 114 e "Phew, I was scared she was gonna follow us the whole way"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 67 } }, // 115 a "She didn't seem so bad"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 68 } }, // 116 e "Are you kidding? She's a crazy kitty!"
{ .type = type::scene_color, .scene_color = { .color = 0xffffff } }, // 117 bgwhite
{ .type = type::play, .play = { .audioIndex = 0, /* FIXME channel */ } }, // 118 sfx/Chime.ogg
{ .type = type::dissolve, .dissolve = { .duration = 3.0 } }, // 119
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 69 } }, // 120 n "After their encounter with the weird cat, the mice scurry out of the flower field and into the nearby meadow"
{ .type = type::scene, .scene = { .imageIndex = 2 } }, // 121 bgforest2
{ .type = type::dissolve, .dissolve = { .duration = 3.0 } }, // 122
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::right } }, // 123 ei
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 70 } }, // 124 e "I think this is the right way..."
{ .type = type::show, .show = { .imageIndex = 8, .transformIndex = transform::left } }, // 125 al
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 71 } }, // 126 a "Then where did the path go?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 72 } }, // 127 e "How am I supposed to know?"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 73 } }, // 128 a "Did you hear that?!?!"
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::centerleft } }, // 129 ei
{ .type = type::show, .show = { .imageIndex = 5, .transformIndex = transform::right } }, // 130 cat
{ .type = type::play, .play = { .audioIndex = 4, /* FIXME channel */ } }, // 131 music/PhrygianButterflies.ogg
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 74 } }, // 132 c "Hey there..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 75 } }, // 133 c "I apologize"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 76 } }, // 134 c "I didn't mean to storm off like that"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 77 } }, // 135 e "Ha ha, no problem..."
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 78 } }, // 136 a "So... Why are you traveling to Castle Alysen?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 79 } }, // 137 e "Alice!!!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 80 } }, // 138 c "If you must know, I have been summoned by the queen"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 81 } }, // 139 c "I suspect that my poor reputation amongst the locals of Eastern Nidus has come back to haunt me"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 82 } }, // 140 c "Though I know not what what she has summoned me for"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 83 } }, // 141 a "Ahhhhhh"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 84 } }, // 142 c "So then..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 85 } }, // 143 c "Why are YOU traveling to the Castle?"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 86 } }, // 144 a "We are delivering a feather!!!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 87 } }, // 145 e "Alice no!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 88 } }, // 146 a "A feather that belonged to the queen herself!!!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 89 } }, // 147 e "Why you little..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 90 } }, // 148 c "A feather you say? One of the queens?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 91 } }, // 149 c "How on the face of Al Mot might you have aquired such a thing?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 92 } }, // 150 c "If it is authentic, that is..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 93 } }, // 151 e "Since Alice cannot keep a secret, I shall tell you"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 94 } }, // 152 e "Seven moons ago, our town was attacked by three owls and a band of mice from the northern principalities"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 95 } }, // 153 e "Eventually word spread to greater nearby settlements, and so"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 96 } }, // 154 e "Messengers from the keep in Musia sent for aid from the Ravens"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 97 } }, // 155 e "Four moons ago, the request was answered"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 98 } }, // 156 e "And a small group of mice accompanied by two ravens a fox, and three squirrels set out to the northern principalities"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 99 } }, // 157 e "Anyways, long story short, we drove those barbaric rats out of their home"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 100 } }, // 158 a "They arent actual rats you know"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 101 } }, // 159 e "Obviously, but you wont catch me speaking kindly of them"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 102 } }, // 160 a "And you forgot the most important part"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 103 } }, // 161 e "Yah yah, I am getting there"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 104 } }, // 162 e "So, essentially, my brother is trained in archery, and..."
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 105 } }, // 163 a "Speed it up already"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 106 } }, // 164 e "You tell it then!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 107 } }, // 165 a "My cousin found this feather in one of the highest towers of a castle far to the north"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 108 } }, // 166 c "How do you know it belongs to the queen?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 109 } }, // 167 e "It said so itself above the display on the wall"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 110 } }, // 168 a "Supposedly, it was in a room filled with treasures!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 111 } }, // 169 c "That is very nice and all, but what are the two of you doing out here all alone?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 112 } }, // 170 c "Do you expect every bird in Avia to respect your alliance with Castle Alysen?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 113 } }, // 171 e "What do you mean?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 114 } }, // 172 c "I mean, the two of you probably look like walking dinner to most creatures"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 115 } }, // 173 a "I could go for some dinner..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 116 } }, // 174 e "Anyways..."
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 117 } }, // 175 e "To answer your question, upon returning to the village, the feather was taken from my brother by the needle guild"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 118 } }, // 176 e "So... Yesterday, after sundown"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 119 } }, // 177 e "We stole the feather from the guild hall before vanishing into the night"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 120 } }, // 178 e "Can you imagine the look on their stupid faces, when they woke up, and not only is the feather missing"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 121 } }, // 179 e "But so are we!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 122 } }, // 180 a "Hahahaha"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 123 } }, // 181 c "Are the two of you mad?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 124 } }, // 182 c "I assume you are attempting to return the Queens feather?"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 125 } }, // 183 a "Yes, we intend to deliver the feather to its rightful owner"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 126 } }, // 184 c "Absolute madness!"
{ .type = type::say, .say = { .characterIndex = 3, .stringIndex = 31 } }, // 185 mg "..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 127 } }, // 186 c "I will follow the two of you"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 128 } }, // 187 c "To keep you safe, that is"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 129 } }, // 188 a "Alright!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 130 } }, // 189 e "Ha ha... Okay..."
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 131 } }, // 190 c "Great! Follow me, I know a shortcut! :3"
{ .type = type::hide, .hide = { .imageIndex = 5 } }, // 191 cat
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 132 } }, // 192 a "Sounds good!"
{ .type = type::hide, .hide = { .imageIndex = 8 } }, // 193 al
{ .type = type::stop, .stop = { /* FIXME channel */ } }, // 194
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 133 } }, // 195 e "Oh dear!"
{ .type = type::hide, .hide = { .imageIndex = 7 } }, // 196 ei
{ .type = type::scene_color, .scene_color = { .color = 0xffffff } }, // 197 bgwhite
{ .type = type::play, .play = { .audioIndex = 0, /* FIXME channel */ } }, // 198 sfx/Chime.ogg
{ .type = type::dissolve, .dissolve = { .duration = 2.0 } }, // 199
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 134 } }, // 200 n "And so the mice girls follow the noble cat further towards their destination"
{ .type = type::scene, .scene = { .imageIndex = 4 } }, // 201 bgwheatfield1
{ .type = type::play, .play = { .audioIndex = 8, /* FIXME channel */ } }, // 202 music/WheatFields.ogg
{ .type = type::show, .show = { .imageIndex = 5, .transformIndex = transform::right } }, // 203 cat
{ .type = type::dissolve, .dissolve = { .duration = 1.3 } }, // 204
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 135 } }, // 205 c "Nya"
{ .type = type::show, .show = { .imageIndex = 8, .transformIndex = transform::left } }, // 206 al
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 136 } }, // 207 a "Look, your right, the castle is just up ahead!"
{ .type = type::show, .show = { .imageIndex = 7, .transformIndex = transform::centerleft } }, // 208 ei
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 137 } }, // 209 e "Wait up"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 138 } }, // 210 c "I told you I knew a shortcut!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 139 } }, // 211 c "Most people take the long way around"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 140 } }, // 212 e "Yah because these are royal wheatfields!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 141 } }, // 213 a "Who cares?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 142 } }, // 214 e "Are you trying to get us killed?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 143 } }, // 215 e "Its trespassing on royal land!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 144 } }, // 216 c "Calm down, I have done this a million times"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 145 } }, // 217 e "That doesnt make me calm!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 146 } }, // 218 c "How can the rolling fields of wheat not calm your spirit?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 147 } }, // 219 c "You little mice truly are mad!"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 148 } }, // 220 a "I like the wheat!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 149 } }, // 221 e "Shut up!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 150 } }, // 222 c "Sounds like someone needs a nap!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 151 } }, // 223 e "Why? because I'm not insane like you?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 152 } }, // 224 c "Yah, your so sane, that you decided to steal from your town and then run off alone to the country of birds"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 153 } }, // 225 c "The power of friendship wont protect the two of you from becoming dinner"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 154 } }, // 226 c "And that, is why I feel obligated to accompany you!"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 155 } }, // 227 e "Hey, we have a good reason!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 156 } }, // 228 c "And what might that be?"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 157 } }, // 229 e "My brother found the feather, not the town guild, its a matter of family pride!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 158 } }, // 230 c "Pride has touched the chosen meouse"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 159 } }, // 231 c "Flies she towards the Castle"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 160 } }, // 232 c "But her ambition burns far too bright, and silly myice dont have any wings to myelt"
{ .type = type::say, .say = { .characterIndex = 3, .stringIndex = 161 } }, // 233 mg "What?"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 162 } }, // 234 c "Nyanyanya"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 163 } }, // 235 c "Nyevermind"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 164 } }, // 236 c "Sing me a song little minstrels!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 165 } }, // 237 c "Very Nyice!"
{ .type = type::say, .say = { .characterIndex = 1, .stringIndex = 166 } }, // 238 c "Now tell me little minstrels, what are your names?"
{ .type = type::say, .say = { .characterIndex = 0, .stringIndex = 167 } }, // 239 a "My name is Alice"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 168 } }, // 240 e "And my name is Eily"
{ .type = type::say, .say = { .characterIndex = 2, .stringIndex = 169 } }, // 241 e "What is your name?"
{ .type = type::say, .say = { .characterIndex = 5, .stringIndex = 170 } }, // 242 l "My name is Leona!"
{ .type = type::scene_color, .scene_color = { .color = 0xffffff } }, // 243 bgwhite
{ .type = type::dissolve, .dissolve = { .duration = 3.0 } }, // 244
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 171 } }, // 245 n "And so, the odd trio walked through the wheatfields and towards the castle walls"
{ .type = type::say, .say = { .characterIndex = 4, .stringIndex = 172 } }, // 246 n "Upon approaching the castle walls"
{ .type = type::_return }, // 247
};
const int statements_length = (sizeof (statements)) / (sizeof (statements[0]));
}

View File

@ -112,7 +112,7 @@ namespace renpy {
},
{
.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = script::images_length,
.descriptorCount = (uint32_t)script::images_length,
},
};
VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{
@ -138,7 +138,7 @@ namespace renpy {
{ // font image
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = script::images_length,
.descriptorCount = (uint32_t)script::images_length,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
}
};
@ -393,7 +393,14 @@ namespace renpy {
};
VkPipelineColorBlendAttachmentState blendAttachment{
.colorWriteMask = 0xF
.blendEnable = VK_TRUE,
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.alphaBlendOp = VK_BLEND_OP_ADD,
.colorWriteMask = 0xF,
};
VkPipelineColorBlendStateCreateInfo colorBlendState{
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
@ -426,7 +433,7 @@ namespace renpy {
},
};
constexpr int vertexAttributeDescriptionsCount = 5;
constexpr int vertexAttributeDescriptionsCount = 6;
VkVertexInputAttributeDescription vertexAttributeDescriptions[vertexAttributeDescriptionsCount]{
// per-vertex
{ // position
@ -445,21 +452,27 @@ namespace renpy {
{
.location = 2,
.binding = 1,
.format = VK_FORMAT_R16G16_UINT,
.format = VK_FORMAT_R16G16_SINT,
.offset = 0,
},
{
.location = 3,
.binding = 1,
.format = VK_FORMAT_R16G16_UINT,
.format = VK_FORMAT_R16G16_SINT,
.offset = 4,
},
{
.location = 4,
.binding = 1,
.format = VK_FORMAT_R16_UINT,
.format = VK_FORMAT_R8G8B8A8_UNORM,
.offset = 8,
},
{
.location = 5,
.binding = 1,
.format = VK_FORMAT_R16_SINT,
.offset = 12,
},
};
VkPipelineVertexInputStateCreateInfo vertexInputState{
@ -496,16 +509,61 @@ namespace renpy {
//////////////////////////////////////////////////////////////////////
void vulkan::draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex)
uint32_t frameIndex,
renpy::interpreter const& state)
{
int outputIndex = 0;
// update
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {1280, 720},
.topLeft = {0, 0},
.imageIndex = 3,
.color = state.backgroundColor,
.imageIndex = (int16_t)state.backgroundIndex,
};
for (uint32_t i = 0; i < state.shownImagesCount; i++) {
renpy::top_left const& tl = renpy::transforms[state.shownImages[i].transformIndex];
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {452, 528},
.topLeft = {(int16_t)tl.left, (int16_t)tl.top},
.imageIndex = (int16_t)state.shownImages[i].imageIndex,
};
}
if (state.menu.count == 0) {
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {708, 200},
.topLeft = {286, 720 - 200},
.imageIndex = -2, // white gradient 1
};
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {244, 200},
.topLeft = {336, 720 - 200},
.imageIndex = 0, // flower
};
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {-244, 200},
.topLeft = {1280 - (336 + 244), 720 - 200},
.imageIndex = 0, // flower
};
if (state.say.characterIndex != -1u) {
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {148, 30},
.topLeft = {560, 528},
.imageIndex = -4, // white gradient 2
};
}
} else {
for (uint32_t i = 0; i < state.menu.count; i++) {
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {480, 40},
.topLeft = {400, (int16_t)(100 * i + 100)},
.imageIndex = -3, // white gradient 2
};
}
}
// flush
constexpr int mappedMemoryRangesCount = 1;
VkMappedMemoryRange mappedMemoryRanges[mappedMemoryRangesCount]{