Merge pull request #128 from Lorenzooone/Cre

Complete ending sequence
This commit is contained in:
jeffman 2020-08-26 20:35:07 -04:00 committed by GitHub
commit e336ed27d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 1808 additions and 4 deletions

View File

@ -3,3 +3,5 @@ $pwd = $pwd.Path
& dotnet build tools/ScriptTool -o "$([IO.Path]::Combine($pwd, "bin/ScriptTool"))" & dotnet build tools/ScriptTool -o "$([IO.Path]::Combine($pwd, "bin/ScriptTool"))"
if ($LASTEXITCODE -ne 0) { exit -1 } if ($LASTEXITCODE -ne 0) { exit -1 }
& dotnet build tools/RenderCastRoll -o "$([IO.Path]::Combine($pwd, "bin/RenderCastRoll"))"
if ($LASTEXITCODE -ne 0) { exit -1 }

View File

@ -6,6 +6,8 @@ $output_rom_file = "bin/m12.gba"
$eb_rom_file = "bin/eb.smc" $eb_rom_file = "bin/eb.smc"
$working_dir = "working" $working_dir = "working"
$src_dir = "src" $src_dir = "src"
$data_dir = "src/data"
$cast_roll_file = "working/cast_roll.json"
$compiled_asm_file = "src/m2-compiled.asm" $compiled_asm_file = "src/m2-compiled.asm"
$includes_asm_file = "m12-includes.asm" # implicitly rooted in working_dir $includes_asm_file = "m12-includes.asm" # implicitly rooted in working_dir
$hack_asm_file = "m2-hack.asm" # implicitly rooted in src_dir $hack_asm_file = "m2-hack.asm" # implicitly rooted in src_dir
@ -14,6 +16,7 @@ $input_c_files =
"src/c/ext.c", "src/c/ext.c",
"src/c/vwf.c", "src/c/vwf.c",
"src/c/locs.c", "src/c/locs.c",
"src/c/credits.c",
"src/c/goods.c", "src/c/goods.c",
"src/c/fileselect.c", "src/c/fileselect.c",
"src/c/status.c", "src/c/status.c",
@ -24,6 +27,7 @@ $input_c_files =
$base_c_address = 0x83755B8; $base_c_address = 0x83755B8;
$scripttool_cmd = "bin/ScriptTool/ScriptTool.dll" $scripttool_cmd = "bin/ScriptTool/ScriptTool.dll"
$rendercastroll_cmd= "bin/RenderCastRoll/RenderCastRoll.dll"
$gcc_cmd = "arm-none-eabi-gcc" $gcc_cmd = "arm-none-eabi-gcc"
$ld_cmd = "arm-none-eabi-ld" $ld_cmd = "arm-none-eabi-ld"
$objdump_cmd = "arm-none-eabi-objdump" $objdump_cmd = "arm-none-eabi-objdump"
@ -48,6 +52,10 @@ $scripttool_args =
$working_dir, $working_dir,
$eb_rom_file, $eb_rom_file,
$input_rom_file $input_rom_file
$rendercastroll_args =
$cast_roll_file,
$data_dir
$gcc_args = $gcc_args =
"-c", "-c",
@ -348,6 +356,10 @@ Copy-Item -Path $input_rom_file -Destination $output_rom_file
& dotnet $scripttool_cmd $scripttool_args & dotnet $scripttool_cmd $scripttool_args
if ($LASTEXITCODE -ne 0) { exit -1 } if ($LASTEXITCODE -ne 0) { exit -1 }
"Pre-rendering cast roll..."
& dotnet $rendercastroll_cmd $rendercastroll_args
if ($LASTEXITCODE -ne 0) { exit -1 }
# ------------------------ ASSEMBLE GAME TEXT ----------------------- # ------------------------ ASSEMBLE GAME TEXT -----------------------
"Assembling game text..." "Assembling game text..."
& $asm_cmd -root $working_dir -sym $includes_sym_file $includes_asm_file & $asm_cmd -root $working_dir -sym $includes_sym_file $includes_asm_file

316
src/c/credits.c Normal file
View File

