Complete cast roll sequence

This commit is contained in:
Lorenzo Carletti 2020-08-24 17:28:29 +02:00
parent 01765bde39
commit 663b6fee15
16 changed files with 491 additions and 5 deletions

View File

@ -29,4 +29,288 @@ void printPlayerNameCredits(unsigned short *arrangements)
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;
}

View File

@ -5,10 +5,36 @@
#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.

Binary file not shown.

View File

@ -0,0 +1 @@
0

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
0

Binary file not shown.

Binary file not shown.

View File

@ -1711,8 +1711,23 @@ nop
//Repoint cast graphical data
.org 0x82DB25C :: dw m2_cast_graphics
.org 0x82DB260 :: dw m2_cast_palette
.org 0x82DB264 :: dw m2_cast_arrangements
//Remove flavour changing the palette
.org 0x801043A :: b 0x8010500
//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"
//==============================================================================
// Move stuff around in order to make space for the code
//==============================================================================
@ -1822,18 +1837,25 @@ m2_widths_battle:
m2_widths_tiny:
.incbin "data/m2-widths-tiny.bin"
.align 4
m2_bits_to_nybbles:
.incbin "data/m2-bits-to-nybbles.bin"
m2_bits_to_nybbles_fast:
.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:
.incbin "data/m2-nybbles-to-bits.bin"
m2_enemy_attributes:
.incbin "data/m2-enemy-attributes.bin"
cast_vwf_names:
.include "data/cast-vwf-names.asm"
flyovertextYear:
.include "data/flyover-text-year.asm"
@ -1891,6 +1913,10 @@ m2_cast_vwf_free:
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"

View File

@ -83,6 +83,8 @@ namespace RenderCastRoll
//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]));
}
}
@ -107,15 +109,30 @@ namespace RenderCastRoll
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 contains the arrangements starting position, the length and the arrangements themselves
byte[] newArr = new byte[8 + (WritingBuffer.yLength * buf.used * 2)];
writeIntToByteArrLE(newArr, 0, buf.startPos + 1); //The + 1 is needed because the map starts from 1, not from 0
writeIntToByteArrLE(newArr, 4, buf.used);
//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, 8 + ((i + (j * buf.used)) * 2), buf.arrangements[j, i]);
writeUShortToByteArrLE(newArr, (i + (j * buf.used)) * 2, buf.arrangements[j, i]);
return newArr;
}
@ -232,8 +249,13 @@ namespace RenderCastRoll
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;