Lumine Hall's VWF

This commit is contained in:
Lorenzo Carletti 2020-08-19 12:30:28 +02:00
parent 2ad223a8cb
commit d3826d7662
9 changed files with 479 additions and 6 deletions

View File

@ -19,7 +19,8 @@ $input_c_files =
"src/c/status.c",
"src/c/battle.c",
"src/c/equip.c",
"src/c/psi.c"
"src/c/psi.c",
"src/c/luminehall.c"
$base_c_address = 0x83755B8;
$scripttool_cmd = "bin/ScriptTool/ScriptTool.dll"

View File

@ -3,6 +3,7 @@
void __attribute__((naked)) cpufastset(void *source, void *dest, int mode) {}
void __attribute__((naked)) cpuset(void *source, void *dest, int mode) {}
byte* __attribute__((naked)) m2_strlookup(int *offset_table, byte *strings, int index) {}
unsigned short* __attribute__((naked)) m2_get_hall_address() {}
int __attribute__((naked)) bin_to_bcd(int value, int* digit_count) {}
int __attribute__((naked)) m2_drawwindow(WINDOW* window) {}
int __attribute__((naked)) m2_resetwindow(WINDOW* window, bool skip_redraw) {}

305
src/c/luminehall.c Normal file
View File

@ -0,0 +1,305 @@
#include "luminehall.h"
#include "locs.h"
void writeLumineHallText()
{
//Function that writes out the Lumine text in the form of arrangements.
//It adds a VWF to what the base game did
byte *lumineText_curr_ptr = luminetext;
int *hallLineSize = &m2_hall_line_size;
int length = 0;
int currLenInTile = 0;
int currPos = 0;
int Tiles[4];
setTilesToBlank(Tiles);
//First things first, it calculates the total length of the text in pixels
while((*lumineText_curr_ptr) != END)
{
length += getCharWidth(*lumineText_curr_ptr);
lumineText_curr_ptr++;
}
//It then gets the length in arrangements. It also makes sure it's a number divisible by 8.
//This avoids having empty tiles showing
length = (length & 8 == 0 ? length : (length + (8 - (length & 7)))) >> 1;
(*hallLineSize) = length;
lumineText_curr_ptr = luminetext;
unsigned short *hallAddress = m2_get_hall_address();
//Prints out the characters
while((*lumineText_curr_ptr) != END)
{
readLumineCharacter(*lumineText_curr_ptr, Tiles, hallAddress, length, &currPos, &currLenInTile);
lumineText_curr_ptr++;
}
//Avoid having tiles that were not entirely printed
while((currPos*4) < length)
{
printVoidLumineTiles(hallAddress, length, currPos);
currPos++;
}
}
void readLumineCharacter(byte chr, int *Tiles, unsigned short *hallAddress, int length, int *currPos, int *currLen)
{
//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 converted (when it makes sense to do so) to arrangements by printLumineTiles.
int tileWidth = 2;
int tileHeight = 2;
int chosenLen;
int renderedLen;
byte *glyphRows;
int AlternativeTiles[4];
switch(chr)
{
case END:
return;
case ENDL:
printEmptyLumineTile(Tiles, hallAddress, length, *currPos, *currLen);
(*currPos)++;
return;
case BLANK:
printEmptyLumineTile(Tiles, hallAddress, length, *currPos, *currLen);
for(int i = 1; i < 8; i++)
printVoidLumineTiles(hallAddress, length, (*currPos) + i);
(*currPos) += 8;
return;
case PC_START:
case PC_START+1:
case PC_START+2:
case PC_START+3:
readLumineCharacterName(pc_names+(chr-PC_START)*PC_NAME_SIZE, Tiles, AlternativeTiles, hallAddress, length, currPos, currLen);
return;
default:
chosenLen = m2_widths_table[0][chr] & 0xFF;
renderedLen = m2_widths_table[0][chr] >> 8;
glyphRows = &m2_font_table[0][chr * tileWidth * tileHeight * 8];
}
if(chosenLen <= 0)
return;
if(((*currLen) + chosenLen) >= 8)
{
setTilesToBlank(AlternativeTiles);
if(renderedLen > 0)
printLumineCharacterInMultiTiles(Tiles, AlternativeTiles, glyphRows, renderedLen, *currLen);
printLumineTiles(Tiles, hallAddress, length, *currPos);
(*currPos)++;
copyTiles(Tiles, AlternativeTiles);
(*currLen) = ((*currLen) + chosenLen) & 7;
}
else
{
if(renderedLen > 0)
printLumineCharacterInSingleTiles(Tiles, glyphRows, renderedLen, *currLen);
(*currLen) += chosenLen;
}
}
void printEmptyLumineTile(int *Tiles, unsigned short *hallAddress, int length, int currPos, int currLen)
{
//Prints either an entirely empty tile or what's been done in the current tile
if(currLen == 0)
printVoidLumineTiles(hallAddress, length, currPos);
else
{
printLumineTiles(Tiles, hallAddress, length, currPos);
setTilesToBlank(Tiles);
}
}
void readLumineCharacterName(byte* str, int *Tiles, int* AlternativeTiles, unsigned short *hallAddress, int length, int *currPos, int *currLen)
{
//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 tileWidth = 2;
int tileHeight = 2;
int chosenLen;
int renderedLen;
byte *glyphRows;
for(int i = 0; i < PC_NAME_SIZE; i++)
{
if(*(str + 1) == 0xFF)
return;
byte chr = decode_character(*(str++));
chosenLen = m2_widths_table[0][chr] & 0xFF;
renderedLen = m2_widths_table[0][chr] >> 8;
glyphRows = &m2_font_table[0][chr * tileWidth * tileHeight * 8];
if(chosenLen <= 0)
continue;
if(((*currLen) + chosenLen) >= 8)
{
setTilesToBlank(AlternativeTiles);
if(renderedLen > 0)
printLumineCharacterInMultiTiles(Tiles, AlternativeTiles, glyphRows, renderedLen, *currLen);
printLumineTiles(Tiles, hallAddress, length, *currPos);
(*currPos)++;
copyTiles(Tiles, AlternativeTiles);
(*currLen) = ((*currLen) + chosenLen) & 7;
}
else
{
if(renderedLen > 0)
printLumineCharacterInSingleTiles(Tiles, glyphRows, renderedLen, *currLen);
(*currLen) += chosenLen;
}
}
}
void printLumineCharacterInMultiTiles(int *Tiles, int *AlternativeTiles, 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 = 2;
int tileHeight = 2;
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[tileIndex + half];
int alternativeTile = AlternativeTiles[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)] << currLen;
else if(dTileY == 1)
glyphRow = glyphRows[row + (half * 4) - startY + 8] << currLen;
canvasRow |= glyphRow;
endingTile |= (canvasRow & 0xFF) << (8 * row);
endingAlternativeTile |= ((canvasRow >> 8) & 0xFF) << (8 * row);
}
Tiles[tileIndex + half] = endingTile;
AlternativeTiles[tileIndex + half] = endingAlternativeTile;
}
}
}
void printLumineCharacterInSingleTiles(int *Tiles, 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 = 2;
int tileHeight = 2;
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[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[tileIndex + half] = endingTile;
}
}
}
void copyTiles(int *Tiles, int* AlternativeTiles)
{
for(int i = 0; i < 4; i++)
Tiles[i] = AlternativeTiles[i];
}
void setTilesToBlank(int *Tiles)
{
for(int i = 0; i < 4; i++)
Tiles[i] = 0;
}
void printLumineTiles(int *Tiles, unsigned short *hallAddress, int length, int currPos)
{
//Converts what is written in 1bpp in the Tiles buffer to arrangements
unsigned short *start = hallAddress + (currPos * 4);
int currHalfTile;
int value;
for(int k = 0; k < 4; k++)
{
for(int i = 0; i < 2; i++)
{
currHalfTile = (Tiles[k] >> i*16)&0xFFFF;
for(int j = 0; j < 4; j++)
{
value = (currHalfTile&3)+((currHalfTile>>6)&0xC);
start[j] = luminesquaretable[value];
currHalfTile = currHalfTile >> 2;
}
start += length;
}
}
}
void printVoidLumineTiles(unsigned short *hallAddress, int length, int currPos)
{
//Prints empty arrangements fast
unsigned short *start = hallAddress + (currPos*4);
for(int k = 0; k < 4; k++)
{
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 4; j++)
{
start[j] = luminesquaretable[0];
}
start += length;
}
}
}
int getCharWidth(byte chr)
{
//Gets the length for a character. Also handles special cases
switch(chr)
{
case END:
return 0;
case ENDL:
return ENDL_SIZE;
case BLANK:
return BLANK_SIZE;
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);
default:
return m2_widths_table[0][chr] & 0xFF;
}
}
int getPCWidth(byte* pc_ptr)
{
//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 < PC_NAME_SIZE; i++)
{
chr = *(pc_ptr+i+1);
if(chr == 0xFF)
return length;
chr = decode_character(*(pc_ptr+i));
length += m2_widths_table[0][chr] & 0xFF;
}
return length;
}