@ -0,0 +1,316 @@
#include "credits.h"
void printPlayerNameCredits(unsigned short *arrangements)
{
//Converts the player name to arrangements
int length = 0;
byte *player_name = m2_player1;
//First things first, it calculates the length of the string
for(length = 0; length < PLAYER_NAME_SIZE && (*(++player_name)) != 0xFF; length++);
//Gets where to position the arrangements...
int start_pos = ((0x1F - length) >> 1) + 1;
int start_pos_default = ((0x1F - 5) >> 1) + 1;
unsigned short *player_name_arrangements = ((0x89 << 2) << 5) + arrangements + start_pos;
unsigned short *default_player_name_arrangements = ((0x89 << 2) << 5) + arrangements + start_pos_default;
player_name = m2_player1;
//Clears the default MARIO player name...
for(int i = 0; i < 5; i++)
{
default_player_name_arrangements[i] = 0xF19B;
default_player_name_arrangements[i + 0x20] = 0xF19B;
}
//Puts the new arrangements in
for(int i = 0; i < length; i++)
{
unsigned short arrangement = m2_credits_conversion_table[player_name[i]];
player_name_arrangements[i] = arrangement;
player_name_arrangements[i + 0x20] = arrangement + 0x20;
}
}
void writeCastText(unsigned short *bg0Arrangements, unsigned short *bg1Arrangements)
{
//Function that writes out the VWF Cast roll text and puts the arrangements in.
byte *castText_curr_ptr;
byte *castText_curr_start = cast_vwf_names;
int length;
int Tiles[SIDE_BUFFER_SIZE + 1][4];
unsigned short lastEdited = 0;
//Do all the entries
while((*castText_curr_start) != END_ALL)
{
//Read info
unsigned short tile_y = (*castText_curr_start) + ((*(castText_curr_start + 1)) << 8);
int center_x = *(castText_curr_start + 2);
castText_curr_start += 3;
//Setup
castText_curr_ptr = castText_curr_start;
length = 0;
setTilesToBlank(Tiles[0]);
//First things first, it calculates the total length of the text in pixels
while((*castText_curr_ptr) != END)
length += getCharWidth(*(castText_curr_ptr++));
//Calculate the starting position of the text
int x = center_x - (length >> 1);
if((x + length) > 240) //GBA Screen width
x = 240 - length;
if(x < 0)
x = 0;
//It then gets the length in arrangements
int effectiveLength = length;
length = (length + 7) >> 3;
castText_curr_ptr = castText_curr_start;
int currXStart = x;
//Prints out the characters
while((*castText_curr_ptr) != END)
x += readCastCharacter(*(castText_curr_ptr++), Tiles, bg0Arrangements, x, tile_y, &lastEdited);
if((x & 7) != 0)
{
//Do the last one
unsigned short baseTileValue = m2_cast_vwf_free;
int *baseGraphicsPointer = (int*)((baseTileValue << 5) + BASE_GRAPHICS_ADDRESS);
int currLen = x & 7;
int currPos = x >> 3;
unsigned short *baseArrangementsPointer = bg0Arrangements + (tile_y << 5) + currPos + 1;
int tileValue = (((lastEdited) >> 5) << 6) + ((lastEdited) & 0x1F);
lastEdited++;
printCastTiles(Tiles[0], baseArrangementsPointer, baseGraphicsPointer + (tileValue << 3), baseTileValue + tileValue);
}
//End of cycle stuff
castText_curr_start = (castText_curr_ptr + 1);
}
}
int readCastCharacter(byte chr, int Tiles[SIDE_BUFFER_SIZE + 1][4], unsigned short *arrangements, int x, int tile_y, unsigned short *lastEdited)
{
//Reads a character. Handles special cases.
//The valid characters are printed to the Tiles 1bpp buffer that stores the VWF form of the text.
//This is then stored (when it makes sense to do so) to arrangements and graphics by printCastTiles.
switch(chr)
{
case END:
return 0;
case PC_START:
case PC_START+1:
case PC_START+2:
case PC_START+3:
return readCastCharacterName(pc_names+(chr-PC_START)*(PC_NAME_SIZE + 2), Tiles, arrangements, x, tile_y, PC_NAME_SIZE, lastEdited);
case PC_START+4:
return readCastCharacterName(pc_names+(chr-PC_START)*(PC_NAME_SIZE + 2), Tiles, arrangements, x, tile_y, DOG_NAME_SIZE, lastEdited);
default:
return printCastCharacter(chr, Tiles, arrangements, x, tile_y, lastEdited);
}
}
int readCastCharacterName(byte* str, int Tiles[SIDE_BUFFER_SIZE + 1][4], unsigned short *arrangements, int x, int tile_y, int max_size, unsigned short *lastEdited)
{
//Reads a playable character's name.
//The characters are printed to the Tiles 1bpp buffer that stores the VWF form of the text.
//This is then converted (when it makes sense to do so) to arrangements by printLumineTiles.
//This is separate in order to avoid recursive issues caused by user's tinkering
int totalLen = 0;
for(int i = 0; i < max_size; i++)
{
if(*(str + 1) == 0xFF)
return totalLen;
byte chr = decode_character(*(str++));
totalLen += printCastCharacter(chr, Tiles, arrangements, x + totalLen, tile_y, lastEdited);
}
return totalLen;
}
int printCastCharacter(byte chr, int Tiles[SIDE_BUFFER_SIZE + 1][4], unsigned short *arrangements, int x, int tile_y, unsigned short *lastEdited)
{
//Function that gets a character and then prints it to the Tiles buffer.
//If the buffer is full, it uses the AlternativeTiles side-buffer and then prints Tiles to the arrangements.
//The same happens to any AlternativeTiles side-buffer that gets full
int tileWidth = CAST_FONT_WIDTH;
int tileHeight = CAST_FONT_HEIGHT;
unsigned short baseTileValue = m2_cast_vwf_free;
int *baseGraphicsPointer = (int*)((baseTileValue << 5) + BASE_GRAPHICS_ADDRESS);
int chosenLen = m2_widths_table[CAST_FONT][chr] & 0xFF;
int renderedLen = m2_widths_table[CAST_FONT][chr] >> 8;
byte *glyphRows = &m2_font_table[CAST_FONT][chr * tileWidth * tileHeight * 8];
int currLen = x & 7;
int currPos = x >> 3;
unsigned short *baseArrangementsPointer = arrangements + (tile_y << 5) + currPos + 1;
if(chosenLen <= 0)
return 0;
if((currLen + chosenLen) >= 8)
{
for(int i = 0; i < SIDE_BUFFER_SIZE; i++)
setTilesToBlank(Tiles[i + 1]);
if(renderedLen > 0)
printCastCharacterInMultiTiles(Tiles, glyphRows, renderedLen, currLen);
int fullAlternatives = ((currLen + chosenLen) >> 3);
for(int i = 0; i < fullAlternatives; i++)
{
int tileValue = (((*lastEdited) >> 5) << 6) + ((*lastEdited) & 0x1F);
(*lastEdited)++;
printCastTiles(Tiles[i], baseArrangementsPointer + i, baseGraphicsPointer + (tileValue << 3), baseTileValue + tileValue);
}
copyTiles(Tiles, fullAlternatives);
}
else if(renderedLen > 0)
printCastCharacterInSingleTiles(Tiles, glyphRows, renderedLen, currLen);
return chosenLen;
}
void printCastCharacterInMultiTiles(int Tiles[SIDE_BUFFER_SIZE + 1][4], byte *glyphRows, int glyphLen, int currLen)
{
//Prints a character to the tiles 1bpp buffer.
//The part that goes beyond the tiles buffer will be printed to the AlternativeTiles buffer
int tileWidth = CAST_FONT_WIDTH;
int tileHeight = CAST_FONT_HEIGHT;
int startY = START_Y;
for(int dTileY = 0; dTileY < tileHeight; dTileY++)
{
int tileIndex = dTileY * 2;
int renderedWidth = glyphLen;
int dTileX = 0;
while(renderedWidth > 0)
{
int *currTile = Tiles[dTileX];
int *currAlt = Tiles[dTileX + 1];
for(int half = 0; half < 2; half++)
{
int tile = currTile[tileIndex + half];
int alternativeTile = currAlt[tileIndex + half];
int endingTile = 0;
int endingAlternativeTile = 0;
for(int row = 0; row < 4; row++)
{
unsigned short canvasRow = ((tile >> (8 * row))&0xFF) | (((alternativeTile >> (8 * row))&0xFF) << 8);
unsigned short glyphRow = 0;
if(row + (half * 4) - startY >= 0)
glyphRow = glyphRows[row + (half * 4) - startY + (dTileY * 8 * tileWidth) + (dTileX * 8)] << currLen;
else if(dTileY == 1)
glyphRow = glyphRows[row + (half * 4) - startY + 8 + (dTileX * 8)] << currLen;
canvasRow |= glyphRow;
endingTile |= (canvasRow & 0xFF) << (8 * row);
endingAlternativeTile |= ((canvasRow >> 8) & 0xFF) << (8 * row);
}
currTile[tileIndex + half] = endingTile;
currAlt[tileIndex + half] = endingAlternativeTile;
}
renderedWidth -= 8;
dTileX++;
}
}
}
void printCastCharacterInSingleTiles(int Tiles[SIDE_BUFFER_SIZE + 1][4], byte *glyphRows, int glyphLen, int currLen)
{
//Prints a character to the tiles 1bpp buffer.
//We know this won't go outside of the buffer's range, so we avoid some checks
int tileWidth = CAST_FONT_WIDTH;
int tileHeight = CAST_FONT_HEIGHT;
int startY = START_Y;
for(int dTileY = 0; dTileY < tileHeight; dTileY++)
{
int tileIndex = dTileY * 2;
for(int half = 0; half < 2; half++)
{
int tile = Tiles[0][tileIndex + half];
int endingTile = 0;
for(int row = 0; row < 4; row++)
{
byte canvasRow = ((tile >> (8 * row))&0xFF);
byte glyphRow = 0;
if(row + (half * 4) - startY >= 0)
glyphRow = glyphRows[row + (half * 4) - startY + (dTileY * 8 * tileWidth)] << currLen;
else if(dTileY == 1)
glyphRow = glyphRows[row + (half * 4) - startY + 8] << currLen;
canvasRow |= glyphRow;
endingTile |= canvasRow << (8 * row);
}
Tiles[0][tileIndex + half] = endingTile;
}
}
}
void copyTiles(int Tiles[SIDE_BUFFER_SIZE + 1][4], int indexMatrix)
{
for(int i = 0; i < 4; i++)
Tiles[0][i] = Tiles[indexMatrix][i];
}
void setTilesToBlank(int *Tiles)
{
for(int i = 0; i < 4; i++)
Tiles[i] = 0;
}
void printCastTiles(int Tiles[4], unsigned short *arrangements, int *graphics, unsigned short tileValue)
{
//Converts what is written in 1bpp in the Tiles buffer to graphics and arrangements
int value;
int currTile;
for(int i = 0; i < 2; i++)
{
arrangements[(i << 5)] = PALETTE | (tileValue + (i << 5));
for(int k = 0; k < 2; k++)
{
currTile = Tiles[k + (i * 2)];
for(int j = 0; j < 4; j++)
graphics[(i << 8) + (k << 2) + j] = m2_bits_to_nybbles_fast_cast[((currTile >> (j * 8)) & 0xFF)];
}
}
}
int getCharWidth(byte chr)
{
//Gets the length for a character. Also handles special cases
switch(chr)
{
case END:
return 0;
case PC_START:
case PC_START+1:
case PC_START+2:
case PC_START+3:
return getPCWidth(pc_names+(chr-PC_START)*(PC_NAME_SIZE + 2), PC_NAME_SIZE);
case PC_START+4:
return getPCWidth(pc_names+(chr-PC_START)*(PC_NAME_SIZE + 2), DOG_NAME_SIZE);
default:
return m2_widths_table[CAST_FONT][chr] & 0xFF;
}
}
int getPCWidth(byte* pc_ptr, int max_size)
{
//Gets the length for a playable character's name.
//This is separate in order to avoid recursive issues caused by user's tinkering
int length = 0;
byte chr;
for(int i = 0; i < max_size; i++)
{
chr = *(pc_ptr+i+1);
if(chr == 0xFF)
return length;
chr = decode_character(*(pc_ptr+i));
length += m2_widths_table[CAST_FONT][chr] & 0xFF;
}
return length;
}

40
src/c/credits.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef HEADER_CREDITS_INCLUDED
#define HEADER_CREDITS_INCLUDED
#include "types.h"
#include "locs.h"
#define PLAYER_NAME_SIZE 24
#define CAST_FONT 0
#define CAST_FONT_WIDTH 2
#define CAST_FONT_HEIGHT 2
#define SIDE_BUFFER_SIZE 2
#define START_Y 2
#define END_ALL 0xFF
#define END 0xFE
#define PC_START 0xF9
#define PC_NAME_SIZE 5
#define DOG_NAME_SIZE 6
#define BASE_GRAPHICS_ADDRESS 0x6000000
#define PALETTE 0xF000
void printPlayerNameCredits(unsigned short *arrangements);
void writeCastText(unsigned short *bg0Arrangements, unsigned short *bg1Arrangements);
int getCharWidth(byte chr);
int getPCWidth(byte* pc_ptr, int max_size);
void setTilesToBlank(int *Tiles);
void printCastTiles(int Tiles[4], unsigned short *arrangements, int *graphics, unsigned short tileValue);
int readCastCharacter(byte chr, int Tiles[SIDE_BUFFER_SIZE + 1][4], unsigned short *arrangements, int x, int tile_y, unsigned short *lastEdited);
int readCastCharacterName(byte* str, int Tiles[SIDE_BUFFER_SIZE + 1][4], unsigned short *arrangements, int x, int tile_y, int max_size, unsigned short *lastEdited);
void printCastCharacterInMultiTiles(int Tiles[SIDE_BUFFER_SIZE + 1][4], byte *glyphRows, int glyphLen, int currLen);
void printCastCharacterInSingleTiles(int Tiles[SIDE_BUFFER_SIZE + 1][4], byte *glyphRows, int glyphLen, int currLen);
void copyTiles(int Tiles[SIDE_BUFFER_SIZE + 1][4], int indexMatrix);
int printCastCharacter(byte chr, int Tiles[SIDE_BUFFER_SIZE + 1][4], unsigned short *arrangements, int x, int tile_y, unsigned short *lastEdited);
extern byte m2_player1[];
extern byte cast_vwf_names[];
extern unsigned short m2_cast_vwf_free;
extern unsigned short m2_credits_conversion_table[];
extern int m2_bits_to_nybbles_fast_cast[];
#endif

116
src/data/cast-table.tbl Normal file
View File

