If you have ever made a side story before, you're probably heard of the monster lab converter tool, which takes your story.txt file and converts it to a file that can be read by the game engine as well as numbering the lines for you.
However, it can be improved so that it's even easier to write side stories. That's where Excalibur comes in - it's basically an upgrade of the monster lab converter. Read on for further details.
Current version: V1
Warning: Requires the .NET Framework to run. If you're using a recent Windows OS (Win7 or later), chances are it's already there.
This project is open-source (someone determined enough is bound to decompile the application anyway) - source code is included in the Program.cs file; open it with a text editor like Notepad (MS Visual Studio is highly recommended, yet difficult to obtain; Notepad++ is less powerful, but it can use a C# intellisense plugin).
How to Use
- Write your story in a .txt file and name it story.txt .
- Copy Excalibur.exe into the same directory as your story.txt .
- Run the application.
The monster lab converter does not ignore sections reserved for setting battle variables, such as [data], [ruka], [anno], and [onedari] - it numbers those lines, which renders them unreadable by the game. Excalibur ignores those sections when numbering lines.
With Excalibur adding its own line numbers, this leaves the destination argument for the commands var_jumpline and gotoline, which are introduced in GC345's patch, to be inaccurate, which could break your code. To fix this, instead of a number, input a section name prefixed by a period. Then, at the intended destination, write the section name with the period prefix with your line of code like so:
name,Alice var_cpa,v1,=,1,0 var_jumpline,.line1 var_cpa,v1,=,2,0 var_jumpline,.line2 var_cpa,v1,=,3,0 var_jumpline,.line3 .line1 = "I shall roast you two with infernal flames!" gotoline,.move .line2 = "I call forth the fires of hell!" gotoline,.move .line3 = "Can you endure this scorching heat!?" .move = "change,mp,2,-" name skillname,Omega Blaze Alice unleashes a storm of fire!
As you can see, you have to write out the full version of the line at the destination. An advantage to this system is that it's (relatively) easier to identify where the jumplines (lines that use the var_jumpline or gotoline command) point to, in case you need to debug your code. Excalibur will confirm if all jumplines point to a skipline (destination line of a jumpline) and all skiplines have at least one jumpline pointing to it in each section that supports line numbering. Compiling will fail if a jumpline does not point to a skipline or if a skipline has no jumplines pointing to it.
A line can be both a jumpline and a skipline, as demonstrated below.
.line = "gotoline,.line0"
Excalibur will recognize this as both a jumpline and a skipline, and it will number it appropriately, as long as it satisfies the confirmation conditions.
Excalibur has the potential to simplify story code by wrapping up several side story commands (and in some cases, many side story commands) into one custom command.
During the final boss fight, Luka teams up with some of his allies, each with their own health pool. In Chapter 5 of the side story Daily Life with Monster Girl Quest, there is a point in the story where three characters duke it out against each other in a Mêlée à Trois , in which each combatant's health is displayed. However, with just side story commands, accomplishing this would be a nightmare.
//Checking the variable (its value contains the target's current health) 100 = "var_cpa,v8,=,25000,0" 101 = "var_jumpline,400" 102 = "var_cpa,v8,>,24750,0" 103 = "var_jumpline,402" 104 = "var_cpa,v8,>,24500,0" 105 = "var_jumpline,404" ... //Displaying the sprite 400 = "sp_alpha,-8,\system\gagee100.bmp,87,21,10,350" 401 = "gotoline,700" 402 = "sp_alpha,-8,\system\gagee99.bmp,87,21,10,350" 403 = "gotoline,700" 404 = "sp_alpha,-8,\system\gagee98.bmp,87,21,10,350" 405 = "gotoline,700" ... //Repeated for EVERY percentage of health; this took up around 400 total lines!
This command wraps all this up into one single line. One line. Seriously. Open the storyOriginal.ini file with the story.txt file within the chapter5 folder in the download and compare their [update_hsp_happy] sections.
- layer - The sprite layer of the health gauge. Utilizes the sp command.
- variable - The variable containing the target's current health. (v0, v1, v2, ...)
- xPos - X position of the gauge. Treat this as an extension of the sp command as well.
- yPos - Y position of the gauge.
- maxHealth - Maximum health of the target. For best results, make this argument divisible by 100.
- gauge - Optional. 0 uses gageeXXX.bmp (enemy health bar), 1 uses gagerXXX.bmp (player health bar). Default: 0.
- drawingEffect - Optional. This is the way the sprite appears on the screen. Utilizes the sp command. Default: 10.
- drawingDuration - Optional. This is how long it takes in milliseconds for the sprite to appear on the screen. Utilizes the sp command. Default: 350.
Doppelganger has her own pool of SP to expend when copying Luka's moves. This command draws sprites that represent the amount of SP the target currently has, as demonstrated in the [update_hsp_happy] section in the chapter5/story.txt file.
This command is named mp for "magic points", as sp was already taken.
- startLayer - The starting sprite layer. Utilizes the sp command. For best results, set this to a large negative number to ensure that this command doesn't overwrite existing sprites in the battle and to ensure that these sprites will appear in front of everything else.
- variable - The variable containing the current SP of the target.
- xPos - X position of the first SP5 sprite. Utilizes the sp command. Offset this if you're only using SP1 sprites.
- yPos - Y position of the first SP5 sprite. Utilizes the sp command.
- maxMP - The maximum SP of the target. The value of variable will automatically be trimmed between 0 and maxMP, inclusive.
- direction - Optional. 0 draws the sprites from right to left, 1 draws the sprites from left to right. Default: 1.
This command displays the animation preceding each skill used in the game. Implementation of the skill animations through this command duplicates the implementation of the skill animations in the vanilla game.
Note that this command does not include the element cut-ins (the images of one of the spirits plus Luka); use the cutin command if you wish to use those.
All skills use one sprite layer and one sound layer, with the following exceptions:
- All variants of Lightning Sword Flash use two sprite layers, "spriteLayer" and "spriteLayer" - 1.
- Quadruple Giga uses five sound layers, "soundLayer" to "soundLayer" + 4, inclusive.
- Vaporizing Rebellion Sword uses eight sound layers, "soundLayer" to "soundLayer" + 7, inclusive.
- Flash Kill and Palm of Pure Violence use two sound layers, "soundLayer" and "soundLayer" + 1.
- Dance of Death uses four sound layers, "soundLayer" to "soundLayer" + 3, inclusive.
skillanim,<spriteLayer>,<skillID> skillanim,<spriteLayer>,<skillID>,[soundLayer] skillanim,<spriteLayer>,<skillID>,[xPos],[yPos] skillanim,<spriteLayer>,<skillID>,[soundLayer],[xPos],[yPos] skillanim,<spriteLayer>,<skillID>,[originalBG] skillanim,<spriteLayer>,<skillID>,[originalBG],[soundLayer] skillanim,<spriteLayer>,<skillID>,[originalBG],[xPos],[yPos] skillanim,<spriteLayer>,<skillID>,[originalBG],[soundLayer],[xPos],[yPos]
- spriteLayer - Self-explanatory by now, hopefully. Some skills use multiple layers.
- skillID - See below for valid values.
- soundLayer - Optional. Also should be self-explanatory. Some skill use multiple layers. Omit this argument if you don't wish to use the skill's sound effects (perhaps to add in your own?)
- xPos - Optional. Default: 0. Definitely omit this argument and yPos if you use skills that use fullscreen sprites, such as Death Sword Chaos Star and Earth Rumbling Decapitation.
- yPos - Optional. Default: 0. Note that leaving this and xPos at the default values use the center of the screen as the crosshairs.
- originalBG - Optional. Default: black. Only used in Fallen Angel Dance and Daystar, which use the bg command. For other skills, it's safe to omit this.
- 0 - Demon Decapitation
- 1 - Thunder Thrust (used at first turn)
- 2 - Demon Skull Beheading
- 3 - Death Sword Chaos Star
- 4 - Lightning Sword Flash (used at first turn)
- 5 - Earth Rumbling Decapitation
- 6 - Serene Demon Sword
- 7 - Vaporizing Rebellion Sword
- 8 - Flash Kill
- 9 - Heavenly Demon Revival
- 10 - Ninefold Rakshasa
- 11 - Daystar (execution of the move)
- 12 - Fallen Angel Dance
- 13 - Element Spica
- 14 - Quadruple Giga (execution of the charged move)
- 15 - Omega Blaze
- 16 - Frost Ozma
- 17 - Monster Lord's Cruelty
- 18 - Aqua Pentagram (used by Erubetie in the final battle, as well as Kraken)
- 19 - Thunder Thrust (not used at first turn)
- 20 - Lightning Sword Flash (w/ Sylph summoned)
- 21 - Lightning Sword Flash (w/o Sylph summoned, not used at first turn)
- 22 - Diamond Plated Fist (used by Alma Elma in the final battle)
- 23 - Dragon Knee (used by Alma Elma in the final battle)
- 24 - Palm of Pure Violence (used by Alma Elma in the final battle)
- 25 - Nine Moons (used by Tamamo in the final battle)
- 26 - Dance of Death (used by Tamamo in the final battle)
- 27 - Dragon Butcher Attack (used by Granberia in the final battle)
More to be added in future update(s)
Duplicates (or at least attempts to) the use of the skill cut-ins (the images of one of the spirits and Luka when he uses an element-based move with that spirit summoned, or all four when using Element Spica or Quadruple Giga). Sound effects optional. Also supports single cut-ins.
A future update will support different directions for the fade-in animation (for now, the cut-in starts at the top of the screen and slides down as it fades in).
cutin,<startSpriteLayer>,<element>,<lukaFlag> cutin,<startSpriteLayer>,<element>,<lukaFlag>,[soundLayer] cutin,<startSpriteLayer>,<element>,<lukaFlag>,[xPos],[yPos] cutin,<startSpriteLayer>,<element>,<lukaFlag>,[soundLayer],[xPos],[yPos]
- startSpriteLayer - The starting sprite layer. This command uses up to four sprite layers.
- element - See below for valid values.
- lukaFlag - Whether to display the spirit cut-in (0), the Luka cut-in (1), or both (2).
- soundLayer - Optional. Omit this argument if you don't wish to use the default sound effects.
- xPos - Optional. X offset. Default X position is at the horizontal center of the screen.
- yPos - Optional. Y offset. Default Y starting position is near the top of the screen.
- 0 - All four elements. Does not support lukaFlag = 2.
- 1 - Wind
- 2 - Earth
- 3 - Water
- 4 - Fire
The following are added functionality not yet implemented but will possibly be in future update(s):
Variable aliases. Using just v0, v1, v2, etc. can get really confusing, especially if you use a lot of them. The custom command var_alias may be something like:
Then you can use that alias in any command that takes in a variable argument and let Excalibur replace them with the actual variables.
The gosub command. This was used very often in the game's code. What this is is basically a goto command, but once you reach the end of the section, the game goes back to the section that called the command. Implementation in story.txt could be something like:
[omega] //v0 determines whether the hero is in a serene state. var_ld,v0,aqua skillname,Omega Blaze Alipheese creates a storm of fire! delay,500 var_cpa,v0,=,4 //The skip part is not always necessary, but in this case it wouldn't make sense to dodge an attack and STILL take damage var_jumpsub,aqua_guard:skip,1 goto,deal_damage end [aqua_guard] skillname,Serene Movement se,1,miss_aqua But like water flowing around an obstacle, Luka evades it! skillname return //or end?
The trouble is that this would be difficult to code in the compiler, as it acts outside the game flow. I don't yet know how to force the game to look into a section and then go straight back to the previous one at that specific line.
City windows. At some points in the game you're left with the option to wander around a city, talking to NPCs. A window will appear with a list of sprite buttons to allow you to choose who to talk to or where to visit. Implementation of the command would be something like:
//Command; supports as many paths as the window can fit win_city,<startSpriteLayer>,<exit_string>,<exit_destination>,<display_string_1>,<destination_section_1>,[display_string_2],[destination_section_2], ... //What the command turns into after compiling sp_alpha,startSpriteLayer,\system\window9.bmp,80,140 strsp,startSpriteLayer - 1,exit_string,410,400,20,2,1,white,#FF4444 strsp,startSpriteLayer - 2,display_string_1,95,160,20,2,1,white,#FF4444 strsp,startSpriteLayer - 3,display_string_2,95,190,20,2,1,white,#FF4444 ... spbtn,startSpriteLayer - 1,exit_section spbtn,startSpriteLayer - 2,destination_section_1 spbtn,startSpriteLayer - 3,destination_section_2 ...