36
src/c/luminehall.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef HEADER_LUMINE_INCLUDED
#define HEADER_LUMINE_INCLUDED
#include "types.h"
#include "locs.h"
#include "vwf.h"
#define START_Y 2
#define END 0xFF
#define ENDL 0xFE
#define ENDL_SIZE 0x8
#define BLANK 0xFD
#define BLANK_SIZE 0x40
#define PC_START 0xF9
#define PC_NAME_SIZE 5
void writeLumineHallText();
int getCharWidth(byte chr);
int getPCWidth(byte* pc_ptr);
void setTilesToBlank(int *Tiles);
void printLumineTiles(int *Tiles, unsigned short *hallAddress, int length, int currPos);
void printVoidLumineTiles(unsigned short *hallAddress, int length, int currPos);
void printEmptyLumineTile(int *Tiles, unsigned short *hallAddress, int length, int currPos, int currLen);
void readLumineCharacter(byte chr, int *Tiles, unsigned short *hallAddress, int length, int *currPos, int *currLen);
void readLumineCharacterName(byte* str, int *Tiles, int* AlternativeTiles, unsigned short *hallAddress, int length, int *currPos, int *currLen);
void printLumineCharacterInMultiTiles(int *Tiles, int *AlternativeTiles, byte *glyphRows, int glyphLen, int currLen);
void printLumineCharacterInSingleTiles(int *Tiles, byte *glyphRows, int glyphLen, int currLen);
void copyTiles(int *Tiles, int* AlternativeTiles);
extern unsigned short* m2_get_hall_address();
extern int m2_hall_line_size;
extern byte luminetext[];
extern unsigned short luminesquaretable[];
#endif