@ -0,0 +1,116 @@
00=\x00
01=\x01
17=\x17
1C=\x1C
26=\x26
30=\x30
3E=\x3E
44=\x44
4A=\x4A
4C=\x4C
56=\x56
FE=[END]
00=
01=!
02="
03=#
04=$
05=%
06=&
07='
08=(
09=)
0A=*
0B=+
0C=,
0D=-
0E=.
0F=/
10=0
11=1
12=2
13=3
14=4
15=5
16=6
17=7
18=8
19=9
1A=:
1B=;
1C=<
1D==
1E=>
1F=?
20=@
21=A
22=B
23=C
24=D
25=E
26=F
27=G
28=H
29=I
2A=J
2B=K
2C=L
2D=M
2E=N
2F=O
30=P
31=Q
32=R
33=S
34=T
35=U
36=V
37=W
38=X
39=Y
3A=Z
3B=[8B]
3C=[8C]
3D=[8D]
3E=[8E]
3F=[8F]
40=`
41=a
42=b
43=c
44=d
45=e
46=f
47=g
48=h
49=i
4A=j
4B=k
4C=l
4D=m
4E=n
4F=o
50=p
51=q
52=r
53=s
54=t
55=u
56=v
57=w
58=x
59=y
5A=z
5B={
5C=|
5D=}
5E=~
5F=[AF]
F9=\cness
FA=\cpaula
FB=\cjeff
FC=\cpoo
FD=\cking
/FF

View File

@ -0,0 +1,10 @@
.loadtable "data/cast-table.tbl"
.strn 078h, 000h, 050h, "\cpaula's mom[END]"
.strn 078h, 000h, 0A0h, "\cpaula's dad[END]"
.strn 080h, 000h, 078h, "\cpaula[END]"
.strn 01Ah, 001h, 078h, "\cjeff[END]"
.strn 0A2h, 001h, 078h, "\cpoo[END]"
.strn 0ADh, 001h, 0B0h, "\cpoo's Master[END]"
.strn 03Ah, 002h, 090h, "\cking[END]"
.str 043h, 002h, 078h, "\cness[END]"

Binary file not shown.

View File

@ -0,0 +1 @@
<EFBFBD>

Binary file not shown.

View File

@ -0,0 +1 @@
<16>3<EFBFBD>5<EFBFBD>7<EFBFBD>9<EFBFBD>;<3B>q<EFBFBD><1C><><EFBFBD>4<EFBFBD>6<EFBFBD>8<EFBFBD>:<3A><<3C><1B><1D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

View File

@ -0,0 +1 @@
0

Binary file not shown.

View File

@ -0,0 +1 @@
q<EFBFBD>s<EFBFBD><EFBFBD><EFBFBD><16>3<EFBFBD>5<EFBFBD>7<EFBFBD>u<EFBFBD>r<EFBFBD>t<EFBFBD><74><EFBFBD><EFBFBD><EFBFBD>4<EFBFBD>6<EFBFBD>8<EFBFBD><38><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

View File

@ -0,0 +1 @@
0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1727,6 +1727,41 @@ nop
//============================================================================== //==============================================================================
.org 0x80DEE6C :: bl dee6c_fix_poison_gyigas :: nop :: nop :: nop .org 0x80DEE6C :: bl dee6c_fix_poison_gyigas :: nop :: nop :: nop
//==============================================================================
// Credits hacks
//==============================================================================
//Repoint credits font (Before it pointed to 0x82FF1B8)
.org 0x82DB284 :: dw m2_credits_font
.org 0x801352E :: bl printPlayerNameCredits
//Repoint cast graphical data
.org m2_cast_roll_pointers :: dw m2_cast_graphics :: dw m2_cast_palette :: dw m2_cast_arrangements
//Remove flavour changing the palette
.org 0x8010426 :: bl prevent_cast_changed_palettes
//Cast Roll VWF
.org 0x800F640 :: bl writeCastText
//Master Belch and Star Master text appearing later
.org 0x8018934 :: dw m2_cast_belch_arrangement
.org 0x80188B2 :: .incbin "data/cast_roll_master_belch_size.bin"
.org 0x82D92BC :: .incbin "data/cast_roll_master_belch_data.bin"
.org 0x8018940 :: dw m2_cast_star_arrangement
.org 0x8018904 :: .incbin "data/cast_roll_star_master_size.bin"
.org 0x82D92C4 :: .incbin "data/cast_roll_star_master_data.bin"
//==============================================================================
// "THE END...?" hacks
//==============================================================================
.org 0x88B5AA0 :: .incbin "data/the_end_graphics.bin"
.org 0x88B62A0 :: .incbin "data/the_end_palette.bin"
.org 0x88B62C0 :: .incbin "data/the_end_arrangements_frame0.bin"
//Add an extra event for the "?" in "THE END..."
.org 0x80A5F5C :: bl extra_event_end_question_mark
//============================================================================== //==============================================================================
// Move stuff around in order to make space for the code // Move stuff around in order to make space for the code
//============================================================================== //==============================================================================
@ -1832,18 +1867,25 @@ m2_widths_battle:
m2_widths_tiny: m2_widths_tiny:
.incbin "data/m2-widths-tiny.bin" .incbin "data/m2-widths-tiny.bin"
.align 4
m2_bits_to_nybbles: m2_bits_to_nybbles:
.incbin "data/m2-bits-to-nybbles.bin" .incbin "data/m2-bits-to-nybbles.bin"
m2_bits_to_nybbles_fast: m2_bits_to_nybbles_fast:
.incbin "data/m2-bits-to-nybbles-fast.bin" .incbin "data/m2-bits-to-nybbles-fast.bin"
m2_bits_to_nybbles_fast_cast:
.incbin "data/m2-bits-to-nybbles-fast-cast.bin"
m2_nybbles_to_bits: m2_nybbles_to_bits:
.incbin "data/m2-nybbles-to-bits.bin" .incbin "data/m2-nybbles-to-bits.bin"
m2_enemy_attributes: m2_enemy_attributes:
.incbin "data/m2-enemy-attributes.bin" .incbin "data/m2-enemy-attributes.bin"
cast_vwf_names:
.include "data/cast-vwf-names.asm"
.align 2 .align 2
luminesquaretable: luminesquaretable:
.incbin "data/luminesquaretable.bin" .incbin "data/luminesquaretable.bin"
@ -1888,6 +1930,42 @@ m2InsaneCultist:
m2_coord_table_file: m2_coord_table_file:
.incbin "data/m2-coord-table-file-select.bin" .incbin "data/m2-coord-table-file-select.bin"
.align 2
m2_credits_conversion_table:
.incbin "data/m2-credits-conversion-table.bin"
.align 4
m2_cast_belch_arrangement:
.incbin "data/cast_roll_master_belch_arrangement.bin"
.align 4
m2_cast_star_arrangement:
.incbin "data/cast_roll_star_master_arrangement.bin"
.align 2
m2_cast_vwf_free:
.incbin "data/cast_roll_first_free.bin"
.align 4
m2_cast_graphics:
.incbin "data/cast_roll_graphics_[c].bin"
.align 4
m2_cast_palette:
.incbin "data/cast_roll_palette_[c].bin"
.align 4
m2_cast_arrangements:
.incbin "data/cast_roll_arrangements_[c].bin"
.align 4
m2_credits_font:
.incbin "data/m2-credits-font_[c].bin"
.align 4
m2_end_frame1:
.incbin "data/the_end_arrangements_frame1.bin"
optimized_byte_4bpp_to_1bpp_table: optimized_byte_4bpp_to_1bpp_table:
.incbin "data/optimized-byte-4bpp-to-1bpp-table.bin" .incbin "data/optimized-byte-4bpp-to-1bpp-table.bin"
@ -1978,6 +2056,7 @@ disclaimer_map:
.definelabel m2_div ,0x80F49D8 .definelabel m2_div ,0x80F49D8
.definelabel m2_remainder ,0x80F4A70 .definelabel m2_remainder ,0x80F4A70
.definelabel cpuset ,0x80F47C0 .definelabel cpuset ,0x80F47C0
.definelabel m2_cast_roll_pointers ,0x82DB25C
.definelabel m2_items ,0x8B1D62C .definelabel m2_items ,0x8B1D62C
.definelabel m2_default_names ,0x82B9330 .definelabel m2_default_names ,0x82B9330
.definelabel m2_psi_print_table ,0x8B2A9C0 .definelabel m2_psi_print_table ,0x8B2A9C0

View File

@ -3375,6 +3375,49 @@ bl eb_cartridge_palette_change
@@end: @@end:
pop {pc} pop {pc}
//==============================================================================
//Prevents changing the palette based on the flavour for the cast roll sequence
prevent_cast_changed_palettes:
push {lr}
ldr r1,=#m2_cast_roll_pointers
cmp r0,r1
beq @@alternate_end
bl 0x8010028
pop {pc}
@@alternate_end:
bl 0x8010028
ldr r1,=#0x40000D4
ldr r0,=#0x2010000
str r0,[r1,#0]
ldr r3,=#0x3001B30
str r3,[r1,#4]
ldr r0,=#0x84000080
str r0,[r1,#8]
ldr r0,[r1,#8]
pop {r0}
ldr r0,=#0x8010501 //Go to the end of the routine
bx r0
//==============================================================================
//Creates a new event that updates the "THE END..." screen to the second frame
extra_event_end_question_mark:
push {lr}
add r0,r0,r1
asr r0,r0,#0x10
cmp r0,#0x48
bne @@end
push {r0}
ldr r0,=#m2_end_frame1
ldr r1,=#0x6001000
mov r2,#0xA0
lsl r2,r2,#1
swi #0xC
pop {r0}
@@end:
pop {pc}
//============================================================================== //==============================================================================
//Prints the sick tiles and then the names //Prints the sick tiles and then the names
sick_name: sick_name:

View File

@ -1,12 +1,14 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16 # Visual Studio 15
VisualStudioVersion = 16.0.28407.52 VisualStudioVersion = 15.0.28307.168
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptTool", "ScriptTool\ScriptTool.csproj", "{29AB41A8-6405-4C4B-A374-BF1BD7AF1A27}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptTool", "ScriptTool\ScriptTool.csproj", "{29AB41A8-6405-4C4B-A374-BF1BD7AF1A27}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptToolGui", "ScriptToolGui\ScriptToolGui.csproj", "{BAE5CBBF-D0B3-4F82-A80A-957CEC379238}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptToolGui", "ScriptToolGui\ScriptToolGui.csproj", "{BAE5CBBF-D0B3-4F82-A80A-957CEC379238}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RenderCastRoll", "RenderCastRoll\RenderCastRoll.csproj", "{DD1C607C-5A74-4921-81A4-6BF530A191D7}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -21,6 +23,10 @@ Global
{BAE5CBBF-D0B3-4F82-A80A-957CEC379238}.Debug|Any CPU.Build.0 = Debug|Any CPU {BAE5CBBF-D0B3-4F82-A80A-957CEC379238}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BAE5CBBF-D0B3-4F82-A80A-957CEC379238}.Release|Any CPU.ActiveCfg = Release|Any CPU {BAE5CBBF-D0B3-4F82-A80A-957CEC379238}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BAE5CBBF-D0B3-4F82-A80A-957CEC379238}.Release|Any CPU.Build.0 = Release|Any CPU {BAE5CBBF-D0B3-4F82-A80A-957CEC379238}.Release|Any CPU.Build.0 = Release|Any CPU
{DD1C607C-5A74-4921-81A4-6BF530A191D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD1C607C-5A74-4921-81A4-6BF530A191D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD1C607C-5A74-4921-81A4-6BF530A191D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD1C607C-5A74-4921-81A4-6BF530A191D7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -0,0 +1,30 @@
using System;
using System.IO;
namespace RenderCastRoll
{
public static class Asset
{
public static readonly string AssetPath;
static Asset()
{
AssetPath = AppDomain.CurrentDomain.BaseDirectory;
}
public static string GetFullPath(string path)
=> Path.Combine(AssetPath, path);
public static string ReadAllText(string path)
=> File.ReadAllText(GetFullPath(path));
public static byte[] ReadAllBytes(string path)
=> File.ReadAllBytes(GetFullPath(path));
public static string[] ReadAllLines(string path)
=> File.ReadAllLines(GetFullPath(path));
public static void WriteAllText(string path, string text)
=> File.WriteAllText(GetFullPath(path), text);
}
}

View File

@ -0,0 +1,167 @@
using System.Collections.Generic;
namespace GBA
{
class LZ77
{
public static int Decompress(byte[] data, int address, out byte[] output)
{
output = null;
int start = address;
if (data[address++] != 0x10) return -1; // Check for LZ77 signature
// Read the block length
int length = data[address++];
length += (data[address++] << 8);
length += (data[address++] << 16);
output = new byte[length];
int bPos = 0;
while (bPos < length)
{
byte ch = data[address++];
for (int i = 0; i < 8; i++)
{
switch ((ch >> (7 - i)) & 1)
{
case 0:
// Direct copy
if (bPos >= length) break;
output[bPos++] = data[address++];
break;
case 1:
// Compression magic
int t = (data[address++] << 8);
t += data[address++];
int n = ((t >> 12) & 0xF) + 3; // Number of bytes to copy
int o = (t & 0xFFF);
// Copy n bytes from bPos-o to the output
for (int j = 0; j < n; j++)
{
if (bPos >= length) break;
output[bPos] = output[bPos - o - 1];
bPos++;
}
break;
default:
break;
}
}
}
return address - start;
}
public static byte[] Compress(byte[] data)
{
return Compress(data, 0, data.Length);
}
public static byte[] Compress(byte[] data, int address, int length)
{
int start = address;
List<byte> obuf = new List<byte>();
List<byte> tbuf = new List<byte>();
int control = 0;
// Let's start by encoding the signature and the length
obuf.Add(0x10);
obuf.Add((byte)(length & 0xFF));
obuf.Add((byte)((length >> 8) & 0xFF));
obuf.Add((byte)((length >> 16) & 0xFF));
while ((address - start) < length)
{
tbuf.Clear();
control = 0;
for (int i = 0; i < 8; i++)
{
bool found = false;
// First byte should be raw
if (address == start)
{
tbuf.Add(data[address++]);
found = true;
}
else if ((address - start) >= length)
{
break;
}
else
{
// We're looking for the longest possible string
// The farthest possible distance from the current address is 0x1000
int max_length = -1;
int max_distance = -1;
for (int k = 1; k <= 0x1000; k++)
{
if ((address - k) < start) break;
int l = 0;
for (; l < 18; l++)
{
if (((address - start + l) >= length) ||
(data[address - k + l] != data[address + l]))
{
if (l > max_length)
{
max_length = l;
max_distance = k;
}
break;
}
}
// Corner case: we matched all 18 bytes. This is
// the maximum length, so don't bother continuing
if (l == 18)
{
max_length = 18;
max_distance = k;
break;
}
}
if (max_length >= 3)
{
address += max_length;
// We hit a match, so add it to the output
int t = (max_distance - 1) & 0xFFF;
t |= (((max_length - 3) & 0xF) << 12);
tbuf.Add((byte)((t >> 8) & 0xFF));
tbuf.Add((byte)(t & 0xFF));
// Set the control bit
control |= (1 << (7 - i));
found = true;
}
}
if (!found)
{
// If we didn't find any strings, copy the byte to the output
tbuf.Add(data[address++]);
}
}
// Flush the temp buffer
obuf.Add((byte)(control & 0xFF));
obuf.AddRange(tbuf.ToArray());
}
return obuf.ToArray();
}
}
}

View File

@ -0,0 +1,355 @@
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace RenderCastRoll
{
class Program
{
static IDictionary<string, byte> m12CharByteLookup;
static byte[] BitsToNybbleLookup;
static readonly ushort Palette = 0xF000;
static RenderFont[] Fonts;
static byte[] Graphics;
static _1bppTile emptyTile = new _1bppTile();
static _1bppTile[] _1bppGraphics;
static _1bppTile[] _1bppGraphics_RotX;
static _1bppTile[] _1bppGraphics_RotY;
static _1bppTile[] _1bppGraphics_RotXY;
static ushort[] Arrangements;
static readonly ushort arrStart = 0x100;
static void Main(string[] args)
{
if (args.Length != 2)
return;
//Initialization
string rendersJson = File.ReadAllText(args[0]);
string dataFolder = args[1] + Path.DirectorySeparatorChar;
Fonts = new RenderFont[2];
Fonts[0] = new RenderFont(dataFolder, "main");
Fonts[1] = new RenderFont(dataFolder, "saturn");
byte[] CastGraphics = File.ReadAllBytes(dataFolder + "cast_sign_graphics.bin");
byte[] CastArrangements = File.ReadAllBytes(dataFolder + "cast_sign_arrangements.bin");
List<Render> renders = JsonConvert.DeserializeObject<RenderRoot>(rendersJson).Renders;
BitsToNybbleLookup = Asset.ReadAllBytes("bits_to_nybbles.bin");
m12CharByteLookup = JsonConvert.DeserializeObject<Dictionary<string, byte>>(Asset.ReadAllText("m12-byte-lookup.json"));
Graphics = new byte[0x8000];
Arrangements = new ushort[0x48E0];
for (int i = 0; i < Arrangements.Length; i++)
Arrangements[i] = 0x3FF; //Empty tile
for (int i = 0; i < CastGraphics.Length; i++)
Graphics[0x8000 - CastGraphics.Length + i] = CastGraphics[i]; //Put the CAST graphics in
int castArrPos = readIntLE(CastArrangements, 0); //First 4 bytes are the position of the CAST arrangements
for (int i = 0; i < ((CastArrangements.Length - 4) >> 1); i++) //Put the CAST arrangements in
{
Arrangements[(castArrPos / 2) + i] = readUShortLE(CastArrangements, (i * 2) + 4);
}
int maxTiles = 0x300 - (CastGraphics.Length / 0x20);
_1bppGraphics = new _1bppTile[maxTiles];
_1bppGraphics_RotX = new _1bppTile[maxTiles];
_1bppGraphics_RotY = new _1bppTile[maxTiles];
_1bppGraphics_RotXY = new _1bppTile[maxTiles];
int UsedTiles = 0;
WritingBuffer[] buffers = new WritingBuffer[renders.Count];
//Render the text as 1bpp
for (int i = 0; i < renders.Count; i++)
buffers[i] = renderText(renders[i]);
for (int i = 0; i < buffers.Length; i++)
UsedTiles = insertInGraphics(buffers[i], UsedTiles);
//Put the arrangements in
for (int i = 0; i < renders.Count; i++)
{
int pos = buffers[i].startPos + 1 + (renders[i].Y * 0x20); //The + 1 is here because the scene's map starts from tile 1. Not tile 0
if (renders[i].Separate_file_name == "")
for (int j = 0; j < buffers[i].used; j++)
for (int k = 0; k < WritingBuffer.yLength; k++)
Arrangements[pos + j + (k * 0x20)] = buffers[i].arrangements[k, j];
else
{
//This is an arrangement that changes when the game is running. Set the starting arrangements to empty
for (int j = 0; j < buffers[i].used; j++)
for (int k = 0; k < WritingBuffer.yLength; k++)
Arrangements[pos + j + (k * 0x20)] = 0x3FF; //Empty tile
//Save this in an external file
File.WriteAllBytes(dataFolder + "cast_roll_" + renders[i].Separate_file_name + "_arrangement.bin", prepareSeparateRender(buffers[i]));
File.WriteAllBytes(dataFolder + "cast_roll_" + renders[i].Separate_file_name + "_data.bin", prepareSeparateRenderData(buffers[i], renders[i]));
File.WriteAllBytes(dataFolder + "cast_roll_" + renders[i].Separate_file_name + "_size.bin", prepareSeparateRenderSize(buffers[i]));
}
}
//Convert the 1bpp tiles to 4bpp
for (int tile = 0; tile < UsedTiles; tile++)
{
int basePos = (tile * 0x20) + 0x2000;
_1bppTile pre_converted_tile = _1bppGraphics[tile];
for (int i = 0; i < 8; i++)
{
int row = readIntLE(BitsToNybbleLookup, pre_converted_tile.getRow(i) * 4);
for (int j = 0; j < 4; j++)
Graphics[basePos + (i * 4) + j] = (byte)((row >> (j * 8)) & 0xFF);
}
}
//File.WriteAllBytes(dataFolder + "cast_roll_graphics.bin", Graphics);
//File.WriteAllBytes(dataFolder + "cast_roll_arrangements.bin", convertUShortArrToByteArrLE(Arrangements));
File.WriteAllBytes(dataFolder + "cast_roll_first_free.bin", convertUShortToByteArrLE((ushort)(UsedTiles + 0x100)));
File.WriteAllBytes(dataFolder + "cast_roll_graphics_[c].bin", GBA.LZ77.Compress(Graphics));
File.WriteAllBytes(dataFolder + "cast_roll_arrangements_[c].bin", GBA.LZ77.Compress(convertUShortArrToByteArrLE(Arrangements)));
}
static byte[] prepareSeparateRenderSize(WritingBuffer buf)
{
byte[] newArr = new byte[1]; //Used in order to have a properly sized buffer
newArr[0] = (byte)((buf.used * 2 * WritingBuffer.yLength) & 0xFF);
return newArr;
}
static byte[] prepareSeparateRenderData(WritingBuffer buf, Render ren)
{
byte[] newArr = new byte[8]; //Data used to display the separate arrangements
writeUShortToByteArrLE(newArr, 0, (ushort)(buf.startPos + 1)); //The + 1 is needed because the map starts from 1, not from 0
writeUShortToByteArrLE(newArr, 2, (ushort)(ren.Y + 0x19)); //Apparently, the actual arrangements start at y = 0x19...
writeUShortToByteArrLE(newArr, 4, (ushort)(buf.used));
writeUShortToByteArrLE(newArr, 6, (ushort)(WritingBuffer.yLength));
return newArr;
}
static byte[] prepareSeparateRender(WritingBuffer buf)
{
//Converts the arrangements to an array that is to be included separately
byte[] newArr = new byte[WritingBuffer.yLength * buf.used * 2];
for (int j = 0; j < WritingBuffer.yLength; j++)
for (int i = 0; i < buf.used; i++)
writeUShortToByteArrLE(newArr, (i + (j * buf.used)) * 2, buf.arrangements[j, i]);
return newArr;
}
static int readIntLE(byte[] arr, int pos)
{
return arr[pos] + (arr[pos + 1] << 8) + (arr[pos + 2] << 16) + (arr[pos + 3] << 24);
}
static ushort readUShortLE(byte[] arr, int pos)
{
return (ushort)(arr[pos] + (arr[pos + 1] << 8));
}
static void writeIntToByteArrLE(byte[] arr, int pos, int val)
{
for (int i = 0; i < 4; i++)
arr[pos + i] = (byte)((val >> (i * 8)) & 0xFF);
}
static void writeUShortToByteArrLE(byte[] arr, int pos, ushort val)
{
for (int i = 0; i < 2; i++)
arr[pos + i] = (byte)((val >> (i * 8)) & 0xFF);
}
static byte[] convertUShortToByteArrLE(ushort val)
{
byte[] newArr = new byte[2];
newArr[0] = (byte)((val) & 0xFF);
newArr[1] = (byte)((val >> 8) & 0xFF);
return newArr;
}
static byte[] convertUShortArrToByteArrLE(ushort[] arr)
{
byte[] newArr = new byte[arr.Length * 2];
for (int i = 0; i < arr.Length; i++)
{
newArr[(i * 2)] = (byte)((arr[i]) & 0xFF);
newArr[(i * 2) + 1] = (byte)((arr[i] >> 8) & 0xFF);
}
return newArr;
}
static int insertInGraphics(WritingBuffer buf, int usedInGraphics)
{
//Optimally inserts the graphics inside the final product
int total = usedInGraphics;
for (int i = 0; i < buf.used; i++)
{
for (int j = 0; j < WritingBuffer.yLength; j++)
{
_1bppTile tile = buf.tiles[j, i];
int rot = 0;
int pos = -1;
if (emptyTile.Equals(tile))
pos = 0x2FF; //Empty tile
else
pos = getPosInFinal(tile, total, _1bppGraphics);
if (pos == -1)
{
rot = 1;
pos = getPosInFinal(tile, total, _1bppGraphics_RotX);
if (pos == -1)
{
rot = 2;
pos = getPosInFinal(tile, total, _1bppGraphics_RotY);
if (pos == -1)
{
rot = 3;
pos = getPosInFinal(tile, total, _1bppGraphics_RotXY);
}
}
}
if (pos == -1) //Hasn't been found in any of the ways the buffer can be looked at
{
rot = 0;
pos = total++;
_1bppGraphics[pos] = tile; //If we're here, we already calculated all four of them
_1bppGraphics_RotX[pos] = tile.rotateX();
_1bppGraphics_RotY[pos] = tile.rotateY();
_1bppGraphics_RotXY[pos] = _1bppGraphics_RotX[pos].rotateY();
}
buf.arrangements[j, i] = (ushort)(Palette | (pos + arrStart) | (rot << 0xA));
}
}
return total;
}
static int getPosInFinal(_1bppTile tile, int total, _1bppTile[] finalProd)
{
int pos = -1;
for (int k = 0; k < total; k++)
if (finalProd[k].Equals(tile))
{
pos = k;
break;
}
return pos;
}
static WritingBuffer renderText(Render r)
{
WritingBuffer a = new WritingBuffer();
byte[] text = getTextBytes(r.Text);
int len = getTextLength(text, r.Font);
int x = r.Center_X - (len / 2);
//Boundary checks
if (x + len > 240)
x = 240 - len;
if (x < 0)
x = 0;
a.startPos = (x >> 3);
int bufferPos = x & 7;
for (int i = 0; i < text.Length; i++)
bufferPos += _1bppRenderChar(text[i], bufferPos, r.Font, a);
a.used = (bufferPos + 7) >> 3;
return a;
}
static byte _1bppRenderChar(byte chr, int x, int font, WritingBuffer buf)
{
//Renders a character
int tileHeight = 2;
int tileWidth = 2;
int tileX = x >> 3;
int chrPos = chr * tileWidth * tileHeight * 8;
int offsetX = x & 7;
int startOffsetY = 3 & 7;
if(font == 1) //Saturn font is higher, for some reason...
startOffsetY = 0;
byte vWidth = Fonts[font].fontWidth[chr * 2];
byte rWidth = Fonts[font].fontWidth[(chr * 2) + 1];
if (font == 1 && vWidth != rWidth) //The Saturn font is compressed horizontally by removing 1 trailing pixel
vWidth -= 1;
for(int dTileY = 0; dTileY < tileHeight; dTileY++)
{
int dTileX = 0;
int renderedWidth = rWidth;
while (renderedWidth > 0)
{
int offsetY = startOffsetY & 7;
int tileIndexX = tileX + dTileX;
int tileIndexY = dTileY;
_1bppTile leftTile = buf.tiles[dTileY, tileIndexX];
_1bppTile rightTile = buf.tiles[dTileY, tileIndexX + 1];
for (int row = 0; row < 8; row++)
{
ushort canvasRow = (ushort)(leftTile.getRow(row + offsetY) | (rightTile.getRow(row + offsetY) << 8));
ushort glyphRow = (ushort)(Fonts[font].font[chrPos + row + (((dTileY * tileWidth) + dTileX) * 8)] << offsetX);
canvasRow |= glyphRow;
leftTile.setRow(row + offsetY, (byte)(canvasRow & 0xFF));
rightTile.setRow(row + offsetY, (byte)((canvasRow >> 8) & 0xFF));
if(row != 7 && row + offsetY == 7)
{
offsetY = -(row + 1);
tileIndexY++;
leftTile = buf.tiles[tileIndexY, tileIndexX];
rightTile = buf.tiles[tileIndexY, tileIndexX + 1];
}
}
renderedWidth -= 8;
dTileX++;
}
}
return vWidth;
}
static byte[] getTextBytes(String str)
{
//Reads a string and converts it to bytes
List<byte> tokens = new List<byte>();
for (int i = 0; str.Length > 0; i++)
{
string token = str[0].ToString();
str = str.Substring(1);
if (token == "[")
while (str.Length > 0 && !token.EndsWith("]"))
{
token += str[0].ToString();
str = str.Substring(1);
}
if (m12CharByteLookup.ContainsKey(token))
tokens.Add(m12CharByteLookup[token]);
}
return tokens.ToArray();
}
static int getTextLength(byte[] text, int Font)
{
int len = 0;
for (int i = 0; i < text.Length; i++)
{
len += Fonts[Font].fontWidth[2 * text[i]];
if (Font == 1 && Fonts[Font].fontWidth[2 * text[i]] != Fonts[Font].fontWidth[(2 * text[i]) + 1]) //Handle Saturn font compression
len -= 1;
}
return len;
}
}
}

View File

@ -0,0 +1,9 @@
{
"profiles": {
"ScriptTool": {
"commandName": "Project",
"commandLineArgs": "-compile -main -misc \"..\\working\" \"..\\eb.smc\" \"..\\m12fresh.gba\"",
"workingDirectory": "C:\\Users\\jeffe\\M12\\bin\\ScriptTool"
}
}
}

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
</ItemGroup>
<ItemGroup>
<None Update="bits_to_nybbles.bin">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="m12-byte-lookup.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace RenderCastRoll
{
public class Render
{
public int Y { get; set; }
public int Center_X { get; set; }
public string Text { get; set; }
public int Font { get; set; }
public string Separate_file_name { get; set; }
}
public class RenderRoot
{
public List<Render> Renders { get; set; }
}
public class RenderFont
{
public byte[] font;
public byte[] fontWidth;
public RenderFont(string folder, string fontName)
{
font = File.ReadAllBytes(folder + "m2-font-" + fontName + ".bin");
fontWidth = File.ReadAllBytes(folder + "m2-widths-" + fontName + ".bin");
}
}
public class _1bppTile
{
UInt64 tile;
public _1bppTile() : this(0) { }
public _1bppTile(UInt64 val)
{
tile = val;
}
public byte getRow(int i)
{
return (byte)((tile >> (i * 8)) & 0xFF);
}
public void setRow(int i, byte val)
{
UInt64 mask = ~((UInt64)(0xFF) << (i * 8));
tile = (tile & mask) | ((UInt64)val << (i * 8));
}
public UInt64 getColumn(int i)
{
UInt64 mask = (UInt64)(0x0101010101010101 << i);
return mask & tile;
}
public void setColumn(int i, UInt64 val)
{
UInt64 mask = ~(UInt64)(0x0101010101010101 << i);
tile = (tile & mask) | val;
}
public bool Equals(_1bppTile t)
{
return this.tile == t.tile;
}
public _1bppTile rotateX()
{
_1bppTile newTile = new _1bppTile(tile);
for (int row = 0; row < 8; row++)
{
byte val = newTile.getRow(row);
byte newVal = 0;
for (int i = 0; i < 8; i++)
newVal |= (byte)(((val >> i) & 1) << (7 - i));
newTile.setRow(row, newVal);
}
return newTile;
}
public _1bppTile rotateY()
{
_1bppTile newTile = new _1bppTile(tile);
for (int column = 0; column < 8; column++)
{
UInt64 val = newTile.getColumn(column);
UInt64 newVal = 0;
for (int i = 0; i < 8; i++)
newVal |= ((val >> (i * 8)) & 0xFF) << ((7 - i) * 8);
newTile.setColumn(column, newVal);
}
return newTile;
}
public override String ToString()
{
String str = "";
for (int i = 0; i < 8; i++)
str += getRow(i).ToString("X") + " ";
return str;
}
}
public class WritingBuffer
{
public static readonly int yLength = 3;
public _1bppTile[,] tiles;
public ushort[,] arrangements;
public int used;
public int startPos;
public WritingBuffer()
{
used = 0;
startPos = 0;
tiles = new _1bppTile[yLength, 0x20];
arrangements = new ushort[yLength, 0x20];
for (int i = 0; i < yLength; i++)
for (int j = 0; j < 0x20; j++)
{
tiles[i, j] = new _1bppTile();
arrangements[i, j] = 0x3FF; //Empty tile
}
}
}
}

Binary file not shown.

View File

@ -0,0 +1,99 @@
{
" ": 0,
"!": 1,
"\"": 2,
"#": 3,
"$": 4,
"%": 5,
"&": 6,
"'": 7,
"(": 8,
")": 9,
"*": 10,
"+": 11,
",": 12,
"-": 13,
".": 129,
"/": 15,
"0": 16,
"1": 17,
"2": 18,
"3": 19,
"4": 20,
"5": 21,
"6": 22,
"7": 23,
"8": 24,
"9": 25,
":": 26,
";": 27,
"<": 28,
"=": 29,
">": 30,
"?": 31,
"@": 32,
"A": 33,
"B": 34,
"C": 35,
"D": 36,
"E": 37,
"F": 38,
"G": 39,
"H": 40,
"I": 41,
"J": 42,
"K": 43,
"L": 44,
"M": 45,
"N": 46,
"O": 47,
"P": 48,
"Q": 49,
"R": 50,
"S": 51,
"T": 52,
"U": 53,
"V": 54,
"W": 55,
"X": 56,
"Y": 57,
"Z": 58,
"[8B]": 59,
"[8C]": 60,
"[8D]": 61,
"[8E]": 62,
"[8F]": 63,
"`": 64,
"a": 65,
"b": 66,
"c": 67,
"d": 68,
"e": 69,
"f": 70,
"g": 71,
"h": 72,
"i": 73,
"j": 74,
"k": 75,
"l": 76,
"m": 77,
"n": 78,
"o": 79,
"p": 80,
"q": 81,
"r": 82,
"s": 83,
"t": 84,
"u": 85,
"v": 86,
"w": 87,
"x": 88,
"y": 89,
"z": 90,
"{": 91,
"|": 92,
"}": 93,
"~": 94,
"[AF]": 95,
"[DOT]": 128
}

