diff --git a/Makefile b/Makefile index 8d4ad62..070b6f3 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/data/font/outline/medieval_sharp_24.data b/data/font/outline/medieval_sharp_24.data new file mode 100644 index 0000000..546f67e Binary files /dev/null and b/data/font/outline/medieval_sharp_24.data differ diff --git a/data/renpy/images/bg/forest2.png b/data/renpy/images/bg/forest2.png new file mode 100644 index 0000000..892a05f Binary files /dev/null and b/data/renpy/images/bg/forest2.png differ diff --git a/data/renpy/images/flowers.png b/data/renpy/images/flowers.png new file mode 100644 index 0000000..33de539 Binary files /dev/null and b/data/renpy/images/flowers.png differ diff --git a/data/renpy/script.rpy b/data/renpy/script.rpy index c43b0f6..2efbea0 100644 --- a/data/renpy/script.rpy +++ b/data/renpy/script.rpy @@ -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" @@ -37,7 +37,7 @@ transform centerleft: transform centerright: - xalign 0.7 + xalign 0.7 yalign 1.0 @@ -48,7 +48,7 @@ init: renpy.music.register_channel("MistAmbience", "music", loop=False) renpy.music.register_channel("PhrygianButterflies", "music", loop=True) renpy.music.register_channel("WheatFields", "music", loop=True) - + # The game starts here. @@ -58,7 +58,7 @@ label start: # Show a background. This uses a placeholder by default, but you can # add a file (named either "bg room.png" or "bg room.jpg") to the # images directory to show it. - + #play Chime "sfx/Chime.ogg" fadeout 1.0 play sound "sfx/Chime.ogg" play MistAmbience "sfx/MistAmbience.ogg" @@ -102,9 +102,9 @@ label start: a "Easy for you to say, all you have to carry is a little memory pipe!" a "I'm tired ><" - e "Don't start whining now!" + e "Don't start whining now!" - e "You need to remember why we have come all this way" + e "You need to remember why we have come all this way" a "I understand... I suppose it is for an important purpose" @@ -115,9 +115,9 @@ label start: label mainbranch1: - e "We're almost out of the forest, we can take a little break once we clear the tree line" + e "We're almost out of the forest, we can take a little break once we clear the tree line" - a "Is that where the flora field is?" + a "Is that where the flora field is?" e "Why yes, If I remember correctly, it should be just up ahead" stop TinyForestMinstrels fadeout 5.5 @@ -129,19 +129,19 @@ label start: voice "n5test.ogg" n "As the minstrel mice girls continue along the path, the forest opens up into a beautiful field of flowers" - + play PhrygianButterflies "music/PhrygianButterflies.ogg" - + scene bgflower1 with Dissolve(1.0) show ei at right - e "Look at all the butterflies! They are all so pretty!" + e "Look at all the butterflies! They are all so pretty!" show al at left - + a "This place is like a dream..." @@ -173,16 +173,16 @@ label start: stop PhrygianButterflies fadeout 4.2 a "They were asking for it, you know" - - - + + + jump mainbranch2 #Improvise music in the butterfly field - #Choose Between: Fleeting and + #Choose Between: Fleeting and #Elri scares the mice #We learn why they want to petition the queen # elri: "Arent you sacred she will eat you?" @@ -190,17 +190,17 @@ label start: #Elri shows them to the wheat town with the castle in the distance #They wish to speak to the queen of birds, but arent important enough #Elri helps - - #Cat is summoned to see the Queen of birds + + #Cat is summoned to see the Queen of birds #Mouse girls realize its their only chance - + # - + #Lenient on Taxes #Removed from the map @@ -218,13 +218,13 @@ label start: show cat at right play ScaredMice "music/ScaredMice.ogg" - + mg "AHHHHHHHHHH!!!!!" - + c "Nyanyanyanya" c "Well, what do we have here? If it isn't two little meowse girls, all alone amongst the flowers" - + menu: "Beg for mercy" : a "Please don't eat us!!!" @@ -232,11 +232,11 @@ label start: "Run" : e "Alice don't run, our only chance is through pleading!" e "Please don't eat us, miss kitty cat!!! ><" - - - + + + jump mainbranch3 - + @@ -279,7 +279,7 @@ label start: c "Well, no..." a "Then why are you traveling to Castle Alysen?" - + c "uhhh" play MistAmbience "sfx/MistAmbience.ogg" @@ -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 @@ -312,7 +312,7 @@ label start: a "Then where did the path go?" e "How am I supposed to know?" - + a "Did you hear that?!?!" @@ -374,7 +374,7 @@ label start: e "You tell it then!" a "My cousin found this feather in one of the highest towers of a castle far to the north" - + c "How do you know it belongs to the queen?" e "It said so itself above the display on the wall" @@ -469,7 +469,7 @@ label start: c "You little mice truly are mad!" a "I like the wheat!" - + e "Shut up!" c "Sounds like someone needs a nap!" @@ -525,10 +525,10 @@ label start: - - - + + + @@ -539,4 +539,3 @@ label start: return - diff --git a/filenames.txt b/filenames.txt index d4dabb6..d2d2970 100644 --- a/filenames.txt +++ b/filenames.txt @@ -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 diff --git a/font.sh b/font.sh new file mode 100644 index 0000000..ceb165c --- /dev/null +++ b/font.sh @@ -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 diff --git a/include/font/outline.h b/include/font/outline.h index 683633e..7e19bc9 100644 --- a/include/font/outline.h +++ b/include/font/outline.h @@ -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); }; diff --git a/include/renpy/interpreter.h b/include/renpy/interpreter.h index e91e5cc..d0018ad 100644 --- a/include/renpy/interpreter.h +++ b/include/renpy/interpreter.h @@ -1,4 +1,8 @@ +#pragma once +#include + +#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(); }; } diff --git a/include/renpy/language.h b/include/renpy/language.h index 2b54854..184a28e 100644 --- a/include/renpy/language.h +++ b/include/renpy/language.h @@ -1,3 +1,5 @@ +#pragma once + #include 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; }; }; } diff --git a/include/renpy/script.h b/include/renpy/script.h index 42323c4..5b24357 100644 --- a/include/renpy/script.h +++ b/include/renpy/script.h @@ -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; } diff --git a/include/renpy/vulkan.h b/include/renpy/vulkan.h index 0c9a41e..c8d78bd 100644 --- a/include/renpy/vulkan.h +++ b/include/renpy/vulkan.h @@ -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); }; } diff --git a/renpy-parser/transform.py b/renpy-parser/transform.py index 16b3657..8f4bfa3 100644 --- a/renpy-parser/transform.py +++ b/renpy-parser/transform.py @@ -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(), diff --git a/shader/font.hlsl b/shader/font.hlsl index 4d7c7bf..5598b9d 100644 --- a/shader/font.hlsl +++ b/shader/font.hlsl @@ -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); } diff --git a/shader/renpy.hlsl b/shader/renpy.hlsl index ee001a7..843f48a 100644 --- a/shader/renpy.hlsl +++ b/shader/renpy.hlsl @@ -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); } diff --git a/src/font/outline.cpp b/src/font/outline.cpp index 0859cd0..007d3ea 100644 --- a/src/font/outline.cpp +++ b/src/font/outline.cpp @@ -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]{ diff --git a/src/main.cpp b/src/main.cpp index 28c926a..385458f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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); diff --git a/src/renpy/interpreter.cpp b/src/renpy/interpreter.cpp new file mode 100644 index 0000000..2ba8f4f --- /dev/null +++ b/src/renpy/interpreter.cpp @@ -0,0 +1,134 @@ +#include +#include + +#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; + } + } +}; diff --git a/src/renpy/script.cpp b/src/renpy/script.cpp new file mode 100644 index 0000000..a93ac6f --- /dev/null +++ b/src/renpy/script.cpp @@ -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])); + +} diff --git a/src/renpy/vulkan.cpp b/src/renpy/vulkan.cpp index 83e50b8..22eedd2 100644 --- a/src/renpy/vulkan.cpp +++ b/src/renpy/vulkan.cpp @@ -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]{