Binary file not shown.

117
src/data/lumine-table.tbl Normal file
View File

@ -0,0 +1,117 @@
00=\x00
01=\x01
17=\x17
1C=\x1C
26=\x26
30=\x30
3E=\x3E
44=\x44
4A=\x4A
4C=\x4C
56=\x56
FF=\end
FE=\n
FD=\blank
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
/00

8
src/data/lumine-text.asm Normal file
View File

@ -0,0 +1,8 @@
.loadtable "data/lumine-table.tbl"
.strn "\blank"
.strn "I'm \cness....\nIt's been a long road getting here...\n"
.strn "Soon, I'll be...\nSoon, I'll be...\nSoon, I'll be...\n"
.strn "What will happen to us?\nW...what's happening?\n"
.strn "My thoughts are being written out on the wall...\nor are they?"
.str "\blank\end"

View File

@ -0,0 +1 @@
ζ¬ ¬ ͺ ¬η«© ¬«η© ͺ©©¨

View File

@ -1712,11 +1712,7 @@ nop
// Lumine Hall hacks
//==============================================================================
.org 0x82DCF94
lumine_char_tilemap:
.area 4000h,00h
.incbin "data/lumine-char-tilemap.bin"
.endarea
.org 0x800ECB2 :: bl writeLumineHallText
//==============================================================================
// Cartridge choosing screen hacks
@ -1822,6 +1818,12 @@ m2_nybbles_to_bits:
m2_enemy_attributes:
.incbin "data/m2-enemy-attributes.bin"
luminesquaretable:
.incbin "data/luminesquaretable.bin"
luminetext:
.include "data/lumine-text.asm"
flyovertextYear:
.include "data/flyover-text-year.asm"
@ -1882,6 +1884,7 @@ disclaimer_map:
.definelabel buffer_subtractor ,0x0000800
.definelabel overworld_buffer ,0x200F200
.definelabel m2_hall_line_size ,0x3000374
.definelabel m2_ness_data ,0x3001D54
.definelabel m2_ness_name ,0x3001F10
.definelabel m2_old_paula_name ,0x3001F16
@ -1911,6 +1914,7 @@ disclaimer_map:
.definelabel m2_change_naming_space ,0x8004E08
.definelabel m2_copy_name_temp_mem ,0x8004E34
.definelabel m2_insert_default_name ,0x8005708
.definelabel m2_get_hall_address ,0x800D7BC
.definelabel m12_dim_palette ,0x80137DC
.definelabel m2_enable_script ,0x80A1F6C
.definelabel m2_sub_a334c ,0x80A334C