361
working/cast_roll.json Normal file
View File

@ -0,0 +1,361 @@
{
"Renders":[
{
"Y":16,
"Center_X":120,
"Text":"Picky Minch",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":24,
"Center_X":64,
"Text":"Lardna Minch",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":24,
"Center_X":176,
"Text":"Aloysius Minch",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":32,
"Center_X":120,
"Text":"Pokey Minch",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":42,
"Center_X":120,
"Text":"Buzz Buzz",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":51,
"Center_X":120,
"Text":"Lier`X.`Agerate",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":62,
"Center_X":120,
"Text":"Frank Fly",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":71,
"Center_X":120,
"Text":"The Sharks",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":82,
"Center_X":120,
"Text":"B. H. Pirkle",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":93,
"Center_X":120,
"Text":"Captain Strong",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":102,
"Center_X":120,
"Text":"Onett police force",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":109,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":139,
"Center_X":120,
"Text":"Orange kid",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":148,
"Center_X":120,
"Text":"Apple kid",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":159,
"Center_X":120,
"Text":"Mr. Everdred",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":175,
"Center_X":120,
"Text":"Runaway Five",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":182,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":194,
"Center_X":120,
"Text":"Happy Happyists",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":204,
"Center_X":120,
"Text":"Carpainter",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":211,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":223,
"Center_X":120,
"Text":"Bubble Monkey",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":230,
"Center_X":64,
"Text":"Tony",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":230,
"Center_X":176,
"Text":"Maxwell",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":237,
"Center_X":120,
"Text":"Tessie",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":245,
"Center_X":120,
"Text":"Tessie-Watching Club",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":257,
"Center_X":120,
"Text":"Brickroad",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":272,
"Center_X":80,
"Text":"Dr. Andonuts",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":290,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":313,
"Center_X":120,
"Text":"mr.saturn",
"Font": 1,
"Separate_file_name": ""
},
{
"Y":325,
"Center_X":120,
"Text":"Master Belch",
"Font": 0,
"Separate_file_name": "master_belch"
},
{
"Y":332,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":344,
"Center_X":64,
"Text":"George Montague",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":354,
"Center_X":120,
"Text":"Gerardo Montague",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":371,
"Center_X":120,
"Text":"Talah Rama",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":378,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":389,
"Center_X":120,
"Text":"Geldegarde Monotoli",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":400,
"Center_X":120,
"Text":"Venus",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":407,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":429,
"Center_X":64,
"Text":"Star Master",
"Font": 0,
"Separate_file_name": "star_master"
},
{
"Y":438,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":457,
"Center_X":120,
"Text":"Dungeon Man",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":457,
"Center_X":192,
"Text":"Noble warrior",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":464,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":474,
"Center_X":120,
"Text":"Tenda tribesmen",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":481,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":497,
"Center_X":120,
"Text":"Flying Men",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":504,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":558,
"Center_X":120,
"Text":"[DOT]",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":570,
"Center_X":96,
"Text":"Dad",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":579,
"Center_X":72,
"Text":"Tracy",
"Font": 0,
"Separate_file_name": ""
},
{
"Y":579,
"Center_X":168,
"Text":"Mom",
"Font": 0,
"Separate_file_name": ""
}
]
}

