2357 lines
79 KiB
C
2357 lines
79 KiB
C
#include "window.h"
|
|
#include "vwf.h"
|
|
#include "number-selector.h"
|
|
#include "locs.h"
|
|
#include "custom_codes.h"
|
|
|
|
byte decode_character(byte chr)
|
|
{
|
|
int c = chr - CHAR_OFFSET;
|
|
if ((c < 0) || ((c >= CHAR_END) && (c < YOUWON_START)) || (c > ARROW))
|
|
c = QUESTION_MARK;
|
|
|
|
return c;
|
|
}
|
|
|
|
byte encode_ascii(char chr)
|
|
{
|
|
return (byte)(chr + 48);
|
|
}
|
|
|
|
int get_tile_number(int x, int y)
|
|
{
|
|
x--;
|
|
y--;
|
|
return m2_coord_table[x + ((y >> 1) * 28)] + (y & 1) * 32;
|
|
}
|
|
|
|
int get_tile_number_buffer(int x, int y)
|
|
{
|
|
x--;
|
|
y--;
|
|
|
|
//Covers the alphabet-printing issues
|
|
if(y >= 0x10)
|
|
y -= 0xC;
|
|
int totalLenght = x + ((y >> 1) * 28);
|
|
int addedValue = (totalLenght >> 5) << 6;
|
|
return (totalLenght & 0x1F) + addedValue + (y & 1) * 32;
|
|
}
|
|
|
|
int get_tile_number_with_offset(int x, int y)
|
|
{
|
|
return get_tile_number(x, y) + *tile_offset;
|
|
}
|
|
|
|
int get_tile_number_with_offset_buffer(int x, int y)
|
|
{
|
|
return get_tile_number_buffer(x, y) + *tile_offset;
|
|
}
|
|
|
|
int get_tile_number_grid(int x, int y)
|
|
{
|
|
return x + (y * 32);
|
|
}
|
|
|
|
int expand_bit_depth(byte row, byte foreground)
|
|
{
|
|
foreground &= 0xF;
|
|
return m2_bits_to_nybbles[row + (foreground * 256)];
|
|
}
|
|
|
|
//The foregroundRow is given as a parameter in order to make this faster
|
|
byte reduce_bit_depth(int row, int foregroundRow)
|
|
{
|
|
row ^= foregroundRow;
|
|
|
|
int lower = m2_nybbles_to_bits[row & 0xFFFF];
|
|
int upper = m2_nybbles_to_bits[(row >> 16) & 0xFFFF];
|
|
|
|
return lower | (upper << 4);
|
|
}
|
|
|
|
//The order is swapped in order to make this faster
|
|
//Doing the bottom tile directly saves some cycles
|
|
void reduce_bit_depth_sp(int* TileRows, int* bufferValues, int* bottomBufferValues)
|
|
{
|
|
int* bottomTileRows = TileRows + (0x20 * 8);
|
|
const int andValue = 0x11111111;
|
|
|
|
//First value
|
|
unsigned int firstRow = *(TileRows++);
|
|
unsigned int secondRow = *(TileRows++);
|
|
unsigned int thirdRow = *(TileRows++);
|
|
unsigned int fourthRow = *(TileRows++);
|
|
|
|
firstRow &= andValue;
|
|
secondRow &= andValue;
|
|
thirdRow &= andValue;
|
|
fourthRow &= andValue;
|
|
|
|
unsigned int value = optimized_byte_4bpp_to_1bpp_table[(fourthRow >> 0xF) + (fourthRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(thirdRow >> 0xF) + (thirdRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(secondRow >> 0xF) + (secondRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(firstRow >> 0xF) + (firstRow & 0xFFFF)];
|
|
*(bufferValues++) = value;
|
|
|
|
//Second value
|
|
firstRow = *(TileRows++);
|
|
secondRow = *(TileRows++);
|
|
thirdRow = *(TileRows++);
|
|
fourthRow = *(TileRows);
|
|
|
|
firstRow &= andValue;
|
|
secondRow &= andValue;
|
|
thirdRow &= andValue;
|
|
fourthRow &= andValue;
|
|
|
|
value = optimized_byte_4bpp_to_1bpp_table[(fourthRow >> 0xF) + (fourthRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(thirdRow >> 0xF) + (thirdRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(secondRow >> 0xF) + (secondRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(firstRow >> 0xF) + (firstRow & 0xFFFF)];
|
|
*(bufferValues) = value;
|
|
|
|
//First value of bottom tile
|
|
firstRow = *(bottomTileRows++);
|
|
secondRow = *(bottomTileRows++);
|
|
thirdRow = *(bottomTileRows++);
|
|
fourthRow = *(bottomTileRows++);
|
|
|
|
firstRow &= andValue;
|
|
secondRow &= andValue;
|
|
thirdRow &= andValue;
|
|
fourthRow &= andValue;
|
|
|
|
value = optimized_byte_4bpp_to_1bpp_table[(fourthRow >> 0xF) + (fourthRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(thirdRow >> 0xF) + (thirdRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(secondRow >> 0xF) + (secondRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(firstRow >> 0xF) + (firstRow & 0xFFFF)];
|
|
*(bottomBufferValues++) = value;
|
|
|
|
//Second value of bottom tile - Is not used by the game
|
|
/*
|
|
firstRow = *(bottomTileRows++);
|
|
secondRow = *(bottomTileRows++);
|
|
thirdRow = *(bottomTileRows++);
|
|
fourthRow = *(bottomTileRows);
|
|
|
|
firstRow &= andValue;
|
|
secondRow &= andValue;
|
|
thirdRow &= andValue;
|
|
fourthRow &= andValue;
|
|
|
|
value = optimized_byte_4bpp_to_1bpp_table[(fourthRow >> 0xF) + (fourthRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(thirdRow >> 0xF) + (thirdRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(secondRow >> 0xF) + (secondRow & 0xFFFF)];
|
|
value <<= 8;
|
|
value |= optimized_byte_4bpp_to_1bpp_table[(firstRow >> 0xF) + (firstRow & 0xFFFF)];
|
|
*(bottomBufferValues) = value;
|
|
*/
|
|
}
|
|
|
|
byte getSex(byte character)
|
|
{
|
|
return character == 1 ? 1 : 0; //character 1 is Paula
|
|
}
|
|
|
|
void getPossessive(byte character, byte *str, int *index)
|
|
{
|
|
char his[] = "his";
|
|
char her[] = "her";
|
|
if(getSex(character) == 1)
|
|
for (int i = 0; i < (sizeof(her) - 1); i++)
|
|
str[(*index)++] = encode_ascii(her[i]);
|
|
else
|
|
for (int i = 0; i < (sizeof(his) - 1); i++)
|
|
str[(*index)++] = encode_ascii(his[i]);
|
|
}
|
|
|
|
void getPronoun(byte character, byte *str, int *index)
|
|
{
|
|
char he[] = "he";
|
|
char she[] = "she";
|
|
if(getSex(character) == 1)
|
|
for (int i = 0; i < (sizeof(she) - 1); i++)
|
|
str[(*index)++] = encode_ascii(she[i]);
|
|
else
|
|
for (int i = 0; i < (sizeof(he) - 1); i++)
|
|
str[(*index)++] = encode_ascii(he[i]);
|
|
}
|
|
|
|
void getCharName(byte character, byte *str, int *index)
|
|
{
|
|
copy_name(str, m2_ness_name, index, character * 7);
|
|
}
|
|
|
|
void copy_name(byte *str, byte *source, int *index, int pos)
|
|
{
|
|
while(source[pos + 1] != 0xFF)
|
|
str[(*index)++] = source[pos++];
|
|
}
|
|
|
|
int ascii_strlen(char *str)
|
|
{
|
|
int len = 0;
|
|
while (str[len] != 0)
|
|
len++;
|
|
return len;
|
|
}
|
|
|
|
int wrapper_count_pixels_to_tiles(byte *str, int length)
|
|
{
|
|
return count_pixels_to_tiles(str, length, 0);
|
|
}
|
|
|
|
int count_pixels_to_tiles(byte *str, int length, int startingPos)
|
|
{
|
|
int pixels = startingPos;
|
|
for(int i = 0; i < length; i++)
|
|
{
|
|
if((str[i] != 0xFF) && (str[i] != 0xFE)) //The latter one is not really needed
|
|
pixels += (m2_widths_table[0][decode_character(str[i])] & 0xFF);
|
|
else if(str[i] == 0xFE)
|
|
{
|
|
// Define 0xFE as a control code
|
|
byte cmd = str[++i];
|
|
switch (cmd)
|
|
{
|
|
case CUSTOMCC_ADD_X:
|
|
pixels += str[++i];
|
|
break;
|
|
|
|
case CUSTOMCC_SET_X:
|
|
pixels = str[++i];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
int tiles = (pixels - startingPos)>> 3;
|
|
if((pixels & 7) != 0)
|
|
tiles +=1;
|
|
return tiles;
|
|
}
|
|
|
|
//For strings without any control code besides the 00 FF one
|
|
int count_pixels_to_tiles_normal_string(byte *str, int startingPos)
|
|
{
|
|
int pixels = startingPos;
|
|
for(int i = 0;; i++)
|
|
{
|
|
if((str[i + 1] != 0xFF)) //The latter one is not really needed
|
|
pixels += (m2_widths_table[0][decode_character(str[i])] & 0xFF);
|
|
else
|
|
break;
|
|
}
|
|
int tiles = (pixels - startingPos)>> 3;
|
|
if(((pixels - startingPos) & 7) != 0)
|
|
tiles +=1;
|
|
return tiles;
|
|
}
|
|
|
|
byte print_character(byte chr, int x, int y)
|
|
{
|
|
return print_character_formatted(chr, x, y, 0, 0xF);
|
|
}
|
|
|
|
byte print_character_formatted(byte chr, int x, int y, int font, int foreground)
|
|
{
|
|
// 0x64 to 0x6C (inclusive) is YOU WON
|
|
if ((chr >= YOUWON_START) && (chr <= YOUWON_END))
|
|
{
|
|
print_special_character(chr + 0xF0, x, y);
|
|
return 8;
|
|
}
|
|
|
|
// 0x6D is an arrow ->
|
|
else if (chr == ARROW)
|
|
{
|
|
print_special_character(ARROW + 0x30, x, y);
|
|
return 8;
|
|
}
|
|
|
|
return print_character_with_callback(chr, x, y, font, foreground, vram, &get_tile_number_with_offset, *tilemap_pointer, 32, 0xC);
|
|
}
|
|
|
|
byte print_character_to_ram(byte chr, int *dest, int xOffset, int font, int foreground)
|
|
{
|
|
return print_character_with_callback(chr, xOffset, 0, font, foreground, dest, &get_tile_number_grid, NULL, 32, 0x10);
|
|
}
|
|
|
|
// Prints a special tile. Pixels are copied to the VWF buffer.
|
|
// x, y in pixels
|
|
void print_special_character(int tile, int x, int y)
|
|
{
|
|
// Special graphics must be tile-aligned
|
|
x >>= 3;
|
|
y >>= 3;
|
|
unsigned short sourceTileIndex = tile + *tile_offset;
|
|
unsigned short destTileIndex = get_tile_number(x, y) + *tile_offset;
|
|
|
|
(*tilemap_pointer)[x + (y * 32)] = destTileIndex | *palette_mask;
|
|
(*tilemap_pointer)[x + ((y + 1) * 32)] = (destTileIndex + 32) | *palette_mask;
|
|
|
|
cpufastset(&vram[sourceTileIndex * 8], &vram[destTileIndex * 8], 8);
|
|
cpufastset(&vram[(sourceTileIndex + 32) * 8], &vram[(destTileIndex + 32) * 8], 8);
|
|
}
|
|
|
|
// Prints a special tile. Pixels are not copied.
|
|
// x, y in pixels
|
|
void print_special_character_buffer(int tile, int x, int y)
|
|
{
|
|
// Special graphics must be tile-aligned
|
|
x >>= 3;
|
|
y >>= 3;
|
|
unsigned short sourceTileIndex = tile + *tile_offset;
|
|
|
|
(*tilemap_pointer)[x + (y * 32)] = sourceTileIndex | *palette_mask;
|
|
(*tilemap_pointer)[x + ((y + 1) * 32)] = (sourceTileIndex + 32) | *palette_mask;
|
|
|
|
}
|
|
|
|
// Maps a special character to the given tile coordinates. Only the tilemap is changed.
|
|
// x, y in tiles
|
|
void map_special_character(unsigned short tile, int x, int y)
|
|
{
|
|
tile = format_tile(tile, false, false);
|
|
(*tilemap_pointer)[x + (y * 32)] = tile;
|
|
(*tilemap_pointer)[x + ((y + 1) * 32)] = tile + 32;
|
|
}
|
|
|
|
// Maps a tile to the given tile coordinates. Only the tilemap is changed.
|
|
// x, y in tiles
|
|
void map_tile(unsigned short tile, int x, int y)
|
|
{
|
|
tile = format_tile(tile, false, false);
|
|
(*tilemap_pointer)[x + (y * 32)] = tile;
|
|
}
|
|
|
|
byte print_character_with_callback(byte chr, int x, int y, int font, int foreground,
|
|
int *dest, int (*getTileCallback)(int, int), unsigned short *tilemapPtr, int tilemapWidth, byte doubleTileHeight)
|
|
{
|
|
int tileWidth = m2_font_widths[font];
|
|
int tileHeight = m2_font_heights[font];
|
|
int widths = m2_widths_table[font][chr];
|
|
|
|
int paletteMask = *palette_mask;
|
|
byte *glyphRows = &m2_font_table[font][chr * tileWidth * tileHeight * 8];
|
|
|
|
int virtualWidth = widths & 0xFF;
|
|
int leftPortionWidth = 8 - (x & 7);
|
|
|
|
int tileX = x >> 3;
|
|
int tileY = y >> 3;
|
|
|
|
int offsetY = y & 7;
|
|
|
|
if((tileY & 1) == 0 && offsetY >= doubleTileHeight - 0x8)
|
|
{
|
|
tileY++;
|
|
offsetY -= (doubleTileHeight - 0x8);
|
|
}
|
|
|
|
int nextY = offsetY;
|
|
for (int dTileY = 0; dTileY < tileHeight; dTileY++) // dest tile Y
|
|
{
|
|
int dTileX = 0;
|
|
int renderedWidth = widths >> 8;
|
|
offsetY = nextY;
|
|
bool changed = false;
|
|
|
|
while (renderedWidth > 0)
|
|
{
|
|
// Glue the leftmost part of the glyph onto the rightmost part of the canvas
|
|
int tileIndex = getTileCallback(tileX + dTileX, tileY + dTileY); //get_tile_number(tileX + dTileX, tileY + dTileY) + tileOffset;
|
|
bool availableSwap = (dTileY != (tileHeight - 1));
|
|
int realTileIndex = tileIndex;
|
|
bool useful = false; //Maybe we go over the maximum tile height, let's make sure the extra tile is properly set IF it's useful
|
|
int tmpTileY = dTileY;
|
|
int limit = ((tmpTileY + tileY) & 1) == 0 ? doubleTileHeight - 8 - 1: 7;
|
|
int sumRemoved = 0;
|
|
|
|
for (int row = 0; row < 8; row++)
|
|
{
|
|
int canvasRow = dest[(realTileIndex * 8) + ((row + offsetY - sumRemoved) & 7)];
|
|
byte glyphRow = glyphRows[row + (dTileY * 8 * tileWidth) + (dTileX * 8)] & ((1 << leftPortionWidth) - 1);
|
|
glyphRow <<= (8 - leftPortionWidth);
|
|
|
|
int expandedGlyphRow = expand_bit_depth(glyphRow, foreground);
|
|
int expandedGlyphRowMask = ~expand_bit_depth(glyphRow, 0xF);
|
|
int tmpCanvasRow = canvasRow;
|
|
canvasRow &= expandedGlyphRowMask;
|
|
canvasRow |= expandedGlyphRow;
|
|
|
|
if(!availableSwap && ((row + offsetY) >> 3) == 1 && canvasRow != tmpCanvasRow) //This changed the canvas, then it's useful... IF it's the extra vertical tile
|
|
useful = true;
|
|
|
|
dest[(realTileIndex * 8) + ((row + offsetY - sumRemoved) & 7)] = canvasRow;
|
|
|
|
if((row + offsetY - sumRemoved) == limit)
|
|
{
|
|
realTileIndex = getTileCallback(tileX + dTileX, tileY + tmpTileY + 1);
|
|
tmpTileY++;
|
|
sumRemoved += limit + 1;
|
|
if(!changed)
|
|
{
|
|
nextY = (nextY + limit + 1) & 7;
|
|
changed = true;
|
|
}
|
|
limit = ((tmpTileY + tileY) & 1) == 0 ? doubleTileHeight - 8 - 1: 7;
|
|
|
|
}
|
|
}
|
|
|
|
if (tilemapPtr != NULL)
|
|
{
|
|
tilemapPtr[tileX + dTileX + ((tileY + dTileY) * tilemapWidth)] = paletteMask | tileIndex;
|
|
if(useful)
|
|
tilemapPtr[tileX + dTileX + ((tileY + dTileY + 1) * tilemapWidth)] = paletteMask | realTileIndex;
|
|
}
|
|
|
|
if (renderedWidth - leftPortionWidth > 0 && leftPortionWidth < 8)
|
|
{
|
|
// Glue the rightmost part of the glyph onto the leftmost part of the next tile
|
|
// on the canvas
|
|
tileIndex = getTileCallback(tileX + dTileX + 1, tileY + dTileY); //get_tile_number(tileX + dTileX + 1, tileY + dTileY) + tileOffset;
|
|
availableSwap = (dTileY != (tileHeight - 1));
|
|
realTileIndex = tileIndex;
|
|
useful = false; //Maybe we go over the maximum tile height, let's make sure the extra tile is properly set IF it's useful
|
|
tmpTileY = dTileY;
|
|
limit = ((tmpTileY + tileY) & 1) == 0 ? doubleTileHeight - 8 - 1: 7;
|
|
sumRemoved = 0;
|
|
|
|
for (int row = 0; row < 8; row++)
|
|
{
|
|
int canvasRow = dest[(realTileIndex * 8) + ((row + offsetY - sumRemoved) & 7)];
|
|
byte glyphRow = glyphRows[row + (dTileY * 8 * tileWidth) + (dTileX * 8)] >> leftPortionWidth;
|
|
|
|
int expandedGlyphRow = expand_bit_depth(glyphRow, foreground);
|
|
int expandedGlyphRowMask = ~expand_bit_depth(glyphRow, 0xF);
|
|
int tmpCanvasRow = canvasRow;
|
|
canvasRow &= expandedGlyphRowMask;
|
|
canvasRow |= expandedGlyphRow;
|
|
|
|
if(!availableSwap && ((row + offsetY) >> 3) == 1 && canvasRow != tmpCanvasRow) //This changed the canvas, then it's useful... IF it's the extra vertical tile
|
|
useful = true;
|
|
|
|
dest[(realTileIndex * 8) + ((row + offsetY - sumRemoved) & 7)] = canvasRow;
|
|
|
|
if((row + offsetY - sumRemoved) == limit)
|
|
{
|
|
realTileIndex = getTileCallback(tileX + 1 + dTileX, tileY + tmpTileY + 1);
|
|
tmpTileY++;
|
|
sumRemoved += limit + 1;
|
|
if(!changed)
|
|
{
|
|
nextY = (nextY + limit + 1) & 7;
|
|
changed = true;
|
|
}
|
|
limit = ((tmpTileY + tileY) & 1) == 0 ? doubleTileHeight - 8 - 1: 7;
|
|
}
|
|
}
|
|
|
|
if (tilemapPtr != NULL)
|
|
{
|
|
tilemapPtr[tileX + dTileX + 1 + ((tileY + dTileY) * tilemapWidth)] = paletteMask | tileIndex ;
|
|
if(useful)
|
|
tilemapPtr[tileX + dTileX + 1 + ((tileY + dTileY + 1) * tilemapWidth)] = paletteMask | realTileIndex;
|
|
}
|
|
}
|
|
|
|
renderedWidth -= 8;
|
|
dTileX++;
|
|
}
|
|
}
|
|
|
|
return virtualWidth;
|
|
}
|
|
|
|
int convert_tile_address_buffer(int tile)
|
|
{
|
|
//Allows using tiles with different size to make the buffer smaller
|
|
tile -= *tile_offset;
|
|
int inner_line = tile & 0x3F;
|
|
int lines = (tile >> 6) << 5;
|
|
int returned_address = ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER) + (lines * DEFAULT_DOUBLE_TILE_HEIGHT);
|
|
|
|
if(inner_line >= 0x20)
|
|
return returned_address + (0x20 * 8) + ((inner_line & 0x1F) * (DEFAULT_DOUBLE_TILE_HEIGHT - 8));
|
|
return returned_address + (inner_line * 8);
|
|
}
|
|
|
|
byte print_character_with_callback_1bpp_buffer(byte chr, int x, int y, byte *dest, int (*getTileCallback)(int, int), int font,
|
|
unsigned short *tilemapPtr, int tilemapWidth, byte doubleTileHeight)
|
|
{
|
|
int tileWidth = m2_font_widths[font];
|
|
int tileHeight = m2_font_heights[font];
|
|
int widths = m2_widths_table[font][chr];
|
|
|
|
int paletteMask = *palette_mask;
|
|
byte *glyphRows = &m2_font_table[font][chr * tileWidth * tileHeight * 8];
|
|
|
|
int virtualWidth = widths & 0xFF;
|
|
|
|
int tileX = x >> 3;
|
|
int tileY = y >> 3;
|
|
|
|
int offsetY = y & 7;
|
|
int offsetX = x & 7;
|
|
|
|
if((tileY & 1) == 0 && offsetY >= doubleTileHeight - 0x8)
|
|
{
|
|
tileY++;
|
|
offsetY -= (doubleTileHeight - 0x8);
|
|
}
|
|
|
|
int nextY = offsetY;
|
|
for (int dTileY = 0; dTileY < tileHeight; dTileY++) // dest tile Y
|
|
{
|
|
int dTileX = 0;
|
|
int renderedWidth = widths >> 8;
|
|
offsetY = nextY;
|
|
bool changed = false;
|
|
|
|
while (renderedWidth > 0)
|
|
{
|
|
// Glue the leftmost part of the glyph onto the rightmost part of the canvas
|
|
int tileIndex = get_tile_number_with_offset_buffer(tileX + dTileX, tileY + dTileY);
|
|
int tileIndexRight = get_tile_number_with_offset_buffer(tileX + dTileX + 1, tileY + dTileY);
|
|
bool availableSwap = (dTileY != (tileHeight - 1));
|
|
int realTileIndex = tileIndex;
|
|
int realTileIndexRight = tileIndexRight;
|
|
bool useful = false; //Maybe we go over the maximum tile height, let's make sure the extra tile is properly set IF it's useful
|
|
int tmpTileY = dTileY;
|
|
int limit = ((tmpTileY + tileY) & 1) == 0 ? doubleTileHeight - 8 - 1: 7;
|
|
int sumRemoved = 0;
|
|
|
|
for (int row = 0; row < 8; row++)
|
|
{
|
|
unsigned short canvasRow = dest[convert_tile_address_buffer(realTileIndex) + ((row + offsetY - sumRemoved) & 7)] + (dest[convert_tile_address_buffer(realTileIndexRight) + ((row + offsetY - sumRemoved) & 7)] << 8);
|
|
unsigned short glyphRow = glyphRows[row + (dTileY * 8 * tileWidth) + (dTileX * 8)] << offsetX;
|
|
|
|
unsigned short tmpCanvasRow = canvasRow;
|
|
canvasRow |= glyphRow;
|
|
|
|
if(!availableSwap && ((row + offsetY) >> 3) == 1 && canvasRow != tmpCanvasRow) //This changed the canvas, then it's useful... IF it's the extra vertical tile
|
|
useful = true;
|
|
|
|
dest[convert_tile_address_buffer(realTileIndex) + ((row + offsetY - sumRemoved) & 7)] = canvasRow;
|
|
dest[convert_tile_address_buffer(realTileIndexRight) + ((row + offsetY - sumRemoved) & 7)] = canvasRow >> 8;
|
|
|
|
if((row + offsetY - sumRemoved) == limit)
|
|
{
|
|
tmpTileY++;
|
|
realTileIndex = get_tile_number_with_offset_buffer(tileX + dTileX, tileY + tmpTileY);
|
|
realTileIndexRight = get_tile_number_with_offset_buffer(tileX + 1 + dTileX, tileY + tmpTileY);
|
|
sumRemoved += limit + 1;
|
|
if(!changed)
|
|
{
|
|
nextY = (nextY + limit + 1) & 7;
|
|
changed = true;
|
|
}
|
|
limit = ((tmpTileY + tileY) & 1) == 0 ? doubleTileHeight - 8 - 1: 7;
|
|
|
|
}
|
|
}
|
|
|
|
if (tilemapPtr != NULL)
|
|
{
|
|
tilemapPtr[tileX + dTileX + ((tileY + dTileY) * tilemapWidth)] = paletteMask | getTileCallback(tileX + dTileX, tileY + dTileY);
|
|
if(renderedWidth - 8 + offsetX > 0 && offsetX != 0)
|
|
tilemapPtr[tileX + dTileX + 1 + ((tileY + dTileY) * tilemapWidth)] = paletteMask | getTileCallback(tileX + dTileX + 1, tileY + dTileY);
|
|
if(useful)
|
|
{
|
|
tilemapPtr[tileX + dTileX + ((tileY + tmpTileY) * tilemapWidth)] = paletteMask | getTileCallback(tileX + dTileX, tileY + tmpTileY);
|
|
if(renderedWidth - 8 + offsetX > 0 && offsetX != 0)
|
|
tilemapPtr[tileX + dTileX + 1 + ((tileY + tmpTileY) * tilemapWidth)] = paletteMask | getTileCallback(tileX + dTileX + 1, tileY + tmpTileY);
|
|
}
|
|
}
|
|
renderedWidth -= 8;
|
|
dTileX++;
|
|
}
|
|
}
|
|
|
|
return virtualWidth;
|
|
}
|
|
|
|
int print_window_header_string(int *dest, byte *str, int x, int y)
|
|
{
|
|
int pixelX = x & 7;
|
|
int *destOffset = dest + ((x & ~7) + (y * 32));
|
|
|
|
for (;;)
|
|
{
|
|
byte code = *(str + 1);
|
|
if (code == 0xFF)
|
|
{
|
|
if (*str == 0)
|
|
break;
|
|
|
|
str += 2;
|
|
continue;
|
|
}
|
|
|
|
pixelX += print_character_to_ram(decode_character(*str++), destOffset, pixelX, 4, 0xF);
|
|
}
|
|
|
|
return pixelX - (x & 7);
|
|
}
|
|
|
|
void clear_window_header(int *dest, int length, int x, int y)
|
|
{
|
|
dest += (x + (y * 32)) * 8;
|
|
clear_rect_ram(dest, length, WINDOW_HEADER_BG);
|
|
}
|
|
|
|
//Prints the number header string in a tiny buffer and stores it in one go
|
|
int print_window_number_header_string(int *dest, byte *str, int x, int y)
|
|
{
|
|
int pixelX = x & 7;
|
|
int *destOffset = dest + ((x & ~7) + (y * 32));
|
|
int buffer[8 * 3];
|
|
|
|
for(int i = 0; i < 8 * 3; i++)
|
|
buffer[i] = 0x33333333;
|
|
|
|
for (;;)
|
|
{
|
|
byte code = *(str + 1);
|
|
if (code == 0xFF)
|
|
{
|
|
if (*str == 0)
|
|
break;
|
|
|
|
str += 2;
|
|
continue;
|
|
}
|
|
|
|
pixelX += print_character_to_ram(decode_character(*str++), buffer, pixelX, 4, 0xF);
|
|
}
|
|
|
|
for(int i = 0; i < 8 * 3; i++)
|
|
destOffset[i] = buffer[i];
|
|
|
|
return pixelX - (x & 7);
|
|
}
|
|
|
|
unsigned short* print_equip_header(int type, unsigned short *tilemap, unsigned int *dest, WINDOW *window)
|
|
{
|
|
byte *str = 0;
|
|
|
|
switch (type)
|
|
{
|
|
case 3:
|
|
str = m12_other_str5; // Weapon
|
|
break;
|
|
case 4:
|
|
str = m12_other_str6; // Body
|
|
break;
|
|
case 5:
|
|
str = m12_other_str7; // Arms
|
|
break;
|
|
case 6:
|
|
str = m12_other_str8; // Other
|
|
break;
|
|
}
|
|
|
|
if (str != 0)
|
|
{
|
|
int startX = WINDOW_HEADER_X * 8;
|
|
int startY = WINDOW_HEADER_Y * 8;
|
|
int width = 0;
|
|
|
|
width += print_window_header_string(dest, str, startX + width, startY);
|
|
|
|
// Print (X)
|
|
if (window->cursor_x > 6)
|
|
{
|
|
int buffer[8 * 3];
|
|
int mask = WINDOW_HEADER_BG;
|
|
for(int i = 0; i < (width & 7); i++) //Saves only the important pixels and deletes the rest in the buffer
|
|
mask = (mask << 4) | 0xF;
|
|
int *destOffset = dest + (((startX + width) & ~7) + (startY * 32));
|
|
|
|
for(int i = 0; i < 8; i++)
|
|
buffer[i] = destOffset[i] & mask;
|
|
for(int i = 0; i < 8 * 2; i++)
|
|
buffer[8 + i] = WINDOW_HEADER_BG;
|
|
int base = window->cursor_x_base;
|
|
str = m2_strlookup(m2_misc_offsets, m2_misc_strings, base + 0x8C);
|
|
width += print_window_header_string(buffer, str, width & 7, 0);
|
|
for(int i = 0; i < 8 * 3; i++) //Restore the vram
|
|
destOffset[i] = buffer[i];
|
|
}
|
|
|
|
// Update tilemap
|
|
int tiles = (width + 7) >> 3;
|
|
int tileIndex = WINDOW_HEADER_TILE + *tile_offset;
|
|
|
|
for (int i = 0; i < tiles; i++)
|
|
{
|
|
*tilemap++ = tileIndex++ | *palette_mask;
|
|
}
|
|
}
|
|
|
|
return tilemap;
|
|
}
|
|
|
|
// Returns a formatted tile value including the palette index, flip flags and
|
|
// tile offset.
|
|
unsigned short format_tile(unsigned short tile, bool flip_x, bool flip_y)
|
|
{
|
|
tile += *tile_offset;
|
|
tile |= *palette_mask;
|
|
|
|
if (flip_x)
|
|
{
|
|
tile |= (1 << 10);
|
|
}
|
|
|
|
if (flip_y)
|
|
{
|
|
tile |= (1 << 11);
|
|
}
|
|
|
|
return tile;
|
|
}
|
|
|
|
// Copy party character name to window header
|
|
// Assumes that the party character names have already been rendered
|
|
// to VRAM; this just copies the map data
|
|
void copy_name_header(WINDOW *window, int character_index)
|
|
{
|
|
// Coordinates of the name tiles
|
|
int x = window->window_x + 1;
|
|
int y = window->window_y - 1;
|
|
|
|
// Print the partial border tile before the name
|
|
(*tilemap_pointer)[x - 1 + (y * 32)] = format_tile(0xB3, false, false);
|
|
|
|
// Get name width in pixels
|
|
byte *name_str = pc_names + (character_index * 7);
|
|
unsigned short *widths_table = m2_widths_table[4]; // small font
|
|
int width = 0;
|
|
|
|
while (*(name_str + 1) != 0xFF)
|
|
{
|
|
width += widths_table[decode_character(*name_str)] & 0xFF;
|
|
name_str++;
|
|
}
|
|
|
|
// Print name
|
|
int num_tiles = (width + 7) >> 3;
|
|
int tile = name_header_tiles[character_index];
|
|
|
|
for (int i = 0; i < num_tiles; i++)
|
|
{
|
|
(*tilemap_pointer)[x + i + (y * 32)] = format_tile(tile, false, false);
|
|
tile++;
|
|
}
|
|
|
|
// Print flipped partial border tile after name
|
|
(*tilemap_pointer)[x + num_tiles + (y * 32)] = format_tile(0xB3, true, false);
|
|
}
|
|
|
|
// Clears a window's name header by printing border tiles in the slots for the
|
|
// name, plus one tile on either side for the partial borders
|
|
void clear_name_header(WINDOW* window)
|
|
{
|
|
// We don't need to know how long the name is; just make a conservative
|
|
// estimate that it couldn't have been more than 4 tiles wide
|
|
|
|
int x = window->window_x; // start of partial border tile
|
|
int y = window->window_y - 1;
|
|
int tile = format_tile(0x96, false, true);
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
(*tilemap_pointer)[x + (y * 32)] = tile;
|
|
x++;
|
|
}
|
|
}
|
|
|
|
// Draws the arrow tiles on a window
|
|
// The big flag controls what size to use
|
|
void draw_window_arrows(WINDOW *window, bool big)
|
|
{
|
|
int x = window->window_x + window->window_width - 3;
|
|
int y = window->window_y - 1;
|
|
unsigned short tile = format_tile(big ? 0x9B : 0xBB, false, false);
|
|
(*tilemap_pointer)[x + (y * 32)] = tile;
|
|
(*tilemap_pointer)[x + 1 + (y * 32)] = tile + 1;
|
|
}
|
|
|
|
// Replaces window arrow tiles with regular border tiles
|
|
void clear_window_arrows(WINDOW *window)
|
|
{
|
|
int x = window->window_x + window->window_width - 3;
|
|
int y = window->window_y - 1;
|
|
unsigned short tile = format_tile(0x96, false, true);
|
|
(*tilemap_pointer)[x + (y * 32)] = tile;
|
|
(*tilemap_pointer)[x + 1 + (y * 32)] = tile;
|
|
}
|
|
|
|
void weld_entry(WINDOW *window, byte *str)
|
|
{
|
|
weld_entry_custom(window, str, 0, 0xF);
|
|
}
|
|
|
|
int weld_entry_saturn(WINDOW *window, byte *str)
|
|
{
|
|
weld_entry_custom(window, str, 1, 0xF);
|
|
|
|
// TODO: figure out when the original routine at 80ED770 might return non-zero
|
|
// Looking at 80CA3A4, maybe 1 is returned if a non-saturn glyph is encountered?
|
|
// And looking at 80D2F24, that seems to be the case...
|
|
return 0;
|
|
}
|
|
|
|
void weld_entry_custom(WINDOW *window, byte *str, int font, int foreground)
|
|
{
|
|
int chr = decode_character(*str);
|
|
|
|
int x = window->pixel_x + (window->window_x + window->text_x) * 8;
|
|
int y = (window->window_y + window->text_y) * 8;
|
|
|
|
if(!window->inside_width_calc)
|
|
x += print_character_formatted(chr, x, y, font, foreground);
|
|
else
|
|
x += (m2_widths_table[font][chr] & 0xFF);
|
|
|
|
window->pixel_x = x & 7;
|
|
window->text_x = (x >> 3) - window->window_x;
|
|
if(window->inside_width_calc && window->text_x >= window->window_width)
|
|
window->text_x = window->window_width;
|
|
}
|
|
|
|
// Returns: ____XXXX = number of characters printed
|
|
// XXXX____ = number of pixels printed
|
|
// x, y: pixels
|
|
int print_string(byte *str, int x, int y)
|
|
{
|
|
if (str == NULL)
|
|
return 0;
|
|
|
|
byte chr;
|
|
int initial_x = x;
|
|
int charCount = 0;
|
|
|
|
while (str[1] != 0xFF)
|
|
{
|
|
x += print_character(decode_character(*str++), x, y);
|
|
charCount++;
|
|
}
|
|
|
|
int totalWidth = x - initial_x;
|
|
|
|
return (charCount & 0xFFFF) | (totalWidth << 16);
|
|
}
|
|
|
|
// Edited version which recognizes the 5F FF code
|
|
// Returns: ____XXXX = number of characters printed
|
|
// XXXX____ = number of pixels printed
|
|
// x, y: pixels
|
|
int print_string_edited(byte *str, int x, int y)
|
|
{
|
|
if (str == NULL)
|
|
return 0;
|
|
|
|
byte chr;
|
|
int initial_x = x;
|
|
int charCount = 0;
|
|
|
|
while (!(str[1] == 0xFF && str[0] == 0x00))
|
|
{
|
|
if(str[1] != 0xFF)
|
|
{
|
|
x += print_character(decode_character(*str++), x, y);
|
|
charCount++;
|
|
}
|
|
else if(str[0] == 0x5F)
|
|
{
|
|
x = initial_x + str[2];
|
|
str += 3;
|
|
}
|
|
}
|
|
|
|
int totalWidth = x - initial_x;
|
|
|
|
return (charCount & 0xFFFF) | (totalWidth << 16);
|
|
}
|
|
|
|
unsigned short printstr_hlight_edited(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight)
|
|
{
|
|
return printstr_hlight_pixels_edited(window, str, x << 3, y << 4, highlight);
|
|
}
|
|
|
|
unsigned short printstr_hlight_pixels_edited(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight)
|
|
{
|
|
unsigned short printX = x + ((window->window_x) << 3);
|
|
unsigned short printY = y + ((window->window_y) << 3);
|
|
unsigned short tmpPaletteMsk = (*palette_mask);
|
|
unsigned short palette_mask_highlight = tmpPaletteMsk;
|
|
if(highlight)
|
|
palette_mask_highlight += 0x1000;
|
|
(*palette_mask) = palette_mask_highlight;
|
|
|
|
unsigned short printed_Characters = print_string_edited(str, printX, printY);
|
|
|
|
(*palette_mask) = tmpPaletteMsk;
|
|
|
|
return printed_Characters;
|
|
}
|
|
|
|
int print_menu_string(WINDOW* window)
|
|
{
|
|
byte *menu_text = window->menu_text;
|
|
if (menu_text == NULL)
|
|
return 0;
|
|
|
|
int x = window->window_x << 3;
|
|
int y = (window->window_y + window->text_y) << 3;
|
|
|
|
byte chr;
|
|
int initial_x = x;
|
|
int charCount = 0;
|
|
bool looping = true;
|
|
int set_count = 0;
|
|
byte first_set_value = 0;
|
|
|
|
while (looping)
|
|
{
|
|
if (menu_text[1] == 0xFF)
|
|
{
|
|
switch (menu_text[0])
|
|
{
|
|
case CUSTOMCC_SET_X:
|
|
{
|
|
byte set_value = menu_text[2];
|
|
x = set_value + initial_x;
|
|
menu_text += 3;
|
|
|
|
set_count++;
|
|
if (set_count == 1)
|
|
{
|
|
first_set_value = set_value;
|
|
}
|
|
else if (set_count == 2)
|
|
{
|
|
// If we're calling SET the second time, update the
|
|
// window cursor delta to be the difference between
|
|
// the two set values
|
|
window->cursor_x_delta = (set_value - first_set_value) >> 3;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case CUSTOMCC_ADD_X:
|
|
x += menu_text[2];
|
|
menu_text += 3;
|
|
break;
|
|
default:
|
|
looping = false;
|
|
window->menu_text = NULL; //Otherwise it will keep printing indefinetly
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
x += print_character(decode_character(*menu_text++), x, y);
|
|
charCount++;
|
|
}
|
|
}
|
|
|
|
window->text_x = 0;
|
|
window->pixel_x = 0;
|
|
|
|
int totalWidth = x - initial_x;
|
|
|
|
return (charCount & 0xFFFF) | (totalWidth << 16);
|
|
}
|
|
|
|
// x,y: tile coordinates
|
|
void clear_tile(int x, int y, int pixels)
|
|
{
|
|
// Clear pixels
|
|
int tileIndex = get_tile_number(x, y) + *tile_offset;
|
|
cpufastset(&pixels, &vram[tileIndex * 8], CPUFASTSET_FILL | 8);
|
|
|
|
// Reset the tilemap (e.g. get rid of equip or SMAAAASH!! tiles)
|
|
(*tilemap_pointer)[x + (y * 32)] = tileIndex | *palette_mask;
|
|
}
|
|
|
|
// x,y: tile coordinates
|
|
void clear_rect(int x, int y, int width, int height, int pixels)
|
|
{
|
|
for (int tileY = 0; tileY < height; tileY++)
|
|
{
|
|
for (int tileX = 0; tileX < width; tileX++)
|
|
{
|
|
clear_tile(x + tileX, y + tileY, pixels);
|
|
}
|
|
}
|
|
}
|
|
|
|
void clear_rect_ram(int *dest, int tileCount, int pixels)
|
|
{
|
|
cpufastset(&pixels, dest, CPUFASTSET_FILL | (tileCount * 8));
|
|
}
|
|
|
|
void clear_window(WINDOW *window)
|
|
{
|
|
clear_rect(window->window_x, window->window_y,
|
|
window->window_width, window->window_height,
|
|
WINDOW_AREA_BG);
|
|
}
|
|
|
|
// x, y, width: tile coordinates
|
|
void print_blankstr(int x, int y, int width)
|
|
{
|
|
clear_rect(x, y, width, 2, WINDOW_AREA_BG);
|
|
}
|
|
|
|
// x, y, width: tile coordinates
|
|
void print_blankstr_window(int x, int y, int width, WINDOW* window)
|
|
{
|
|
print_blankstr(x + window->window_x, y + window->window_y, width);
|
|
}
|
|
|
|
// x,y: tile coordinates
|
|
void copy_tile(int xSource, int ySource, int xDest, int yDest)
|
|
{
|
|
int sourceTileIndex = get_tile_number(xSource, ySource) + *tile_offset;
|
|
int destTileIndex = get_tile_number(xDest, yDest) + *tile_offset;
|
|
cpufastset(&vram[sourceTileIndex * 8], &vram[destTileIndex * 8], 8);
|
|
}
|
|
|
|
// x,y: tile coordinates
|
|
void copy_tile_up(int x, int y)
|
|
{
|
|
copy_tile(x, y, x, y - 2);
|
|
}
|
|
|
|
void print_space(WINDOW *window)
|
|
{
|
|
byte space = SPACE;
|
|
weld_entry(window, &space);
|
|
}
|
|
|
|
// Prints the dollar sign, the zeroes, and (optionally if style == 1) the 00 symbol
|
|
void print_number_menu(WINDOW* window, int style)
|
|
{
|
|
// Print a $ sign (0x54) at (32, 32) pixels
|
|
int x = (window->window_x << 3) + 32;
|
|
int y = (window->window_y << 3) + 32;
|
|
|
|
print_character(decode_character(0x54), x, y);
|
|
x += 8;
|
|
|
|
// Print the zeroes (0x60)
|
|
for (int i = 0; i < window->cursor_x_delta; i++)
|
|
{
|
|
print_character(decode_character(0x60), x, y);
|
|
x += 8;
|
|
}
|
|
|
|
// Print the 00 symbol (0x56)
|
|
if (style == 1)
|
|
{
|
|
print_character(decode_character(0x56), x, y);
|
|
}
|
|
}
|
|
|
|
// Print the given digit for the number selection menu at the current cursor location
|
|
void print_number_menu_current(byte digit, WINDOW* window)
|
|
{
|
|
// Skip the 4 blank tiles
|
|
int x = (window->window_x + (window->cursor_x_delta - window->cursor_x) + 4) << 3;
|
|
|
|
// Skip the first two text rows
|
|
int y = (window->window_y + 4) << 3;
|
|
|
|
// Erase what was there before
|
|
print_blankstr(x >> 3, y >> 3, 1);
|
|
|
|
// Now print the digit
|
|
print_character(decode_character(digit + 0x60), x, y);
|
|
}
|
|
|
|
// Clears the number menu of a window
|
|
// More specifically, clear the 3rd row of text and reset the bottom window border
|
|
void clear_number_menu(WINDOW* window)
|
|
{
|
|
// Clear the text
|
|
print_blankstr_window(0, 4, window->window_width, window);
|
|
|
|
// Reset the border (6th tile row)
|
|
unsigned short border_tile = (*tile_offset + 0x96) | *palette_mask;
|
|
for (int i = 0; i < window->window_width; i++)
|
|
{
|
|
(*tilemap_pointer)[window->window_x + i + ((window->window_y + 6) * 32)] = border_tile;
|
|
}
|
|
}
|
|
|
|
// Prints a character to a window, and updates the window's text position
|
|
byte print_character_to_window(byte chr, WINDOW* window)
|
|
{
|
|
int x = ((window->window_x + window->text_x) << 3) + window->pixel_x;
|
|
int y = (window->window_y + window->text_y) << 3;
|
|
|
|
byte width = print_character(chr, x, y);
|
|
x += width;
|
|
|
|
window->pixel_x = x & 7;
|
|
window->text_x = (x >> 3) - window->window_x;
|
|
|
|
return width;
|
|
}
|
|
|
|
// Write the following, in sequence, to str:
|
|
// [5F FF xx] code to right-align the text to padding pixels
|
|
// Dollar sign (0x54)
|
|
// Digits
|
|
// 00 symbol (0x56)
|
|
// [00 FF] end code
|
|
void format_cash_window(int value, int padding, byte* str)
|
|
{
|
|
// Convert digits to BCD for easy parsing
|
|
int digit_count;
|
|
int bcd = bin_to_bcd(value, &digit_count);
|
|
|
|
// Dollar sign is 6 pixels wide, 00 symbol is 8
|
|
padding -= 14;
|
|
|
|
// Subtract 6 pixels for each digit
|
|
padding -= (6 * digit_count);
|
|
|
|
// Control code
|
|
*str++ = 0x5F;
|
|
*str++ = 0xFF;
|
|
*str++ = padding & 0xFF;
|
|
|
|
*str++ = 0x54;
|
|
|
|
// Write the digits
|
|
for (int i = 0; i < digit_count; i++)
|
|
{
|
|
byte digit = ((bcd >> ((digit_count - 1 - i) * 4)) & 0xF) + ZERO;
|
|
*str++ = digit;
|
|
}
|
|
|
|
*str++ = 0x56;
|
|
*str++ = 0;
|
|
*str++ = 0xFF;
|
|
}
|
|
|
|
int player_name_printing_registration(byte* str, WINDOW* window)
|
|
{
|
|
char String[26];
|
|
bool ended = false;
|
|
int total = 24;
|
|
for(int i = 0; i < 24; i++)
|
|
{
|
|
if(ended)
|
|
{
|
|
String[i] = 0x53;
|
|
}
|
|
else if((i < 23 && str[i + 1] == 0xFF && str[i] == 0) || (i == 23 && str[i] == 0))
|
|
{
|
|
String[i] = 0x70;
|
|
total = i;
|
|
ended = true;
|
|
}
|
|
else
|
|
String[i] = str[i];
|
|
}
|
|
String[24] = 0;
|
|
String[25] = 0xFF;
|
|
print_blankstr_window_buffer(0, 2, 24, window);
|
|
printstr_buffer(window, String, 0, 1, 0);
|
|
return total;
|
|
}
|
|
|
|
// The game draws windows lazily: no window will be drawn to the screen until
|
|
// a renderable token is encountered. So it's possible to have text that
|
|
// does stuff in the background without ever showing a window. Lots of doors
|
|
// and hotspots do this for example.
|
|
// When the game first encounters a renderable token, it checks two things:
|
|
// - If the flag at 0x30051F0 is 1, then call m2_resetwindow and set the flag to 0
|
|
// - If the window has flag 0x20 set, then call m2_drawwindow (which unsets the
|
|
// window flag)
|
|
// See 80CA2C2 for an example. We want to replicate this behaviour sometimes,
|
|
// e.g. for custom control codes that are considered renderable.
|
|
void handle_first_window(WINDOW* window)
|
|
{
|
|
if (*first_window_flag == 1)
|
|
{
|
|
m2_resetwindow(window, false);
|
|
*first_window_flag = 0;
|
|
}
|
|
else if (window->redraw)
|
|
{
|
|
m2_drawwindow(window);
|
|
}
|
|
}
|
|
|
|
//Returns in *String a string containing "Talk to" and "Goods"
|
|
void setupShortMainMenu_Talk_to_Goods(char *String)
|
|
{
|
|
char Talk_to[] = "Talk to";
|
|
char Goods[] = "Goods";
|
|
int index = 0;
|
|
String[index++] = 0x5F;
|
|
String[index++] = 0xFF;
|
|
String[index++] = 0x08;
|
|
for(int i = 0; i < (sizeof(Talk_to) - 1); i++)
|
|
String[index++] = encode_ascii(Talk_to[i]);
|
|
String[index++] = 0x5F;
|
|
String[index++] = 0xFF;
|
|
String[index++] = 0x30;
|
|
for(int i = 0; i < (sizeof(Goods) - 1); i++)
|
|
String[index++] = encode_ascii(Goods[i]);
|
|
String[index++] = 0;
|
|
String[index++] = 0xFF;
|
|
}
|
|
|
|
int get_pointer_jump_back(byte *character)
|
|
{
|
|
byte *address1 = ((byte*)0x3004F24);
|
|
byte *address2 = ((byte*)0x3005078);
|
|
byte val = (*address1);
|
|
byte val2 = (*address2);
|
|
if(val != 0 || val2 == 0)
|
|
return 0;
|
|
val2--;
|
|
(*address2) = val2;
|
|
int *address3 = ((int*)0x3005080);
|
|
byte *str = (byte*)(*(address3 + val2));
|
|
return (str - character - 2);
|
|
}
|
|
|
|
void print_letter_in_buffer(WINDOW* window, byte* character, byte* dest)
|
|
{
|
|
m2_cstm_last_printed[0] = (*character);
|
|
weld_entry_custom_buffer(window, character, 0, 0xF, dest);
|
|
if(window->delay_between_prints == 0)
|
|
return;
|
|
byte* address = (byte*)0x3005218;
|
|
byte counter = (*address);
|
|
if(counter == 1)
|
|
m2_soundeffect(0x133);
|
|
}
|
|
|
|
int print_window_with_buffer(WINDOW* window)
|
|
{
|
|
int delay = 0;
|
|
if((window->loaded_code != 0) && ((*script_readability) == 0))
|
|
{
|
|
if(window->delay_between_prints == 0)
|
|
delay = 0;
|
|
else if(!window->enable && window->flags_unknown1 == 1)
|
|
{
|
|
|
|
}
|
|
else if(window->enable && window->flags_unknown1 == 1)
|
|
{
|
|
|
|
}
|
|
else
|
|
return 0;
|
|
while(window->loaded_code !=0)
|
|
{
|
|
window->delay = delay;
|
|
print_character_with_codes(window, (byte*)(OVERWORLD_BUFFER - ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER)));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void scrolltext_buffer(WINDOW* window, byte* dest)
|
|
{
|
|
unsigned short empty_tile = ((*tile_offset) + 0x1FF) | (*palette_mask);
|
|
unsigned short *arrangementBase = (*tilemap_pointer);
|
|
int start = (window->window_y * 32) + window->window_x;
|
|
if(window->window_height <= 2)
|
|
{
|
|
if(window->window_area > 0)
|
|
{
|
|
for(int y = 0; y < window->window_height && y + window->window_y <= 0x1F; y++)
|
|
for(int x = 0; x < window->window_width && x + window->window_x <= 0x1F; x++)
|
|
{
|
|
arrangementBase[start + x + (y * 32)] = empty_tile;
|
|
clear_tile_buffer(x + window->window_x, y + window->window_y, dest);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(window->window_area > 0)
|
|
{
|
|
for(int y = 2; y < window->window_height && y + window->window_y <= 0x1F; y++)
|
|
for(int x = 0; x < window->window_width && x + window->window_x <= 0x1F; x++)
|
|
{
|
|
if(arrangementBase[start + ((y - 2) * 32) + x] == empty_tile)
|
|
{
|
|
if(arrangementBase[start + (y * 32) + x] != empty_tile) //Non Blank to Blank
|
|
{
|
|
copy_tile_up_buffer(x, y, dest);
|
|
arrangementBase[start + ((y - 2) * 32) + x] = arrangementBase[start + (y * 32) + x];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(arrangementBase[start + (y * 32) + x] == empty_tile) //Blank to Non Blank
|
|
{
|
|
arrangementBase[start + ((y - 2) * 32) + x] = empty_tile;
|
|
}
|
|
copy_tile_up_buffer(x, y, dest); //Non Blank to Non Blank
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
for(int y = window->window_height - 2; y >= 0 && y < window->window_height; y++)
|
|
for(int x = 0; x < window->window_width && x + window->window_x <= 0x1F; x++)
|
|
{
|
|
arrangementBase[start + x + (y * 32)] = empty_tile;
|
|
clear_tile_buffer(x + window->window_x, y + window->window_y, dest);
|
|
}
|
|
}
|
|
|
|
void properScroll(WINDOW* window, byte* dest)
|
|
{
|
|
scrolltext_buffer(window, dest);
|
|
window->text_y = window->text_y - 2;
|
|
window->text_x = 0;
|
|
window->pixel_x = 0;
|
|
}
|
|
|
|
void setStuffWindow_Graphics()
|
|
{
|
|
int *something = (int*)0x3005220;
|
|
unsigned short *address = (unsigned short*)((*something) + 0x4BA);
|
|
(*address) = 0;
|
|
(*(address + 2)) = 0;
|
|
(*(address - 2)) = (*(address - 2)) + 1;
|
|
if((*(address - 2)) >= 2)
|
|
(*(address + 2)) = 0;
|
|
}
|
|
|
|
byte print_character_with_codes(WINDOW* window, byte* dest)
|
|
{
|
|
int delay = window->delay--;
|
|
if(delay > 0)
|
|
return 0;
|
|
bool usingOffset2= false;
|
|
int offsetJump = 0;
|
|
int returnedLength = 0;
|
|
byte *character = window->text_start + window->text_offset;
|
|
int y = window->window_y + window->text_y;
|
|
int x = window->window_x + window->text_x;
|
|
unsigned short *tilesetDest = (unsigned short *)(*tilemap_pointer);
|
|
tilesetDest = tilesetDest + (y << 6) + (x << 1);
|
|
|
|
|
|
if((*(character + 1)) != 0xFF)
|
|
if(window->text_y >= window->window_height || y > 0x1F)
|
|
{
|
|
properScroll(window, dest);
|
|
return 0;
|
|
}
|
|
|
|
switch(window->loaded_code)
|
|
{
|
|
case 6:
|
|
break;
|
|
case 7:
|
|
character = m2_ness_name + window->text_offset2; //Ness
|
|
usingOffset2 = true;
|
|
break;
|
|
case 8:
|
|
character = (m2_ness_name + 7) + window->text_offset2; //Paula
|
|
usingOffset2 = true;
|
|
break;
|
|
case 9:
|
|
character = (m2_ness_name + 14) + window->text_offset2; //Jeff
|
|
usingOffset2 = true;
|
|
break;
|
|
case 10:
|
|
character = (m2_ness_name + 21) + window->text_offset2; //Poo
|
|
usingOffset2 = true;
|
|
break;
|
|
case 11:
|
|
character = (m2_ness_name + 36) + window->text_offset2; //Food
|
|
usingOffset2 = true;
|
|
break;
|
|
case 12:
|
|
character = (m2_ness_name + 44) + window->text_offset2; //Rockin
|
|
usingOffset2 = true;
|
|
break;
|
|
case 20:
|
|
character = (m2_ness_name + 28) + window->text_offset2; //King
|
|
usingOffset2 = true;
|
|
break;
|
|
case 13:
|
|
break; //User
|
|
case 14:
|
|
break; //Target
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if((*(character + 1)) == 0xFF)
|
|
{
|
|
byte code = (*character);
|
|
switch(code)
|
|
{
|
|
case 1:
|
|
window->text_y += 2;
|
|
window->text_x = 0;
|
|
window->pixel_x = 0;
|
|
if(!usingOffset2)
|
|
window->text_offset += 2;
|
|
else
|
|
window->text_offset2 += 2;
|
|
setStuffWindow_Graphics();
|
|
if(window->text_y >= window->window_height || window->text_y + window->window_y > 0x1F)
|
|
properScroll(window, dest);
|
|
break;
|
|
case 2:
|
|
window->text_y += 2;
|
|
window->text_x = 0;
|
|
window->pixel_x = 0;
|
|
if(!usingOffset2)
|
|
window->text_offset += 2;
|
|
else
|
|
window->text_offset2 += 2;
|
|
window->counter = 0;
|
|
window->loaded_code = 2;
|
|
setStuffWindow_Graphics();
|
|
return 2;
|
|
case 0xD:
|
|
case 0xE:
|
|
case 0xF:
|
|
case 0x10:
|
|
window->text_offset += 2;
|
|
window->text_offset2 = 0;
|
|
window->loaded_code = 7 + code - 0xD;
|
|
break;
|
|
case 0:
|
|
if(window->loaded_code >= 6 && window->loaded_code <= 0x20)
|
|
{
|
|
window->loaded_code = 1;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
offsetJump = get_pointer_jump_back(character);
|
|
if(offsetJump != 0)
|
|
window->text_offset += 2 + offsetJump;
|
|
else
|
|
{
|
|
window->loaded_code = 0;
|
|
return 1;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
if(code >= 0x60)
|
|
window->text_offset += m2_jump_to_offset(character);
|
|
else
|
|
{
|
|
returnedLength = custom_codes_parse_generic(code, character, window, dest);
|
|
if(returnedLength == 0)
|
|
returnedLength = 2;
|
|
else if(returnedLength < 0)
|
|
returnedLength = 0;
|
|
window->text_offset += returnedLength;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
handle_first_window_buffer(window, (byte*)(OVERWORLD_BUFFER - ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER)));
|
|
window->delay = window->delay_between_prints;
|
|
if(window->text_x >= window->window_width || (window->text_x + window->window_x) > 0x1F)
|
|
{
|
|
window->text_y += 2;
|
|
window->text_x = 0;
|
|
window->pixel_x = 0;
|
|
}
|
|
print_letter_in_buffer(window, character, dest);
|
|
if(!usingOffset2)
|
|
window->text_offset += 1;
|
|
else
|
|
window->text_offset2 += 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
byte print_character_formatted_buffer(byte chr, int x, int y, int font, int foreground, byte *dest)
|
|
{
|
|
// 0x64 to 0x6C (inclusive) is YOU WON
|
|
if ((chr >= YOUWON_START) && (chr <= YOUWON_END))
|
|
{
|
|
print_special_character_buffer(chr + 0xF0, x, y);
|
|
return 8;
|
|
}
|
|
|
|
// 0x6D is an arrow ->
|
|
if (chr == ARROW)
|
|
{
|
|
print_special_character_buffer(ARROW + 0x30, x, y);
|
|
return 9;
|
|
}
|
|
|
|
return print_character_with_callback_1bpp_buffer(chr, x, y, dest, &get_tile_number_with_offset, font, *tilemap_pointer, 32, 0xC);
|
|
}
|
|
|
|
void weld_entry_custom_buffer(WINDOW *window, byte *str, int font, int foreground, byte* dest)
|
|
{
|
|
int chr = decode_character(*str);
|
|
|
|
int x = window->pixel_x + (window->window_x + window->text_x) * 8;
|
|
int y = (window->window_y + window->text_y) * 8;
|
|
|
|
if(!window->inside_width_calc)
|
|
x += print_character_formatted_buffer(chr, x, y, font, foreground, dest);
|
|
else
|
|
x += (m2_widths_table[font][chr] & 0xFF);
|
|
|
|
window->pixel_x = x & 7;
|
|
window->text_x = (x >> 3) - window->window_x;
|
|
if(window->inside_width_calc && window->text_x >= window->window_width)
|
|
window->text_x = window->window_width;
|
|
|
|
}
|
|
|
|
void handle_first_window_buffer(WINDOW* window, byte* dest)
|
|
{
|
|
if (*first_window_flag == 1)
|
|
{
|
|
buffer_reset_window(window, false, dest);
|
|
*first_window_flag = 0;
|
|
}
|
|
else if (window->redraw)
|
|
{
|
|
window->pixel_x = 0;
|
|
buffer_drawwindow(window, dest);
|
|
}
|
|
}
|
|
|
|
void clear_window_buffer(WINDOW *window, byte* dest)
|
|
{
|
|
clear_rect_buffer(window->window_x, window->window_y,
|
|
window->window_width, window->window_height,
|
|
dest);
|
|
}
|
|
|
|
// x,y: tile coordinates
|
|
void clear_rect_buffer(int x, int y, int width, int height, byte* dest)
|
|
{
|
|
for (int tileY = 0; tileY < height; tileY++)
|
|
{
|
|
for (int tileX = 0; tileX < width; tileX++)
|
|
{
|
|
clear_tile_buffer(x + tileX, y + tileY, dest);
|
|
}
|
|
}
|
|
}
|
|
|
|
int print_string_in_buffer(byte *str, int x, int y, byte *dest)
|
|
{
|
|
if (str == NULL)
|
|
return 0;
|
|
|
|
byte chr;
|
|
int initial_x = x;
|
|
int charCount = 0;
|
|
|
|
while (str[1] != 0xFF || str[0] != 0)
|
|
{
|
|
if(str[1] == 0xFF && str[0] == 1)
|
|
{
|
|
x = initial_x;
|
|
str += 2;
|
|
y+= 0x10;
|
|
}
|
|
else if(str[1] != 0xFF)
|
|
{
|
|
x += print_character_formatted_buffer(decode_character(*str++), x, y, 0, 0xF, dest);
|
|
charCount++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
int totalWidth = x - initial_x;
|
|
|
|
return (charCount & 0xFFFF) | (totalWidth << 16);
|
|
}
|
|
|
|
int printstr_buffer(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight)
|
|
{
|
|
int tmpOffset = window->text_offset;
|
|
int tmpOffset2 = window->text_offset2;
|
|
byte* tmpTextStart = window->text_start;
|
|
unsigned short tmpText_x = window->text_x;
|
|
unsigned short tmpText_y = window->text_y;
|
|
unsigned short tmpDelayPrints = window->delay_between_prints;
|
|
unsigned short tmpPaletteMsk = (*palette_mask);
|
|
unsigned short palette_mask_highlight = tmpPaletteMsk;
|
|
window->text_start = str;
|
|
window->text_offset = 0;
|
|
window->text_offset2 = 0;
|
|
window->text_x = x;
|
|
window->text_y = (y << 1);
|
|
if(highlight)
|
|
palette_mask_highlight += 0x1000;
|
|
(*palette_mask) = palette_mask_highlight;
|
|
|
|
window->pixel_x = 0;
|
|
unsigned short output = 0;
|
|
while(output != 1)
|
|
{
|
|
window->delay = 0;
|
|
output = print_character_with_codes(window, (byte*)(OVERWORLD_BUFFER - ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER)));
|
|
}
|
|
int retValue = (window->text_x << 3) + window->pixel_x;
|
|
window->text_start = tmpTextStart;
|
|
window->text_offset = tmpOffset;
|
|
window->text_offset2 = tmpOffset2;
|
|
window->text_x = tmpText_x;
|
|
window->text_y = tmpText_y;
|
|
window->delay_between_prints = tmpDelayPrints;
|
|
(*palette_mask) = tmpPaletteMsk;
|
|
return retValue;
|
|
}
|
|
|
|
//Instead of printing an highlighted version of the string, it just highlights the corresponding arrangements
|
|
int highlight_string(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight)
|
|
{
|
|
int retValue = 0;
|
|
if(highlight)
|
|
{
|
|
unsigned short palette_mask_highlight = (*palette_mask) + (highlight == true ? 0x1000 : 0);
|
|
unsigned short* arrangementBase = (*tilemap_pointer) + window->window_x + x + ((window->window_y + (y << 1)) << 5);
|
|
int totalTiles = count_pixels_to_tiles_normal_string(str, 0);
|
|
for(int i = 0; i < totalTiles; i++)
|
|
{
|
|
arrangementBase[i] = (arrangementBase[i] & 0x0FFF) | palette_mask_highlight;
|
|
arrangementBase[i + 0x20] = (arrangementBase[i + 0x20] & 0x0FFF) | palette_mask_highlight;
|
|
}
|
|
retValue = (x + totalTiles) << 3;
|
|
}
|
|
return retValue;
|
|
}
|
|
|
|
//Highlights "Talk to"
|
|
void highlight_talk_to()
|
|
{
|
|
char Talk_to[] = "Talk to";
|
|
byte str[0xA];
|
|
int i;
|
|
for(i = 0; i < (sizeof(Talk_to) - 1); i++)
|
|
str[i] = encode_ascii(Talk_to[i]);
|
|
str[i++] = 0;
|
|
str[i] = 0xFF;
|
|
highlight_string(getWindow(0), str, 1, 0, true);
|
|
}
|
|
|
|
unsigned short printstr_hlight_buffer(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight)
|
|
{
|
|
return printstr_hlight_pixels_buffer(window, str, x << 3, y << 4, highlight);
|
|
}
|
|
|
|
unsigned short printstr_hlight_pixels_buffer(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight)
|
|
{
|
|
unsigned short printX = x + ((window->window_x) << 3);
|
|
unsigned short printY = y + ((window->window_y) << 3);
|
|
unsigned short tmpPaletteMsk = (*palette_mask);
|
|
unsigned short palette_mask_highlight = tmpPaletteMsk;
|
|
if(highlight)
|
|
palette_mask_highlight += 0x1000;
|
|
(*palette_mask) = palette_mask_highlight;
|
|
|
|
unsigned short printed_Characters = print_string_in_buffer(str, printX, printY, (byte*)(OVERWORLD_BUFFER - ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER)));
|
|
|
|
(*palette_mask) = tmpPaletteMsk;
|
|
|
|
return printed_Characters;
|
|
}
|
|
|
|
WINDOW* getWindow(int index)
|
|
{
|
|
return window_pointers[index];
|
|
}
|
|
|
|
int initWindow_buffer(WINDOW* window, byte* text_start, unsigned short delay_between_prints)
|
|
{
|
|
window->vwf_skip = false;
|
|
window->unknown3 = 0;
|
|
window->text_x = 0;
|
|
window->text_y = 0;
|
|
window->text_offset = 0;
|
|
window->text_start = text_start;
|
|
window->text_start2 = text_start;
|
|
window->delay_between_prints = delay_between_prints;
|
|
window->delay = 0;
|
|
window->loaded_code = 1;
|
|
window->enable = true;
|
|
window->flags_unknown1 |= 1;
|
|
window->redraw = true;
|
|
if(text_start == NULL)
|
|
buffer_drawwindow(window, (byte*)(OVERWORLD_BUFFER - ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER)));
|
|
return 0;
|
|
}
|
|
|
|
//A different initWindow called by some windows
|
|
int initWindow_cursor_buffer(WINDOW* window, byte* text_start, unsigned short cursor_x_delta, unsigned short unknown7a, unsigned short cursor_x_base)
|
|
{
|
|
window->vwf_skip = false;
|
|
window->unknown3 = 0;
|
|
window->text_x = 0;
|
|
window->text_y = 0;
|
|
window->text_offset = 0;
|
|
window->text_start = text_start;
|
|
window->text_start2 = text_start;
|
|
window->delay_between_prints = 0;
|
|
window->delay = 0;
|
|
window->counter = 0;
|
|
window->loaded_code = 1;
|
|
if(!window->enable)
|
|
{
|
|
window->cursor_y = 0;
|
|
window->unknown6 = 0;
|
|
window->unknown6a = 0;
|
|
window->unknown7 = 0;
|
|
window->unknown7a = unknown7a;
|
|
window->cursor_x = cursor_x_base;
|
|
window->cursor_x_base = cursor_x_base;
|
|
window->cursor_x_delta = cursor_x_delta;
|
|
}
|
|
window->enable = true;
|
|
window->flags_unknown1 |= 1;
|
|
window->redraw = true;
|
|
if(text_start == NULL)
|
|
buffer_drawwindow(window, (byte*)(OVERWORLD_BUFFER - ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER)));
|
|
return 0;
|
|
}
|
|
|
|
void clearWindowTiles_buffer(WINDOW* window)
|
|
{
|
|
clear_window_buffer(window, (byte*)(OVERWORLD_BUFFER - ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER)));
|
|
window->text_x = 0;
|
|
window->text_y = 0;
|
|
}
|
|
|
|
// x,y: tile coordinates
|
|
void clear_tile_buffer(int x, int y, byte* dest)
|
|
{
|
|
// Clear pixels
|
|
int tileIndex = get_tile_number_buffer(x, y) + *tile_offset;
|
|
int *destTileInt = (int*)&dest[convert_tile_address_buffer(tileIndex)];
|
|
destTileInt[0] = 0;
|
|
if(((tileIndex - *tile_offset) & 0x20) == 0)
|
|
destTileInt[1] = 0;
|
|
|
|
// Reset the tilemap (e.g. get rid of equip or SMAAAASH!! tiles)
|
|
(*tilemap_pointer)[x + (y * 32)] = (get_tile_number(x, y) + (*tile_offset)) | *palette_mask;
|
|
}
|
|
|
|
int buffer_reset_window(WINDOW* window, bool skip_redraw, byte* dest)
|
|
{
|
|
window->delay = 0;
|
|
byte code = window->loaded_code - 0xD;
|
|
if(code >= 1)
|
|
window->loaded_code = 1;
|
|
window->enable = true;
|
|
window->flags_unknown1 = 1;
|
|
window->redraw = true;
|
|
window->hold = true;
|
|
window->flags_unknown3a = window->flags_unknown3a && 0x1C; //The first byte is set to 0x23
|
|
if(!skip_redraw)
|
|
buffer_drawwindow(window, dest);
|
|
return 0;
|
|
}
|
|
|
|
int buffer_drawwindow(WINDOW* window, byte* dest)
|
|
{
|
|
if((int*)dest == vram)
|
|
clear_window(window);
|
|
else
|
|
clear_window_buffer(window, dest);
|
|
unsigned short empty_tile = (0x1FF + (*tile_offset)) | (*palette_mask);
|
|
int baseOfWindow = ((window->window_y - 1) * 32) + window->window_x - 1;
|
|
unsigned short *arrangementBase = (*tilemap_pointer);
|
|
|
|
for(int y = 0; y < window->window_height && y + window->window_y <= 0x1F; y++)
|
|
for(int x = 0; x < window->window_width && x + window->window_x <= 0x1F; x++)
|
|
arrangementBase[baseOfWindow + 1 + x + ((y + 1) * 32)] = empty_tile;
|
|
|
|
window->counter = 0;
|
|
unsigned short void_tile = (0x1DF + (*tile_offset)) | (*palette_mask);
|
|
if((window->window_x - 1 < 0) || (window->window_x - 1 + window->window_width > 0x1F) || (window->window_y - 1 < 0) || (window->window_y - 1 + window->window_height > 0x1F))
|
|
return -1;
|
|
|
|
//Tiles
|
|
unsigned short bottom_right_corner_void = (0x93 + (*tile_offset)) | (*palette_mask);
|
|
unsigned short bottom_right_corner_full = (0x94 + (*tile_offset)) | (*palette_mask);
|
|
unsigned short bottom_left_corner_void = 0x400 | bottom_right_corner_void;
|
|
unsigned short bottom_left_corner_full = 0x400 | bottom_right_corner_full;
|
|
unsigned short top_right_corner_void = 0x800 | bottom_right_corner_void;
|
|
unsigned short top_right_corner_full = 0x800 | bottom_right_corner_full;
|
|
unsigned short top_left_corner_void = 0xC00 | bottom_right_corner_void;
|
|
unsigned short top_left_corner_full = 0xC00 | bottom_right_corner_full;
|
|
|
|
//Check which tiles to use for the corners
|
|
unsigned short current_top_left_tile = arrangementBase[baseOfWindow];
|
|
if(current_top_left_tile == void_tile) //Top left
|
|
arrangementBase[baseOfWindow] = top_left_corner_void;
|
|
else if(current_top_left_tile != top_left_corner_void)
|
|
arrangementBase[baseOfWindow] = top_left_corner_full;
|
|
unsigned short current_top_right_tile = arrangementBase[baseOfWindow + 1 + window->window_width];
|
|
if(current_top_right_tile == void_tile) //Top right
|
|
arrangementBase[baseOfWindow + 1 + window->window_width] = top_right_corner_void;
|
|
else if(current_top_right_tile != top_right_corner_void)
|
|
arrangementBase[baseOfWindow + 1 + window->window_width] = top_right_corner_full;
|
|
unsigned short current_bottom_left_tile = arrangementBase[baseOfWindow + ((window->window_height + 1) * 32)];
|
|
if(current_bottom_left_tile == void_tile) //Bottom left
|
|
arrangementBase[baseOfWindow + ((window->window_height + 1) * 32)] = bottom_left_corner_void;
|
|
else if(current_bottom_left_tile != bottom_left_corner_void)
|
|
arrangementBase[baseOfWindow + ((window->window_height + 1) * 32)] = bottom_left_corner_full;
|
|
unsigned short current_bottom_right_tile = arrangementBase[baseOfWindow + ((window->window_height + 1) * 32) + 1 + window->window_width];
|
|
if(current_bottom_right_tile == void_tile) //Bottom right
|
|
arrangementBase[baseOfWindow + ((window->window_height + 1) * 32) + 1 + window->window_width] = bottom_right_corner_void;
|
|
else if(current_bottom_right_tile != bottom_right_corner_void)
|
|
arrangementBase[baseOfWindow + ((window->window_height + 1) * 32) + 1 + window->window_width] = bottom_right_corner_full;
|
|
|
|
//Border tiles
|
|
unsigned short *address = (unsigned short*)0x3000A0E;
|
|
unsigned short bottom_horizontal = (0x96 + (*tile_offset)) | (*palette_mask);
|
|
unsigned short top_horizontal = 0x800 | bottom_horizontal;
|
|
unsigned short right_vertical = (0x95 + (*tile_offset)) | (*palette_mask);
|
|
unsigned short left_vertical = 0x400 | right_vertical;
|
|
|
|
for(int i = 0; i < window->window_width; i++)
|
|
{
|
|
arrangementBase[baseOfWindow + 1 + i] = top_horizontal;
|
|
arrangementBase[baseOfWindow + ((window->window_height + 1) * 32) + 1 + i] = bottom_horizontal;
|
|
}
|
|
|
|
for(int i = 0; i < window->window_height; i++)
|
|
{
|
|
arrangementBase[baseOfWindow + ((i + 1) * 32)] = left_vertical;
|
|
arrangementBase[baseOfWindow + ((i + 1) * 32) + 1 + window->window_width] = right_vertical;
|
|
}
|
|
|
|
window->redraw = false;
|
|
window->enable = true;
|
|
|
|
(*address) = 1;
|
|
return 0;
|
|
}
|
|
|
|
int setNumber_getLength(int value, byte *str, int maxLength)
|
|
{
|
|
if(value <= 0)
|
|
{
|
|
str[0] = ZERO;
|
|
return 1;
|
|
}
|
|
unsigned int *upperValuesTable = (unsigned int*)0x8B1C064;
|
|
unsigned int upperValue = *(upperValuesTable + maxLength);
|
|
if(value >= upperValue)
|
|
{
|
|
for(int i = 0; i < maxLength; i++)
|
|
str[i] = ZERO + 9;
|
|
return maxLength;
|
|
}
|
|
int pos = 0;
|
|
int tmpValue = value;
|
|
for(int i=0; i < maxLength + 1; i++)
|
|
{
|
|
if(value >= upperValue)
|
|
{
|
|
byte digit;
|
|
if(upperValue == 0)
|
|
digit = tmpValue;
|
|
else
|
|
{
|
|
digit = m2_div(tmpValue, upperValue);
|
|
tmpValue -= (digit * upperValue);
|
|
}
|
|
str[pos++] = ZERO + digit;
|
|
}
|
|
upperValue = *(upperValuesTable + maxLength - i - 1);
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
unsigned short ailmentTileSetup(byte *ailmentBase, unsigned short defaultVal)
|
|
{
|
|
int value = defaultVal;
|
|
byte flagValue = 0;
|
|
if((*ailmentBase) == CONSCIOUS)
|
|
{
|
|
if((*(ailmentBase + 1)) != CONSCIOUS)
|
|
{
|
|
flagValue = (*(ailmentBase + 1));
|
|
value = 1;
|
|
}
|
|
else if((*(ailmentBase + 2)) != CONSCIOUS)
|
|
{
|
|
flagValue = (*(ailmentBase + 2));
|
|
value = 2;
|
|
}
|
|
else if((*(ailmentBase + 3)))
|
|
{
|
|
flagValue = (*(ailmentBase + 3));
|
|
value = 3;
|
|
}
|
|
else if((*(ailmentBase + 4)))
|
|
{
|
|
flagValue = (*(ailmentBase + 4));
|
|
value = 4;
|
|
}
|
|
else if((*(ailmentBase + 5)))
|
|
{
|
|
flagValue = (*(ailmentBase + 5));
|
|
value = 5;
|
|
}
|
|
else if((*(ailmentBase + 6)))
|
|
{
|
|
flagValue = (*(ailmentBase + 6));
|
|
value = 6;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
value = 0;
|
|
flagValue = (*(ailmentBase));
|
|
}
|
|
unsigned short *returnValues = (unsigned short*)0x8B1F2E4;
|
|
return (*(returnValues + (value * 7) + flagValue - 1));
|
|
}
|
|
|
|
void printTinyArrow(int x, int y)
|
|
{
|
|
print_special_character_buffer(0x9F, x, y);
|
|
}
|
|
|
|
void printCashWindow()
|
|
{
|
|
(*window_flags) |= 2;
|
|
byte *str = (*free_strings_pointers);
|
|
format_cash_window(*cash_on_hand, 0x30, str);
|
|
initWindow_buffer(getWindow(1), str, 0);
|
|
print_window_with_buffer(getWindow(1));
|
|
m2_sub_d6844();
|
|
m2_sub_d3c50();
|
|
}
|
|
|
|
void eb_cartridge_palette_change(bool background)
|
|
{
|
|
unsigned short *paletteDest = (unsigned short*)0x5000040;
|
|
if(background)
|
|
{
|
|
if(BUILD_PALETTE)
|
|
{
|
|
//Makes the game do the palette work. Copy the result in a bin file and use that instead in order to make the swap fast
|
|
unsigned short palettes[0x50];
|
|
cpuset(paletteDest, palettes, 0x50);
|
|
for(int i = 0; i < 5; i++)
|
|
m12_dim_palette(&palettes[i * 0x10], 0x10, 0x800);
|
|
cpuset(palettes, paletteDest, 0x50);
|
|
}
|
|
else
|
|
cpuset(m12_cartridge_palettes_dimmed, paletteDest, 0x50);
|
|
}
|
|
else
|
|
cpuset(&m12_cartridge_palettes[0x20], paletteDest, 0x50);
|
|
}
|
|
|
|
// x, y, width: tile coordinates
|
|
void print_blankstr_buffer(int x, int y, int width, byte *dest)
|
|
{
|
|
clear_rect_buffer(x, y, width, 2, dest);
|
|
}
|
|
|
|
//Function called for printing the alphabet. Seems to be a trimmed down version of the normal script-reading function. Probably done in order to make this faster
|
|
int print_alphabet_buffer(WINDOW* window)
|
|
{
|
|
byte* dest = (byte*)(OVERWORLD_BUFFER - ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER));
|
|
if(window->redraw)
|
|
buffer_drawwindow(window, dest);
|
|
if(window->loaded_code == 0 || (*script_readability) != 0)
|
|
return 0;
|
|
|
|
window->delay = 0;
|
|
byte* str = window->text_start + window->text_offset;
|
|
|
|
while(true)
|
|
{
|
|
unsigned short y = window->window_y + window->text_y;
|
|
while(window->text_y >= window->window_height || y > 0x1F)
|
|
{
|
|
properScroll(window, dest);
|
|
y = window->window_y + window->text_y;
|
|
}
|
|
|
|
if(str[1] == 0xFF)
|
|
{
|
|
byte returnedVal = custom_codes_parse_generic(str[0], str, window, dest);
|
|
if(returnedVal != 0)
|
|
{
|
|
window->text_offset += returnedVal;
|
|
str += returnedVal;
|
|
}
|
|
else if(str[0] == 1)
|
|
{
|
|
window->text_y += 2;
|
|
window->text_x = 0;
|
|
window->pixel_x = 0;
|
|
str += 2;
|
|
window->text_offset += 2;
|
|
}
|
|
else if(str[0] == 0)
|
|
{
|
|
window->loaded_code = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(window->text_x >= window->window_width || (window->text_x + window->window_x) > 0x1F)
|
|
{
|
|
window->text_y += 2;
|
|
window->text_x = 0;
|
|
window->pixel_x = 0;
|
|
}
|
|
weld_entry_custom_buffer(window, str, 0, 0xF, dest);
|
|
str++;
|
|
window->text_offset++;
|
|
}
|
|
}
|
|
}
|
|
|
|
int check_overworld_buffer()
|
|
{
|
|
int address = *((int*)(OVERWORLD_BUFFER_POINTER));
|
|
if(address == 0)
|
|
{
|
|
int tmp_counter = m2_buffer_counter;
|
|
address = (int)m2_malloc(OVERWORLD_BUFFER_SIZE);
|
|
*((int*)(OVERWORLD_BUFFER_POINTER)) = address;
|
|
m2_buffer_counter = tmp_counter;
|
|
}
|
|
return address;
|
|
}
|
|
|
|
void free_overworld_buffer()
|
|
{
|
|
int address = *((int*)(OVERWORLD_BUFFER_POINTER));
|
|
if(address != 0)
|
|
{
|
|
int tmp_counter = m2_buffer_counter;
|
|
m2_free((int*)address);
|
|
*((int*)(OVERWORLD_BUFFER_POINTER)) = 0;
|
|
m2_buffer_counter = tmp_counter;
|
|
}
|
|
}
|
|
|
|
void load_pixels_overworld_buffer()
|
|
{
|
|
int tile = *tile_offset;
|
|
byte* buffer = (byte*)(OVERWORLD_BUFFER - (tile * TILESET_OFFSET_BUFFER_MULTIPLIER));
|
|
int* topBufferValues = (int*)(&buffer[tile * 8]);
|
|
int* bottomBufferValues = topBufferValues + 0x40;
|
|
int* topTilePointer;
|
|
int nextValue = 0x20;
|
|
int i = 0;
|
|
while(i < (0x1C * 8))
|
|
{
|
|
//Using pointers instead of values directly saves another 14k cycles. The total amount of cycles this routine now takes is about 92k
|
|
tile = m2_coord_table_fast_progression[i];
|
|
int remainingTiles = tile >> 0xB;
|
|
tile = (tile & 0x7FF) + (*tile_offset);
|
|
topTilePointer = &vram[(tile * 8)];
|
|
if(i == nextValue)
|
|
{
|
|
nextValue += 0x20;
|
|
topBufferValues = bottomBufferValues;
|
|
bottomBufferValues += 0x40;
|
|
}
|
|
i++;
|
|
//Using "reduce_bit_depth_sp" reduced the total amount of cycles from 300k to 162k
|
|
reduce_bit_depth_sp(topTilePointer, topBufferValues, bottomBufferValues);
|
|
topTilePointer += 8;
|
|
topBufferValues += 2;
|
|
bottomBufferValues++;
|
|
while(remainingTiles > 0)
|
|
{
|
|
if(i == nextValue)
|
|
{
|
|
nextValue += 0x20;
|
|
topBufferValues = bottomBufferValues;
|
|
bottomBufferValues += 0x40;
|
|
}
|
|
i++;
|
|
reduce_bit_depth_sp(topTilePointer, topBufferValues, bottomBufferValues);
|
|
topTilePointer += 8;
|
|
topBufferValues += 2;
|
|
bottomBufferValues++;
|
|
remainingTiles--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void store_pixels_overworld_buffer(int totalYs)
|
|
{
|
|
int tile = *tile_offset;
|
|
byte* buffer = (byte*)(OVERWORLD_BUFFER - (tile * TILESET_OFFSET_BUFFER_MULTIPLIER));
|
|
totalYs >>= 1;
|
|
int total = totalYs * 0x1C;
|
|
int* topBufferValues = (int*)(&buffer[tile * 8]);
|
|
int* bottomBufferValues = topBufferValues + 0x40;
|
|
int* topTilePointer;
|
|
int* bottomTilePointer;
|
|
int* bits_to_nybbles_pointer = m2_bits_to_nybbles_fast;
|
|
int bits_to_nybbles_array[0x100];
|
|
//It's convenient to copy the table in IWRAM (about 0x400 cycles) only if we have more than 0x55 total tiles to copy ((total * 0xC * 2) = total cycles used reading from EWRAM vs. (total * 0xC) + 0x400 = total cycles used writing to and reading from IWRAM)
|
|
//From a full copy it saves about 15k cycles
|
|
if(total >= 0x56)
|
|
{
|
|
cpufastset(bits_to_nybbles_pointer, bits_to_nybbles_array, 0x100);
|
|
bits_to_nybbles_pointer = bits_to_nybbles_array;
|
|
}
|
|
int nextValue = 0x20;
|
|
int i = 0;
|
|
while(i < total)
|
|
{
|
|
//Not using functions for the tile values saves about 30k cycles on average
|
|
//Using pointers + a way to keep track of subsequent tiles saves 50k cycles on average from a full copy
|
|
//m2_coord_table_fast_progression has the tile number and the number of tiles used without interruction after it in a single short
|
|
tile = m2_coord_table_fast_progression[i];
|
|
int remainingTiles = tile >> 0xB;
|
|
tile = (tile & 0x7FF) + (*tile_offset);
|
|
topTilePointer = &vram[(tile * 8)];
|
|
bottomTilePointer = topTilePointer + (0x20 * 8);
|
|
if(i == nextValue)
|
|
{
|
|
nextValue += 0x20;
|
|
topBufferValues += 0x20;
|
|
bottomBufferValues += 0x40;
|
|
}
|
|
i++;
|
|
unsigned int first_half = *(topBufferValues++);
|
|
unsigned int second_half = *(topBufferValues++);
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 8) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x10) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x18) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 8) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x10) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x18) & 0xFF];
|
|
first_half = *(bottomBufferValues++);
|
|
//second_half = *(bottomBufferValues++);
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 8) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x10) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x18) & 0xFF];
|
|
//Since those are unused
|
|
bottomTilePointer += 4;
|
|
/* The game doesn't use these
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 8) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x10) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x18) & 0xFF];
|
|
*/
|
|
|
|
while(remainingTiles > 0)
|
|
{
|
|
if(i == nextValue)
|
|
{
|
|
nextValue += 0x20;
|
|
topBufferValues += 0x20;
|
|
bottomBufferValues += 0x40;
|
|
}
|
|
i++;
|
|
first_half = *(topBufferValues++);
|
|
second_half = *(topBufferValues++);
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 8) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x10) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x18) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 8) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x10) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x18) & 0xFF];
|
|
first_half = *(bottomBufferValues++);
|
|
//second_half = *(bottomBufferValues++);
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 8) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x10) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x18) & 0xFF];
|
|
//Since those are unused
|
|
bottomTilePointer += 4;
|
|
/* The game doesn't use these
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 8) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x10) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x18) & 0xFF];
|
|
*/
|
|
remainingTiles--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void store_pixels_overworld_buffer_totalTiles(int totalTiles)
|
|
{
|
|
int tile = *tile_offset;
|
|
byte* buffer = (byte*)(OVERWORLD_BUFFER - (tile * TILESET_OFFSET_BUFFER_MULTIPLIER));
|
|
int* topBufferValues = (int*)(&buffer[tile * 8]);
|
|
int* bottomBufferValues = topBufferValues + 0x40;
|
|
int* topTilePointer;
|
|
int* bottomTilePointer;
|
|
int* bits_to_nybbles_pointer = m2_bits_to_nybbles_fast;
|
|
int bits_to_nybbles_array[0x100];
|
|
//It's convenient to copy the table in IWRAM (about 0x400 cycles) only if we have more than 0x55 total tiles to copy ((total * 0xC * 2) = total cycles used reading from EWRAM vs. (total * 0xC) + 0x400 = total cycles used writing to and reading from IWRAM)
|
|
//From a full copy it saves about 15k cycles
|
|
if(totalTiles >= 0x56)
|
|
{
|
|
cpufastset(bits_to_nybbles_pointer, bits_to_nybbles_array, 0x100);
|
|
bits_to_nybbles_pointer = bits_to_nybbles_array;
|
|
}
|
|
int nextValue = 0x20;
|
|
int i = 0;
|
|
while(i < totalTiles)
|
|
{
|
|
//Not using functions for the tile values saves about 30k cycles on average
|
|
//Using pointers + a way to keep track of subsequent tiles saves 50k cycles on average
|
|
//m2_coord_table_fast_progression has the tile number and the number of tiles used without interruction after it in a single short
|
|
tile = m2_coord_table_fast_progression[i];
|
|
int remainingTiles = tile >> 0xB;
|
|
tile = (tile & 0x7FF) + (*tile_offset);
|
|
topTilePointer = &vram[(tile * 8)];
|
|
bottomTilePointer = topTilePointer + (0x20 * 8);
|
|
if(i == nextValue)
|
|
{
|
|
nextValue += 0x20;
|
|
topBufferValues += 0x20;
|
|
bottomBufferValues += 0x40;
|
|
}
|
|
i++;
|
|
unsigned int first_half = *(topBufferValues++);
|
|
unsigned int second_half = *(topBufferValues++);
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 8) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x10) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x18) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 8) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x10) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x18) & 0xFF];
|
|
first_half = *(bottomBufferValues++);
|
|
//second_half = *(bottomBufferValues++);
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 8) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x10) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x18) & 0xFF];
|
|
//Since those are unused
|
|
bottomTilePointer += 4;
|
|
/* The game doesn't use these
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 8) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x10) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x18) & 0xFF];
|
|
*/
|
|
|
|
while(remainingTiles > 0 && i < totalTiles)
|
|
{
|
|
if(i == nextValue)
|
|
{
|
|
nextValue += 0x20;
|
|
topBufferValues += 0x20;
|
|
bottomBufferValues += 0x40;
|
|
}
|
|
i++;
|
|
first_half = *(topBufferValues++);
|
|
second_half = *(topBufferValues++);
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 8) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x10) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x18) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 8) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x10) & 0xFF];
|
|
*(topTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x18) & 0xFF];
|
|
first_half = *(bottomBufferValues++);
|
|
//second_half = *(bottomBufferValues++);
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 8) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x10) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(first_half >> 0x18) & 0xFF];
|
|
//Since those are unused
|
|
bottomTilePointer += 4;
|
|
/* The game doesn't use these
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 8) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x10) & 0xFF];
|
|
*(bottomTilePointer++) = bits_to_nybbles_pointer[(second_half >> 0x18) & 0xFF];
|
|
*/
|
|
remainingTiles--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// x, y, width: tile coordinates
|
|
void print_blankstr_window_buffer(int x, int y, int width, WINDOW* window)
|
|
{
|
|
print_blankstr_buffer(x + window->window_x, y + window->window_y, width, (byte*)(OVERWORLD_BUFFER - ((*tile_offset) * TILESET_OFFSET_BUFFER_MULTIPLIER)));
|
|
}
|
|
|
|
// x,y: tile coordinates
|
|
void copy_tile_buffer(int xSource, int ySource, int xDest, int yDest, byte *dest)
|
|
{
|
|
int sourceTileIndex = get_tile_number_buffer(xSource, ySource) + *tile_offset;
|
|
int destTileIndex = get_tile_number_buffer(xDest, yDest) + *tile_offset;
|
|
int* sourceTile = (int*)&dest[convert_tile_address_buffer(sourceTileIndex)];
|
|
int* destTile = (int*)&dest[convert_tile_address_buffer(destTileIndex)];
|
|
|
|
//Copy the first part, no matter what
|
|
destTile[0] = sourceTile[0];
|
|
//Handle the 4 different cases
|
|
if(((sourceTileIndex - *tile_offset) & 0x20) == 0)
|
|
{
|
|
if(((destTileIndex - *tile_offset) & 0x20) == 0)
|
|
destTile[1] = sourceTile[1];
|
|
}
|
|
else
|
|
{
|
|
if(((destTileIndex - *tile_offset) & 0x20) == 0)
|
|
destTile[1] = 0;
|
|
}
|
|
|
|
}
|
|
|
|
// x,y: tile coordinates
|
|
void copy_tile_up_buffer(int x, int y, byte *dest)
|
|
{
|
|
copy_tile_buffer(x, y, x, y - 2, dest);
|
|
} |