View File

@ -2202,7 +2202,7 @@
^L2186^[1C FF 02 00 _L2188_]@Good morning everyone![1B FF 14 00] Are[01 FF] you ready for your adventure?[02 FF]@I think all of you are the bee's[01 FF] knees.[1B FF 14 00] Yes,[1B FF 0A 00] I do![02 FF]^L2188^@You are all so... cool![1B FF 14 00] Yes,[1B FF 0A 00][01 FF] you're hip![1D FF][00 FF] ^L2186^[1C FF 02 00 _L2188_]@Good morning everyone![1B FF 14 00] Are[01 FF] you ready for your adventure?[02 FF]@I think all of you are the bee's[01 FF] knees.[1B FF 14 00] Yes,[1B FF 0A 00] I do![02 FF]^L2188^@You are all so... cool![1B FF 14 00] Yes,[1B FF 0A 00][01 FF] you're hip![1D FF][00 FF]
^L2192^[92 FF 03 01 02][81 FF _L3986_][92 FF 03 01 03][81 FF _L3986_][1C FF B8 02 _L3987_][FB FF 64 00]^L3988^[82 FF _L3986_]@Working through the night,[01 FF] [0F FF] fixed[01 FF] the [90 FF 00][1A FF 02 00].[02 FF]@After being fixed, the[01 FF] [90 FF 00][1A FF 02 00] became[01 FF] the [87 FF][90 FF 00][1A FF 02 00].[02 FF][08 FF B8 02][C6 FF]^L3986^[00 FF] ^L2192^[92 FF 03 01 02][81 FF _L3986_][92 FF 03 01 03][81 FF _L3986_][1C FF B8 02 _L3987_][FB FF 64 00]^L3988^[82 FF _L3986_]@Working through the night,[01 FF] [0F FF] fixed[01 FF] the [90 FF 00][1A FF 02 00].[02 FF]@After being fixed, the[01 FF] [90 FF 00][1A FF 02 00] became[01 FF] the [87 FF][90 FF 00][1A FF 02 00].[02 FF][08 FF B8 02][C6 FF]^L3986^[00 FF]
^L2193^@[0D FF],[1B FF 0F 00] could you get the[01 FF] phone?[1D FF][00 FF] ^L2193^@[0D FF],[1B FF 0F 00] could you get the[01 FF] phone?[1D FF][00 FF]
^L2194^@Did you finish doing everything[01 FF] that you wanted to?[22 FF][03 FF 00 00][04 FF _L2198_][05 FF _L2199_]^L2199^@You'd better do everything,[1B FF 0F 00][01 FF] because once you start looking[01 FF] at the album,[02 FF]@you can't stop![1D FF][00 FF]^L2198^@Okay![1B FF 14 00] Now you can finally[01 FF] share your incredible[01 FF] experiences with me...[02 FF]@You did so well![02 FF][C6 FF][86 FF _L2200_][86 FF _L2201_][C4 FF 00 5E][D9 FF 05 00][1C FF 7E 02 _L2202_][CB FF 02 00 06 00][A0 FF 01 00 12 03 01 00][1B FF 01 00][A6 FF 01 00 01 00]^L2202^[CB FF 01 00 06 00][A0 FF 00 00 21 03 01 00][1B FF 01 00][A6 FF 00 00 01 00][CE FF 0E 00 05 00][A1 FF 0E 00 01 00][CE FF 12 00 05 00][A1 FF 12 00 01 00][1B FF 78 00][1B FF 78 00][1B FF 78 00][1B FF 78 00][1B FF 78 00][1B FF 3C 00][A0 FF 29 00 C0 02 01 00][1B FF 3C 00][1B FF 64 00][A0 FF D0 07 C1 02 01 00][9E FF][86 FF _L2201_][FC FF 13 00][14 FF 6E 00][FC FF 2E 00][FC FF 14 00][C4 FF 00 5F][A0 FF 47 00 F5 02 01 00][9E FF][A0 FF B4 02 F6 02 01 00][9E FF][A0 FF 19 01 F7 02 01 00][9E FF][FC FF 13 00][14 FF 89 00][CB FF FF 00 06 00][FC FF 0C 00][9E FF][1B FF 3C 00][FC FF 15 00][86 FF _L2203_][00 FF] ^L2194^@Did you finish doing everything[01 FF] that you wanted to?[22 FF][03 FF 00 00][04 FF _L2198_][05 FF _L2199_]^L2199^@You'd better do everything,[1B FF 0F 00][01 FF] because once you start looking[01 FF] at the album,[02 FF]@you can't stop![1D FF][00 FF]^L2198^@Okay![1B FF 14 00] Now you can finally[01 FF] share your incredible[01 FF] experiences with me...[02 FF]@You did so well![02 FF][C6 FF][86 FF _L2200_][86 FF _L2201_][C4 FF 00 5E][D9 FF 05 00][1C FF 7E 02 _L2202_][CB FF 02 00 06 00][A0 FF 01 00 12 03 01 00][1B FF 01 00][A6 FF 01 00 01 00]^L2202^[CB FF 01 00 06 00][A0 FF 00 00 21 03 01 00][1B FF 01 00][A6 FF 00 00 01 00][CE FF 0E 00 05 00][A1 FF 0E 00 01 00][CE FF 12 00 05 00][A1 FF 12 00 01 00][1B FF 78 00][1B FF 78 00][1B FF 78 00][1B FF 78 00][1B FF 78 00][1B FF 3C 00][A0 FF 29 00 C0 02 01 00][1B FF 3C 00][1B FF 64 00][A0 FF D0 07 C1 02 01 00][9E FF][FC FF 0B 00][14 FF 88 00][FC FF 2D 00][A0 FF D0 07 C2 02 01 00][CB FF FF 00 06 00][9E FF][86 FF _L2201_][FC FF 13 00][14 FF 6E 00][FC FF 2E 00][FC FF 14 00][C4 FF 00 5F][A0 FF 47 00 F5 02 01 00][9E FF][A0 FF B4 02 F6 02 01 00][9E FF][A0 FF 19 01 F7 02 01 00][9E FF][FC FF 13 00][14 FF 89 00][CB FF FF 00 06 00][FC FF 0C 00][9E FF][1B FF 3C 00][FC FF 15 00][86 FF _L2203_][00 FF]
^L2195^^L2196^@After all your chats with people[01 FF] you met on your adventure are[01 FF] finally over,[02 FF]@please come back here.[02 FF]@The photo-man brought an[01 FF] album by.[02 FF]@I'd like to look at it with you...[1D FF][C6 FF][08 FF 83 02][83 FF 8E 02][82 FF _L2197_][1B FF 3C 00][A1 FF 15 00 7B 00][08 FF F1 02][00 FF] ^L2195^^L2196^@After all your chats with people[01 FF] you met on your adventure are[01 FF] finally over,[02 FF]@please come back here.[02 FF]@The photo-man brought an[01 FF] album by.[02 FF]@I'd like to look at it with you...[1D FF][C6 FF][08 FF 83 02][83 FF 8E 02][82 FF _L2197_][1B FF 3C 00][A1 FF 15 00 7B 00][08 FF F1 02][00 FF]
^L2197^[00 FF] ^L2197^[00 FF]
^L2200^[09 FF B4 00][09 FF B5 00][09 FF 85 02][09 FF BE 01][09 FF 86 02][09 FF 87 02][09 FF 88 02][09 FF B6 02][09 FF B7 02][86 FF _L4002_][09 FF F2 02][FC FF 3A 00][00 FF] ^L2200^[09 FF B4 00][09 FF B5 00][09 FF 85 02][09 FF BE 01][09 FF 86 02][09 FF 87 02][09 FF 88 02][09 FF B6 02][09 FF B7 02][86 FF _L4002_][09 FF F2 02][FC FF 3A 00][00 FF]
@ -3658,7 +3658,7 @@
^L4038^[08 FF 3C 00][14 FF 86 00][FC FF 16 00][AF FF 02][EA FF FF 00][A0 FF D0 07 BE 02 01 00][1B FF 01 00][C9 FF D0 07][EB FF FF 00][00 FF] ^L4038^[08 FF 3C 00][14 FF 86 00][FC FF 16 00][AF FF 02][EA FF FF 00][A0 FF D0 07 BE 02 01 00][1B FF 01 00][C9 FF D0 07][EB FF FF 00][00 FF]
^L4039^[EA FF FF 00][14 FF 87 00][FC FF 16 00][AF FF 03][A0 FF D0 07 BF 02 01 00][1B FF 01 00][C9 FF D0 07][EB FF FF 00][9E FF][FC FF 17 00][9E FF][FC FF 19 00][00 FF] ^L4039^[EA FF FF 00][14 FF 87 00][FC FF 16 00][AF FF 03][A0 FF D0 07 BF 02 01 00][1B FF 01 00][C9 FF D0 07][EB FF FF 00][9E FF][FC FF 17 00][9E FF][FC FF 19 00][00 FF]
^L4040^[1B FF 01 00][C9 FF D0 07][EB FF FF 00][9E FF][CA FF][EA FF FF 00][00 FF] ^L4040^[1B FF 01 00][C9 FF D0 07][EB FF FF 00][9E FF][CA FF][EA FF FF 00][00 FF]
^L4041^[74 FF][D4 FF 08 00][A0 FF D0 07 14 00 01 00][86 FF _L4040_][A0 FF 2D 00 FA 02 01 00][85 FF 16 00 06 00][D4 FF 09 00][CA FF][DC FF 2D 00 01 00 01 00][DA FF 2D 00 00 00][C3 FF 01 03 2D 00][D8 FF 01 00 00 00][EA FF FF 00][1B FF 01 00][AA FF 2D 00][09 FF 27 01][08 FF D3 01][08 FF 61 00][1B FF 1E 00][C4 FF 00 B1][1B FF 78 00][1B FF 78 00][1B FF 14 00]@A letter arrived from my[01 FF] brother, Pokey...[1B FF 0F 00] it is[01 FF] addressed to [0D FF].[02 FF]@There's no stamp,[1B FF 0F 00] and it's not[01 FF] time for the mailman to come...[02 FF]@Anyway, I brought it over.[02 FF]@It says,[1B FF 0F 00] <come and get me,[01 FF] loser![02 FF]@Spankety, spankety, spankety.>[02 FF]@...I wonder where he is?[1D FF][1B FF 14 00][C6 FF][1B FF 01 00][08 FF D1 00][FC FF 1E 00][9E FF][CB FF FF 00 06 00][09 FF 83 02][09 FF D1 00][08 FF DA 01][14 FF 6E 00][FC FF 1F 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][FC FF 35 00][00 FF] ^L4041^[74 FF][D4 FF 08 00][A0 FF D0 07 14 00 01 00][86 FF _L4040_][A0 FF 2D 00 FA 02 01 00][85 FF 16 00 06 00][D4 FF 09 00][CA FF][DC FF 2D 00 01 00 01 00][DA FF 2D 00 00 00][C3 FF 01 03 2D 00][D8 FF 01 00 00 00][EA FF FF 00][1B FF 01 00][AA FF 2D 00][09 FF 27 01][08 FF D3 01][08 FF 61 00][1B FF 1E 00][C4 FF 00 B1][1B FF 78 00][1B FF 78 00][1B FF 14 00]@A letter arrived from my[01 FF] brother, Pokey...[1B FF 0F 00] it is[01 FF] addressed to [0D FF].[02 FF]@There's no stamp,[1B FF 0F 00] and it's not[01 FF] time for the mailman to come...[02 FF]@Anyway, I brought it over.[02 FF]@It says,[1B FF 0F 00] <come and get me,[01 FF] loser![02 FF]@Spankety, spankety, spankety.>[02 FF]@...I wonder where he is?[1D FF][1B FF 14 00][C6 FF][1B FF 01 00][08 FF D1 00][FC FF 1E 00][9E FF][CB FF FF 00 06 00][09 FF 83 02][09 FF D1 00][08 FF DA 01][14 FF 6E 00][FC FF 1F 00][1B FF 3C 00][FC FF 49 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][1B FF 3C 00][FC FF 35 00][00 FF]
^L4042^[C6 FF][AE FF 06][CB FF 06 00 06 00][A6 FF 2D 00 16 00][9E FF][A5 FF 2D 00 06 00][CC FF 06 00 01 00][C4 FF 00 7B][1B FF 78 00][1B FF 3C 00][C5 FF]@(Picky joins you.)[02 FF][C6 FF][00 FF] ^L4042^[C6 FF][AE FF 06][CB FF 06 00 06 00][A6 FF 2D 00 16 00][9E FF][A5 FF 2D 00 06 00][CC FF 06 00 01 00][C4 FF 00 7B][1B FF 78 00][1B FF 3C 00][C5 FF]@(Picky joins you.)[02 FF][C6 FF][00 FF]
^L4043^[FC FF 33 00][6E FF 01 00][C3 FF 05 01 01 00][D8 FF 05 00 00 00][C3 FF 01 01 05 00][D8 FF 01 00 00 00]@[0D FF]![02 FF]@Do you hear a buzzing that[01 FF] sounds like a bee flying around?[22 FF][03 FF 00 00][04 FF _L4046_][05 FF _L4047_]^L4047^@Oh, c'mon...[1B FF 14 00] You must hear[01 FF] it...[02 FF][80 FF _L4048_]^L4046^@Yes! You can hear it![02 FF]^L4048^[C6 FF][C4 FF 00 76][1B FF 3C 00][C3 FF 01 02 C6 00][D8 FF 01 00 00 00][C3 FF 05 02 C6 00][D8 FF 05 00 00 00][C3 FF 06 02 C6 00][D8 FF 06 00 00 00][A9 FF 35 01][A0 FF D0 07 24 00 01 00][9E FF][A0 FF D5 00 25 00 01 00][9E FF]^L4051^@A bee I am[02 FF]@not...[02 FF]@I'm from 10 years in the[01 FF] future.[02 FF]@And,[02 FF]@in the future,[1B FF 0F 00] all is[01 FF] devastation...[02 FF]@Giygas, the universal cosmic[01 FF] destroyer,[02 FF]@sent all to the horror of eternal[01 FF] darkness...[02 FF]@.....[02 FF]@However,[1B FF 14 00] you must listen![02 FF]@Where I am from,[02 FF]@there is a well-known legend[01 FF] that has been handed down[01 FF] from ancient times.[02 FF]@It says <When the chosen boy[01 FF] reaches the point,[1B FF 0F 00] he will find[01 FF] the light.[02 FF]@The passing of time will shatter[01 FF] the nightmare rock[02 FF]@and will reveal the path of[01 FF] light.>[02 FF]@You see,[1B FF 0F 00] it is my opinion that[01 FF] you are that boy, [0D FF].[02 FF]@This I believe...[02 FF]@.....[02 FF]@Giygas' monstrous plan must[01 FF] have been set in motion[01 FF] somewhere on Earth...[02 FF]@If you start to confront the[01 FF] enemy immediately,[02 FF]@you may have time to counter[01 FF] the evil intentions of Giygas.[02 FF]@Three things are of the utmost[01 FF] importance:[1B FF 1E 00] wisdom,[1B FF 0F 00] courage,[1B FF 14 00][01 FF] and friendship.[02 FF]@...The legends from the ancient[01 FF] times tell of three boys and a[01 FF] girl[02 FF]@who defeat Giygas.[02 FF]@...I will tell you more later.[02 FF]@Go now![1B FF 14 00] And do not be anxious[01 FF] about the future.[02 FF]@You have much work to do,[01 FF] [0D FF].[02 FF]@Did you listen to what I told[01 FF] you?[03 FF 00 00][04 FF _L4049_][05 FF _L4050_]^L4050^@I hate to go over it again,[1B FF 0F 00] but I[01 FF] guess I'll start over...[02 FF]@We'll be here 'til sunrise![02 FF][C7 FF][80 FF _L4051_]^L4049^@Thank you for listening to my[01 FF] long story.[02 FF]@You are as exceptional as I[01 FF] expected you to be...[02 FF][C6 FF][C4 FF 00 0B][1B FF 78 00][1B FF 3C 00][1B FF 78 00][1B FF 78 00]@Buzz Buzz now joins you.[02 FF][C6 FF][A9 FF D5 00][08 FF 12 00][C5 FF][A9 FF D5 00][1B FF 3C 00][B2 FF 05 00 CC 00][1B FF 3C 00][B5 FF 05 00][AA FF D5 00]@[0D FF]![02 FF]@It looks like you're really in a lot[01 FF] of trouble this time...[02 FF]@Three boys,[1B FF 0F 00] he said? ...Uhhh...[02 FF]@I'm not one of those three, am[01 FF] I?...[02 FF]@...'Cause... I'm not into this kind[01 FF] of thing at all...[02 FF]@Geez.[1B FF 14 00] My heart is almost[01 FF] pounding right out of my[01 FF] chest!...[02 FF][C6 FF][9D FF 01 2B _L3912_][FC FF 34 00][00 FF] ^L4043^[FC FF 33 00][6E FF 01 00][C3 FF 05 01 01 00][D8 FF 05 00 00 00][C3 FF 01 01 05 00][D8 FF 01 00 00 00]@[0D FF]![02 FF]@Do you hear a buzzing that[01 FF] sounds like a bee flying around?[22 FF][03 FF 00 00][04 FF _L4046_][05 FF _L4047_]^L4047^@Oh, c'mon...[1B FF 14 00] You must hear[01 FF] it...[02 FF][80 FF _L4048_]^L4046^@Yes! You can hear it![02 FF]^L4048^[C6 FF][C4 FF 00 76][1B FF 3C 00][C3 FF 01 02 C6 00][D8 FF 01 00 00 00][C3 FF 05 02 C6 00][D8 FF 05 00 00 00][C3 FF 06 02 C6 00][D8 FF 06 00 00 00][A9 FF 35 01][A0 FF D0 07 24 00 01 00][9E FF][A0 FF D5 00 25 00 01 00][9E FF]^L4051^@A bee I am[02 FF]@not...[02 FF]@I'm from 10 years in the[01 FF] future.[02 FF]@And,[02 FF]@in the future,[1B FF 0F 00] all is[01 FF] devastation...[02 FF]@Giygas, the universal cosmic[01 FF] destroyer,[02 FF]@sent all to the horror of eternal[01 FF] darkness...[02 FF]@.....[02 FF]@However,[1B FF 14 00] you must listen![02 FF]@Where I am from,[02 FF]@there is a well-known legend[01 FF] that has been handed down[01 FF] from ancient times.[02 FF]@It says <When the chosen boy[01 FF] reaches the point,[1B FF 0F 00] he will find[01 FF] the light.[02 FF]@The passing of time will shatter[01 FF] the nightmare rock[02 FF]@and will reveal the path of[01 FF] light.>[02 FF]@You see,[1B FF 0F 00] it is my opinion that[01 FF] you are that boy, [0D FF].[02 FF]@This I believe...[02 FF]@.....[02 FF]@Giygas' monstrous plan must[01 FF] have been set in motion[01 FF] somewhere on Earth...[02 FF]@If you start to confront the[01 FF] enemy immediately,[02 FF]@you may have time to counter[01 FF] the evil intentions of Giygas.[02 FF]@Three things are of the utmost[01 FF] importance:[1B FF 1E 00] wisdom,[1B FF 0F 00] courage,[1B FF 14 00][01 FF] and friendship.[02 FF]@...The legends from the ancient[01 FF] times tell of three boys and a[01 FF] girl[02 FF]@who defeat Giygas.[02 FF]@...I will tell you more later.[02 FF]@Go now![1B FF 14 00] And do not be anxious[01 FF] about the future.[02 FF]@You have much work to do,[01 FF] [0D FF].[02 FF]@Did you listen to what I told[01 FF] you?[03 FF 00 00][04 FF _L4049_][05 FF _L4050_]^L4050^@I hate to go over it again,[1B FF 0F 00] but I[01 FF] guess I'll start over...[02 FF]@We'll be here 'til sunrise![02 FF][C7 FF][80 FF _L4051_]^L4049^@Thank you for listening to my[01 FF] long story.[02 FF]@You are as exceptional as I[01 FF] expected you to be...[02 FF][C6 FF][C4 FF 00 0B][1B FF 78 00][1B FF 3C 00][1B FF 78 00][1B FF 78 00]@Buzz Buzz now joins you.[02 FF][C6 FF][A9 FF D5 00][08 FF 12 00][C5 FF][A9 FF D5 00][1B FF 3C 00][B2 FF 05 00 CC 00][1B FF 3C 00][B5 FF 05 00][AA FF D5 00]@[0D FF]![02 FF]@It looks like you're really in a lot[01 FF] of trouble this time...[02 FF]@Three boys,[1B FF 0F 00] he said? ...Uhhh...[02 FF]@I'm not one of those three, am[01 FF] I?...[02 FF]@...'Cause... I'm not into this kind[01 FF] of thing at all...[02 FF]@Geez.[1B FF 14 00] My heart is almost[01 FF] pounding right out of my[01 FF] chest!...[02 FF][C6 FF][9D FF 01 2B _L3912_][FC FF 34 00][00 FF]
^L4044^[AF FF 07][00 FF] ^L4044^[AF FF 07][00 FF]