Add buffering for the full status window. Also update status tiles in printed text.

Temporarily breaks battle psi menu
This commit is contained in:
Lorenzooone 2019-09-03 22:38:59 +02:00
parent 1c0e1264e0
commit 310771a6a9
17 changed files with 1353 additions and 575 deletions

View File

@ -15,7 +15,9 @@ $input_c_files =
"src/c/vwf.c",
"src/c/locs.c",
"src/c/goods.c",
"src/c/fileselect.c"
"src/c/fileselect.c",
"src/c/status.c",
"src/c/psi.c"
$base_c_address = 0x8100000;
$scripttool_cmd = "bin/ScriptTool/ScriptTool.dll"

View File

@ -13,6 +13,8 @@ int __attribute__((naked)) m2_remainder(int dividend, int divisor) {}
void __attribute__((naked)) m2_formatnumber(int value, byte* strDest, int length) {}
int __attribute__((naked)) m2_sub_a334c(int value) {}
int __attribute__((naked)) m2_sub_a3384(int value) {}
void __attribute__((naked)) m2_sub_d3c50() {}
void __attribute__((naked)) m2_sub_d6844() {}
int __attribute__((naked)) m2_clearwindowtiles(WINDOW* window) {}
int __attribute__((naked)) customcodes_parse_generic(int code, char* parserAddress, WINDOW* window, int* dest) {}
void __attribute__((naked)) m2_printstr(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight) {}

View File

@ -189,7 +189,7 @@ void print_file_string(int x, int y, int length, byte *str, int window_selector,
fileselect_pixels_location,
&get_tile_number_file_select,
tilesetDestPtr,
width);
width, 0x10);
pixelX += pixels;
}

View File

@ -12,13 +12,6 @@ typedef enum DIRECTION_MOVED
DIRECTION_LEFT
} MOVED;
typedef enum GOODS_ACTION
{
ACTION_NONE = 0,
ACTION_STEPIN = 1,
ACTION_STEPOUT = -1
} GOODS_ACTION;
int goods_outer_process(WINDOW* window, int y_offset, bool give);
int goods_inner_process(WINDOW *window, unsigned short *items);
void goods_print_items(WINDOW *window, unsigned short *items, int y_offset);

View File

@ -2,14 +2,18 @@
int *fileselect_pixels_location = (int*) 0x2015000;
int *window_flags = (int*) 0x300130C;
byte *character_general_data = (byte*) 0x3001D40;
PC (*pc_stats)[4] = (PC(*)[4]) 0x3001D54;
int *cash_on_hand = (int*) 0x30023D0;
byte *pc_count = (byte*) 0x3001F0B;
bool (*pc_flags)[4] = (bool(*)[4]) 0x3001F0C;
byte *pc_names = (byte*) 0x3001F10;
PAD_STATE *pad_state = (PAD_STATE*) 0x3002500;
PAD_STATE *pad_state_shadow = (PAD_STATE*) 0x3002504;
byte *script_readability = (byte*) 0x3004F08;
unsigned short *tile_offset = (unsigned short*) 0x30051EC;
int *first_window_flag = (int*) 0x30051F0;
byte **free_strings_pointers = (byte**) 0x3005200;
unsigned short *palette_mask = (unsigned short*) 0x3005228;
WINDOW **window_pointers = (WINDOW**) 0x3005230;
short *active_window_party_member = (short*) 0x3005264;
@ -20,3 +24,4 @@ byte *m2_misc_strings = (byte*) 0x8B17424;
int *m2_items_offsets = (int*) 0x8B1AF94;
byte *m2_items_strings = (byte*) 0x8B1A694;
unsigned short *name_header_tiles = (unsigned short*) 0x8B1B8B0;
PSIPrintInfo *psi_print_info = (PSIPrintInfo*) 0x8B2A9C0;

View File

@ -5,16 +5,20 @@
#include "pc.h"
#include "input.h"
#include "window.h"
#include "psi.h"
extern int *window_flags;
extern PC (*pc_stats)[4];
extern int *cash_on_hand;
extern byte *pc_count;
extern bool (*pc_flags)[4];
extern byte *pc_names;
extern PAD_STATE *pad_state;
extern PAD_STATE *pad_state_shadow;
extern byte *script_readability;
extern unsigned short *tile_offset;
extern int *first_window_flag;
extern byte **free_strings_pointers;
extern unsigned short *palette_mask;
extern WINDOW **window_pointers;
extern short *active_window_party_member;
@ -26,5 +30,7 @@ extern byte *m2_misc_strings;
extern int *m2_items_offsets;
extern byte *m2_items_strings;
extern unsigned short *name_header_tiles;
extern byte *character_general_data;
extern PSIPrintInfo *psi_print_info;
#endif

View File

@ -12,17 +12,37 @@ typedef enum AILMENT
NAUSEOUS = 4,
POISONED = 5,
SUNSTROKE = 6,
SNIFFLING = 7,
MASHROOMIZED = 8,
POSSESSED = 9,
HOMESICK = 0xA,
SNIFFLING = 7
} AILMENT;
typedef enum AILMENT2
{
MASHROOMIZED = 1,
POSSESSED = 2
} AILMENT2;
typedef enum AILMENT3
{
SLEEP = 1,
CRYING = 2
} AILMENT3;
typedef enum CHARACTER
{
NESS = 0,
PAULA = 1,
JEFF = 2,
POO = 3
} CHARACTER;
typedef struct PC {
unsigned short goods[14];
int experience;
//0x20
byte unknown[12];
int level;
short level;
short unknown2a;
//0x30
unsigned short hp_max;
unsigned short hp_current;
byte hp_unknown[2]; // possibly a rolling flag + a fractional value
@ -31,13 +51,14 @@ typedef struct PC {
unsigned short pp_current;
byte pp_unknown[2];
unsigned short pp_rolling;
//0x40
AILMENT ailment;
bool mashroomized;
bool sleep;
AILMENT2 ailment2;
AILMENT3 ailment3;
bool strange;
bool cant_concentrate;
bool homesick;
byte unknown2[2];
bool unknown2[2];
byte offense_base;
byte defense_base;
byte speed_base;
@ -46,6 +67,7 @@ typedef struct PC {
byte vitality_base;
byte iq_base;
byte offense_effective;
//0x50
byte defense_effective;
byte speed_effective;
byte guts_effective;
@ -53,6 +75,7 @@ typedef struct PC {
byte vitality_effective;
byte iq_effective;
byte unknown3[11];
//0x61
byte equipment[4];
byte unknown4[7];
} PC;

145
src/c/psi.c Normal file
View File

@ -0,0 +1,145 @@
#include "window.h"
#include "psi.h"
#include "number-selector.h"
#include "locs.h"
void psiWindow_buffer(CHARACTER psiCharacter, PSIWindow typeOfWindow, PSIClasses printableClasses)
{
PC *char_data = &(m2_ness_data[psiCharacter]);
PSIPrintInfo *printInfo;
int level = 0;
int thing2 = 0;
byte *str = 0;
byte *boolCmpWindowType = (byte*)(&(typeOfWindow));
byte *boolCmpPrintableClasses = (byte*)(&(printableClasses));
byte *address = (byte*)0x3000A00;
WINDOW *window = getWindow(7);
SpecialPSIFlag *SpecialPSIFlags = (SpecialPSIFlag*)(character_general_data + 0x22A);
bool print[0x11];
for(int i = 0; i < 0x11; i ++)
print[i] = true;
for(int i = 0; i < 4; i++)
{
(*(address + i)) = 0;
(*(address + i + 4)) = 0;
(*(address + i + 8)) = 0;
}
if(psiCharacter == POO && typeOfWindow.Classes_Window && printableClasses.Offense)
{
if(SpecialPSIFlags->Poo_Starstorm_Alpha)
{
printInfo = &(psi_print_info[20]);
psiPrint_buffer(20 + 1, window, print[6 - 1], printInfo);
print[6 - 1] = false;
}
if(SpecialPSIFlags->Poo_Starstorm_Omega)
{
printInfo = &(psi_print_info[21]);
psiPrint_buffer(21 + 1, window, print[6 - 1], printInfo);
print[6 - 1] = false;
}
}
printInfo = &(psi_print_info[0]);
for(int i = 0; printInfo->PSIID != 0; i++)
{
if(psiCharacter != JEFF)
{
int val = psiCharacter == POO ? 2 : psiCharacter;
level = printInfo->levelLearnt[val];
}
if(level != 0)
{
byte *boolCmpWindowTypePrintInfo = (byte*)(&(printInfo->windowType));
if((*boolCmpWindowType) & (*boolCmpWindowTypePrintInfo))
{
if(char_data->level >= level)
{
byte *boolCmpPrintableClassesPrintInfo = (byte*)(&(printInfo->possibleClasses));
if((*boolCmpPrintableClasses) & (*boolCmpPrintableClassesPrintInfo))
{
psiPrint_buffer(i + 1, window, print[printInfo->PSIID - 1], printInfo);
print[printInfo->PSIID - 1] = false;
}
}
}
}
printInfo = &(psi_print_info[i + 1]);
}
if(psiCharacter == NESS && typeOfWindow.Character_Window && printableClasses.Other)
{
if(SpecialPSIFlags->Ness_Teleport_Alpha)
{
printInfo = &(psi_print_info[0x32]);
psiPrint_buffer(0x32 + 1, window, print[0x11 - 1], printInfo);
print[0x11 - 1] = false;
}
if(SpecialPSIFlags->Ness_Teleport_Beta)
{
printInfo = &(psi_print_info[0x33]);
psiPrint_buffer(0x33 + 1, window, print[0x11 - 1], printInfo);
print[0x11 - 1] = false;
}
}
}
void psiTargetWindow_buffer(byte target)
{
WINDOW *window = getWindow(0x9); //Target Window
PSIPrintInfo *printInfo = &(psi_print_info[target - 1]);
byte *string_group1 = (byte*)(0x8B204E4);
byte extract = (printInfo->PSIID);
byte value = 0;
byte value2 = 0;
byte *str = 0;
if(extract != 4)
{
value = (*(string_group1 + (printInfo->PSIPrintInfoID * 12)));
value = (value * 0x64);
value2 = (*(string_group1 + (printInfo->PSIPrintInfoID * 12) + 1));
value2 = (value2 * 0x14);
str = (byte*)(0x8B74390 + value + value2); //It doesn't use the pointer to the description the struct has but it obtains it like this...
}
else
str = (byte*)(0x8B74390);
printstr_hlight_buffer(window, str, 0, 0, 0);
str = m2_strlookup((int*)0x8B17EE4, (byte*)0x8B17424, 0x1B);
printstr_buffer(window, str, 0, 1, 0);
value = (*(string_group1 + (printInfo->PSIPrintInfoID * 12) + 3));
str = (window->number_text_area + 0x12);
m2_formatnumber(value, str, 2);
(*(window->number_text_area + 0x14)) = 0;
(*(window->number_text_area + 0x15)) = 0xFF;
printstr_buffer(window, str, 7, 1, 0);
}
void psiPrint_buffer(byte value, WINDOW* window, bool printPSILine, PSIPrintInfo *printInfo)
{
byte *str = 0;
byte *address = (byte*)0x3000A00;
if(printPSILine)
{
byte PSIID = printInfo->PSIID;
str = (byte*)(0x8B74228 + (PSIID * 0x14));
printstr_hlight_buffer(window, str, 0, printInfo->YPrinting << 1, 0);
if(PSIID == 1)
{
str = (byte*)(m2_ness_name + (7 * 4) + (8 * 2)); //Go to Rockin's name
print_string_in_buffer(str, 0x71, ((printInfo->YPrinting << 1) + window->window_y) << 3, (int*)(0x2014000 - 0x2000));
}
}
byte symbol = printInfo->symbol;
str = (byte*)(0x8B1B904 + (symbol * 3));
printstr_hlight_buffer(window, str, printInfo->XSymbol + 1, printInfo->YPrinting << 1, 0);
int val = ((((printInfo->XSymbol - 9) >> 0x1F) + printInfo->XSymbol - 9) >> 1) + (printInfo->YPrinting << 2);
(*(address + val)) = value;
}

46
src/c/psi.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef HEADER_PSI_INCLUDED
#define HEADER_PSI_INCLUDED
#include "vwf.h"
typedef struct PSIClasses {
bool Offense : 1;
bool Recover : 1;
bool Assist : 1;
bool Other : 1;
} PSIClasses;
typedef struct PSIWindow
{
bool Character_Window : 1;
bool Classes_Window : 1;
} PSIWindow;
typedef struct PSIPrintInfo {
byte PSIID;
byte symbol;
PSIClasses possibleClasses;
PSIWindow windowType;
unsigned short PSIPrintInfoID;
byte levelLearnt[3];
byte XSymbol;
unsigned short YPrinting;
byte *description;
} PSIPrintInfo;
typedef struct SpecialPSIFlag {
bool Ness_Teleport_Alpha : 1;
bool Poo_Starstorm_Alpha : 1;
bool Poo_Starstorm_Omega : 1;
bool Ness_Teleport_Beta : 1;
} SpecialPSIFlag;
void psiWindow_buffer(CHARACTER psiCharacter, PSIWindow typeOfWindow, PSIClasses printableClasses);
void psiTargetWindow_buffer(byte target);
void psiPrint_buffer(byte value, WINDOW* window, bool printPSILine, PSIPrintInfo *printInfo);
extern PSIPrintInfo m2_psi_print_table[];
#endif

277
src/c/status.c Normal file
View File

@ -0,0 +1,277 @@
#include "window.h"
#include "status.h"
#include "number-selector.h"
#include "locs.h"
void printNumberOfStatus(int maxLength, int value, int blankX, int y, int strX, int width)
{
byte str[0x10];
int end = setNumber_getLength(value, str, maxLength);
str[end] = 0;
str[end + 1] = 0xFF;
print_blankstr_buffer(blankX, y, width, (int*)(0x2014000 - 0x2000));
int x = (strX - (end * 6));
print_string_in_buffer(str, x, y << 3, (int*)(0x2014000 - 0x2000));
}
void printStatusSymbolArrangement(unsigned short symbolTile, WINDOW* window)
{
unsigned short *arrangementBase = ((*tilemap_pointer) + (((window->window_y) + 2) << 5) + window->window_x);
unsigned short ailmentTile = ((*tile_offset) + symbolTile) | (*palette_mask);
(*(arrangementBase + 10)) = ailmentTile;
if(symbolTile == 0x1FF)
ailmentTile -= 0x20;
(*(arrangementBase + 42)) = (ailmentTile + 0x20);
}
void printStatusString(WINDOW* window, int value)
{
byte *str = m2_strlookup((int*)0x8B17EE4, (byte*)0x8B17424, value);
printstr_hlight_buffer(window, str, 1, 2, 0);
}
int statusNumbersPrint(WINDOW* window, bool doNotPrint)
{
if ((!(window->flags_unknown3a & 0x10)) && !doNotPrint)
{
window->flags_unknown3a |= 0x10;
// Draw window header
map_tile(0xB3, window->window_x, window->window_y - 1);
clear_name_header(window);
copy_name_header(window, *active_window_party_member);
}
if(!doNotPrint)
{
m2_hpwindow_up(*active_window_party_member);
PC *character_data = &(m2_ness_data[*active_window_party_member]);
printNumberOfStatus(2, character_data->level, 0x5, 1, 0x38, 3);
printNumberOfStatus(3, character_data->hp_max, 0x10, 7, 0x93, 3);
printNumberOfStatus(3, character_data->hp_rolling, 0xC, 7, 0x78, 3);
printNumberOfStatus(3, character_data->pp_max, 0x10, 9, 0x93, 3);
printNumberOfStatus(3, character_data->pp_rolling, 0xC, 9, 0x78, 3);
printNumberOfStatus(7, character_data->experience, 0xC, 0xB, 0x93, 7);
if(character_data->level < 99)
{
unsigned int *experienceLevelTable = (unsigned int*)0x8B1EC20;
unsigned int experienceLevelUp = *(experienceLevelTable + ((*active_window_party_member) * 100) + character_data->level + 1);
printNumberOfStatus(7, experienceLevelUp - character_data->experience, 2, 0xD, 0x3D, 6);
}
else
print_blankstr_buffer(2, 0xD, 6, (int*)(0x2014000 - 0x2000));
printNumberOfStatus(3, character_data->offense_effective, 0x19, 0x1, 0xE1, 4);
printNumberOfStatus(3, character_data->defense_effective, 0x19, 0x3, 0xE1, 4);
printNumberOfStatus(3, character_data->speed_effective, 0x19, 0x5, 0xE1, 4);
printNumberOfStatus(3, character_data->guts_effective, 0x19, 0x7, 0xE1, 4);
printNumberOfStatus(3, character_data->vitality_effective, 0x19, 0x9, 0xE1, 4);
printNumberOfStatus(3, character_data->iq_effective, 0x19, 0xB, 0xE1, 4);
printNumberOfStatus(3, character_data->luck_effective, 0x19, 0xD, 0xE1, 4);
print_blankstr_buffer(5, 0xF, 0x14, (int*)(0x2014000 - 0x2000));
if((*active_window_party_member) != JEFF)
{
byte *str = m2_strlookup((int*)0x8B17EE4, (byte*)0x8B17424, 0x13);
print_string_in_buffer(str, 0x2C, (0xF) << 3, (int*)(0x2014000 - 0x2000));
}
print_blankstr_buffer(1, 0x3, 0xA, (int*)(0x2014000 - 0x2000));
unsigned short symbolTile = ailmentTileSetup(character_data, 0);
if(symbolTile == 0)
{
printStatusSymbolArrangement(0x1FF, window);
}
if(character_data->ailment != CONSCIOUS)
printStatusString(window, 0x7F + character_data->ailment);
else if(character_data->ailment2 != CONSCIOUS)
printStatusString(window, 0x86 + character_data->ailment2);
else if(character_data->homesick)
printStatusString(window, 0x89);
if(character_data->ailment != CONSCIOUS || character_data->ailment2 != CONSCIOUS || character_data->ailment3 != CONSCIOUS || character_data->strange || character_data->cant_concentrate || character_data->unknown2[0])
{
if(symbolTile == 0)
return 0;
printStatusSymbolArrangement(symbolTile, window);
return 0;
}
}
return -1;
}
int statusReadInput(WINDOW* window)
{
unsigned short previousCharacter = *active_window_party_member;
int currentCharacter = previousCharacter;
PAD_STATE state = *pad_state;
PAD_STATE state_shadow = *pad_state_shadow;
if(state.right && !window->hold)
currentCharacter += 1;
if(state.left && !window->hold)
currentCharacter -= 1;
if((state.left || state.right) && !window->hold)
{
window->unknown7 = 0;
if(state.left)
{
if(currentCharacter < 0)
currentCharacter = 3;
int foundChar = currentCharacter;
for(int i = 0; i < 4; i++)
{
if (foundChar < 0)
foundChar = 3;
if ((*pc_flags)[foundChar])
break;
foundChar--;
}
currentCharacter = foundChar;
}
else
{
if(currentCharacter > 3)
currentCharacter = 0;
int foundChar = currentCharacter;
for(int i = 0; i < 4; i++)
{
if (foundChar > 3)
foundChar = 0;
if ((*pc_flags)[foundChar])
break;
foundChar++;
}
currentCharacter = foundChar;
}
m2_hpwindow_up(currentCharacter);
clear_name_header(window);
copy_name_header(window, currentCharacter);
(*active_window_party_member) = currentCharacter;
if(currentCharacter != previousCharacter)
statusNumbersPrint(window, false);
}
if(state_shadow.right || state_shadow.left)
{
if(state.right || state.left)
{
int flag = *window_flags;
if(flag & 0x800)
{
if(currentCharacter != previousCharacter)
m2_soundeffect(0x131);
}
else if(currentCharacter != previousCharacter)
m2_soundeffect(0x12E);
}
window->hold = true;
}
else
window->hold = false;
if(state.b || state.select)
{
m2_soundeffect(0x12E);
window->counter = 0;
return ACTION_STEPOUT;
}
else if(state.a || state.l)
{
m2_soundeffect(0x12D);
if(currentCharacter != JEFF)
{
if((*pc_count) > 1)
{
unsigned short *arrangementBase = (*tilemap_pointer) + (((window->window_y - 1) << 5) + window->window_x + window->window_width - 4);
unsigned short topTile = ((*tile_offset) + 0x96) | (*palette_mask) | 0x800;
(*arrangementBase) = topTile;
(*(arrangementBase + 1)) = topTile;
(*(arrangementBase + 2)) = topTile;
(*(arrangementBase + 3)) = topTile;
}
window->counter = 0;
return 1;
}
else
return 0;
}
window->counter++;
if (*pc_count > 1)
{
// We're doing a bit of simplification here.
// The Japanese version tries to highlight the arrow you pressed.
// It only shows for a couple frames and it looks weird, so we're
// just going to show the arrows and not bother with the direction indicator.
draw_window_arrows(window, window->counter < 8);
}
if (window->counter > 16)
window->counter = 0;
return ACTION_NONE;
}
int statusWindowNumbers(WINDOW* window, bool doNotPrint)
{
if(statusNumbersPrint(window, doNotPrint) == 0)
return 0;
return statusReadInput(window);
}
int statusWindowText(WINDOW* window)
{
if(window->redraw)
buffer_drawwindow(window, (int*)(0x2014000 - 0x2000));
if(window->loaded_code != 0 && ((*script_readability) == 0))
{
window->delay = 0;
while(true)
{
while(window->text_y >= window->window_height || window->window_y + window->text_y > 0x1F)
properScroll(window, (int*)(0x2014000 - 0x2000));
byte *str = window->text_start + window->text_offset;
if((*(str + 1)) == 0xFF)
{
int returnedLength = customcodes_parse_generic(*str, str, window, (int*)(0x2014000 - 0x2000));
if(returnedLength != 0)
{
if(returnedLength < 0)
returnedLength = 0;
window->text_offset += returnedLength;
}
else
{
if((*str) == 1)
{
window->text_y += 2;
window->text_x = 0;
window->text_offset += 2;
}
else if((*str) == 0)
{
window->loaded_code = 0;
break;
}
else
window->text_offset++;
}
}
else
{
if(window->text_x >= window->window_width || window->window_x + window->text_x > 0x1F)
{
window->text_y += 2;
window->text_x = 0;
}
weld_entry_custom_buffer(window, str, 0, 0xF, (int*)(0x2014000 - 0x2000));
window->text_offset++;
}
}
}
return 0;
}

14
src/c/status.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef HEADER_STATUS_INCLUDED
#define HEADER_STATUS_INCLUDED
#include "vwf.h"
void printNumberOfStatus(int maxLength, int value, int blankX, int y, int strX, int width);
void printStatusSymbolArrangement(unsigned short symbolTile, WINDOW* window);
void printStatusString(WINDOW* window, int value);
int statusNumbersPrint(WINDOW* window, bool doNotPrint);
int statusReadInput(WINDOW* window);
int statusWindowNumbers(WINDOW* window, bool doNotPrint);
int statusWindowText(WINDOW* window);
#endif

View File

@ -156,12 +156,12 @@ byte print_character_formatted(byte chr, int x, int y, int font, int foreground)
return 8;
}
return print_character_with_callback(chr, x, y, font, foreground, vram, &get_tile_number_with_offset, *tilemap_pointer, 32);
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);
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.
@ -199,7 +199,7 @@ void map_tile(unsigned short tile, int x, int y)
}
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)
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];
@ -216,10 +216,19 @@ byte print_character_with_callback(byte chr, int x, int y, int font, int foregro
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)
{
@ -228,10 +237,13 @@ byte print_character_with_callback(byte chr, int x, int y, int font, int foregro
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) & 7)];
int canvasRow = dest[(realTileIndex * 8) + ((row + offsetY - sumRemoved) & 7)];
byte glyphRow = glyphRows[row + (dTileY * 8 * tileWidth) + (dTileX * 8)] & ((1 << leftPortionWidth) - 1);
glyphRow <<= (8 - leftPortionWidth);
@ -244,9 +256,21 @@ byte print_character_with_callback(byte chr, int x, int y, int font, int foregro
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) & 7)] = canvasRow;
if(offsetY != 0 && ((row + offsetY) == 7))
realTileIndex = getTileCallback(tileX + dTileX, tileY + dTileY + 1);
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)
@ -264,10 +288,13 @@ byte print_character_with_callback(byte chr, int x, int y, int font, int foregro
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) & 7)];
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);
@ -279,9 +306,20 @@ byte print_character_with_callback(byte chr, int x, int y, int font, int foregro
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) & 7)] = canvasRow;
if(offsetY != 0 && ((row + offsetY) == 7))
realTileIndex = getTileCallback(tileX + dTileX + 1, tileY + dTileY + 1);
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)
@ -793,6 +831,29 @@ int player_name_printing_registration(byte* str, WINDOW* window)
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);
}
}
int get_pointer_jump_back(byte *character)
{
byte *address1 = ((byte*)0x3004F24);
@ -823,7 +884,7 @@ void print_letter_in_buffer(WINDOW* window, byte* character, int* dest)
int print_window_with_buffer(WINDOW* window)
{
int delay = 0;
if((window->loaded_code != 0) && (m2_script_readability == 0))
if((window->loaded_code != 0) && ((*script_readability) == 0))
{
if(window->delay_between_prints == 0)
delay = 0;
@ -1110,7 +1171,7 @@ byte print_character_formatted_buffer(byte chr, int x, int y, int font, int fore
return 8;
}
return print_character_with_callback(chr, x, y, font, foreground, dest, &get_tile_number_with_offset, *tilemap_pointer, 32);
return print_character_with_callback(chr, x, y, font, foreground, dest, &get_tile_number_with_offset, *tilemap_pointer, 32, 0xC);
}
void weld_entry_custom_buffer(WINDOW *window, byte *str, int font, int foreground, int* dest)
@ -1126,29 +1187,6 @@ void weld_entry_custom_buffer(WINDOW *window, byte *str, int font, int foregroun
window->text_x = (x >> 3) - window->window_x;
}
// 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);
}
}
void handle_first_window_buffer(WINDOW* window, int* dest)
{
if (*first_window_flag == 1)
@ -1260,39 +1298,31 @@ WINDOW* getWindow(int index)
return window_pointers[index];
}
void psiTargetWindow_buffer(byte target)
int initWindow_buffer(WINDOW* window, byte* text_start, unsigned short delay_between_prints)
{
WINDOW *window = getWindow(0x9); //Target Window
byte *string_group = (byte*)(0x8B2A9B0);
byte *string_group1 = (byte*)(0x8B204E4);
byte extract = (*(string_group +(target << 4)));
byte value = 0;
byte value2 = 0;
unsigned short val = 0;
byte *str = 0;
if(extract != 4)
{
val = (*(string_group + (target << 4) + 4)) + ((*(string_group + (target << 4) + 5)) << 8);
value = (*(string_group1 + (val * 12)));
value = (value * 0x64);
value2 = (*(string_group1 + (val * 12) + 1));
value2 = (value2 * 0x14);
str = (byte*)(0x8B74390 + value + value2);
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, (int*)(0x2014000 - 0x2000));
return 0;
}
else
str = (byte*)(0x8B74390);
printstr_hlight_buffer(window, str, 0, 0, 0);
str = m2_strlookup((int*)0x8B17EE4, (byte*)0x8B17424, 0x1B);
printstr_buffer(window, str, 0, 1, 0);
val = (*(string_group + (target << 4) + 4)) + ((*(string_group + (target << 4) + 5)) << 8);
value = (*(string_group1 + (val * 12) + 3));
str = (window->number_text_area + 0x12);
m2_formatnumber(value, str, 2);
(*(window->number_text_area + 0x14)) = 0;
(*(window->number_text_area + 0x15)) = 0xFF;
printstr_buffer(window, str, 7, 1, 0);
void clearWindowTiles_buffer(WINDOW* window)
{
clear_window_buffer(window, (int*)(0x2014000 - 0x2000));
window->text_x = 0;
window->text_y = 0;
}
// x,y: tile coordinates
@ -1359,12 +1389,12 @@ int buffer_drawwindow(WINDOW* window, int* dest)
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 * 32)];
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 * 32) + 1 + window->window_width];
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)
@ -1396,6 +1426,107 @@ int buffer_drawwindow(WINDOW* window, int* dest)
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(PC *character, unsigned short defaultVal)
{
int value = defaultVal;
byte flagValue = 0;
if(character->ailment == CONSCIOUS)
{
if(character->ailment2 != CONSCIOUS)
{
flagValue = character->ailment2;
value = 1;
}
else if(character->ailment3 != CONSCIOUS)
{
flagValue = character->ailment3;
value = 2;
}
else if(character->strange)
{
flagValue = character->strange;
value = 3;
}
else if(character->cant_concentrate)
{
flagValue = character->cant_concentrate;
value = 4;
}
else if(character->homesick)
{
flagValue = character->homesick;
value = 5;
}
else if(character->unknown2[0])
{
flagValue = character->unknown2[0];
value = 6;
}
else
return 0;
}
else
{
value = 0;
flagValue = character->ailment;
}
unsigned short *returnValues = (unsigned short*)0x8B1F2E4;
return (*(returnValues + (value * 7) + flagValue - 1));
}
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();
}
// x, y, width: tile coordinates
void print_blankstr_buffer(int x, int y, int width, int *dest)
{
clear_rect_buffer(x, y, width, 2, WINDOW_AREA_BG, dest);
}
// x,y: tile coordinates
void copy_tile_buffer(int xSource, int ySource, int xDest, int yDest, int *dest)
{

View File

@ -39,7 +39,7 @@ void print_special_character(int tile, int x, int y);
void map_special_character(unsigned short tile, int x, int y);
void map_tile(unsigned short tile, int x, int y);
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);
int *dest, int (*getTileCallback)(int, int), unsigned short *tilemapPtr, int tilemapWidth, byte doubleTileHeight);
byte print_character_to_ram(byte chr, int *dest, int xOffset, int font, int foreground);
int print_window_header_string(int *dest, byte *str, int x, int y);
void clear_window_header(int *dest, int length, int x, int y);
@ -92,6 +92,16 @@ int jumpToOffset(byte* character);
void copy_tile_buffer(int xSource, int ySource, int xDest, int yDest, int *dest);
void copy_tile_up_buffer(int x, int y, int *dest);
void setStuffWindow_Graphics();
void clearWindowTiles_buffer(WINDOW* window);
int initWindow_buffer(WINDOW* window, byte* text_start, unsigned short delay_between_prints);
void print_blankstr_buffer(int x, int y, int width, int *dest);
unsigned short ailmentTileSetup(PC *character, unsigned short defaultVal);
int setNumber_getLength(int value, byte *str, int maxLength);
int print_string_in_buffer(byte *str, int x, int y, int *dest);
void printCashWindow();
WINDOW* getWindow(int index);
void printstr_buffer(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight);
unsigned short printstr_hlight_buffer(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight);
extern unsigned short m2_coord_table[];
extern byte m2_ness_name[];
@ -107,6 +117,7 @@ extern byte m12_other_str7[];
extern byte m12_other_str8[];
extern byte m2_cstm_last_printed[];
extern byte *m2_script_readability;
extern PC m2_ness_data[];
extern void cpufastset(void *source, void *dest, int mode);
extern byte* m2_strlookup(int *offset_table, byte *strings, int index);
@ -120,3 +131,5 @@ extern int m2_remainder(int dividend, int divisor);
extern void m2_soundeffect(int index);
extern void m2_printstr(WINDOW* window, byte* str, unsigned short x, unsigned short y, bool highlight);
extern int customcodes_parse_generic(int code, char* parserAddress, WINDOW* window, int* dest);
extern void m2_sub_d3c50();
extern void m2_sub_d6844();

View File

@ -3,6 +3,13 @@
#include "types.h"
typedef enum WINDOW_ACTION
{
ACTION_NONE = 0,
ACTION_STEPIN = 1,
ACTION_STEPOUT = -1
} WINDOW_ACTION;
typedef struct WINDOW {
// 0x00
bool enable : 1; // 0x0001 Indicates that the window is enabled.

Binary file not shown.

View File

@ -14,6 +14,7 @@
//==============================================================================
.org 0x8AFED84 :: .incbin "data/m2-mainfont1-empty.bin"
.org 0x8B03DE4 :: .incbin "data/m2-status-symbols.bin"
.org 0x8B0F424 :: .incbin "data/m2-mainfont2-empty.bin"
.org 0x8B13424 :: .incbin "data/m2-mainfont3-empty.bin"
.org 0x8B088A4 :: .incbin "data/m2-shifted-cursor.bin"
@ -49,17 +50,47 @@ mov r3,6
.include "m2-status-initial.asm"
.include "m2-status-switch.asm"
//---------------------------------------------------------
// Main window hacks
//---------------------------------------------------------
.org 0x80B7D9A :: bl b7d9a_main_window_manage_input
//.org 0x80B8A36 :: bl initWindow_buffer //Money window
//.org 0x80B8A3C :: bl print_window_with_buffer
.org 0x80B8890 :: bl print_window_with_buffer :: bl b8894_printCashWindowAndStore //Main window + Cash Window out of Status menu
.org 0x80B831A :: bl initWindow_buffer
.org 0x80B8320 :: bl b8320_statusWindowTextStore
//---------------------------------------------------------
// BAC18 hacks (status window)
//---------------------------------------------------------
.org 0x80BACFC :: bl bac18_redraw_status
.org 0x80BAC46 :: nop :: nop
.org 0x80BAC6E :: bl bac6e_statusWindowNumbersInputManagement
.org 0x80BAD7E :: bl printstr_buffer
.org 0x80BAD88 :: bl initWindow_buffer
.org 0x80BAD92 :: bl initWindow_buffer
.org 0x80BACFC :: bl bac18_redraw_status_store
.org 0x80BADE6 :: bl bac18_redraw_status
.org 0x80BACEA :: bl bacea_status_psi_window
.org 0x80BACBA :: bl print_window_with_buffer
.org 0x80BACC4 :: bl initWindow_buffer
.org 0x80BAD1A :: bl clearWindowTiles_buffer
.org 0x80BADF6 :: bl initWindow_buffer
.org 0x80BACEE :: bl bac18_clear_psi
.org 0x80BADB0 :: bl badb0_status_inner_window
.org 0x80BADCC :: b 0x80BADD8
//---------------------------------------------------------
// PSI window hacks
//---------------------------------------------------------
.org 0x80BAE1C :: bl print_window_with_buffer
.org 0x80BAEC6 :: bl baec6_psi_window_print_buffer
.org 0x80BAED4 :: bl baec6_psi_window_print_buffer
.org 0x80BAEE2 :: bl baec6_psi_window_print_buffer
.org 0x80BAEF0 :: bl baec6_psi_window_print_buffer
//---------------------------------------------------------
// BAEF8 hacks (equip window)
//---------------------------------------------------------
@ -1511,12 +1542,15 @@ m2_coord_table_file:
.definelabel m2_clearwindowtiles ,0x80CA834
.definelabel m2_menuwindow ,0x80C1C98
.definelabel m2_resetwindow ,0x80BE490
.definelabel m2_sub_d3c50 ,0x80D3C50
.definelabel m2_hpwindow_up ,0x80D3F0C
.definelabel m2_curhpwindow_down ,0x80D41D8
.definelabel m2_sub_d6844 ,0x80D6844
.definelabel m2_div ,0x80F49D8
.definelabel m2_remainder ,0x80F4A70
.definelabel m2_default_names ,0x82B9330
.definelabel m2_items ,0x8B1D62C
.definelabel m2_default_names ,0x82B9330
.definelabel m2_psi_print_table ,0x8B2A9C0
//==============================================================================
// Code files

View File

@ -330,20 +330,50 @@ bl 0x80BE260
mov r1,r0
mov r0,r4
mov r2,0
bl 0x80BE458
bl initWindow_buffer
// Render text
mov r0,r4
bl 0x80C8FFC
bl statusWindowText
// Render numbers
mov r0,r4
ldrh r1,[r0,#0]
ldr r2,=#0xFBFF
and r1,r2
strh r1,[r0,#0]
mov r1,0
bl 0x80C0A5C
bl statusNumbersPrint
pop {r4,pc}
.pool
//==============================================================================
// Redraws the status window (when exiting the PSI menu) and stores it
bac18_redraw_status_store:
push {lr}
bl bac18_redraw_status
bl store_pixels_overworld
pop {pc}
.pool
//==============================================================================
// Only if the character changed store the buffer - called when reading inputs
bac6e_statusWindowNumbersInputManagement:
push {lr}
ldr r2,=#m2_active_window_pc
ldrb r2,[r2,#0]
push {r2}
bl statusWindowNumbers
pop {r2}
ldr r1,=#m2_active_window_pc
ldrb r1,[r1,#0]
cmp r1,r2
beq @@end
bl store_pixels_overworld
@@end:
pop {pc}
//==============================================================================
// Clears the PSI window when switching classes
@ -359,7 +389,8 @@ beq @@next
// If flag 0x10 is set, clear the PSI window
ldr r0,[r5,0x1C] // PSI window
bl clear_window
ldr r1,=#0x2012000
bl clear_window_buffer
@@next:
// Clobbered code
@ -1761,7 +1792,6 @@ strb r2,[r0,#3]
b @@end //Goes to the end of the routine
@@goToInner:
bl load_pixels_overworld
lsl r0,r0,0x10 //Properly stores the output into r4 and, since we're going into the inner window, sets vwf_skip to false
asr r4,r0,0x10
ldr r0,[r5,#0x20]
@ -1884,7 +1914,7 @@ cmp r1,#0 //Checks if vwf_skip is false
bne @@end
mov r1,r2 //If it is, prints the PSI description
mov r2,0
bl m2_initwindow //Initializes the PSI description window
bl initWindow_buffer //Initializes the PSI description window
ldr r0,[r5,0x28]
bl print_window_with_buffer //Prints the PSI description window
bl store_pixels_overworld
@ -2088,6 +2118,28 @@ pop {pc}
.pool
//==============================================================================
//Prints and stores the PSI window in the PSI menu
baec6_psi_window_print_buffer:
push {lr}
bl psiWindow_buffer
bl store_pixels_overworld
pop {pc}
//==============================================================================
//Loads the buffer in if entering another window from the main window
b7d9a_main_window_manage_input:
push {lr}
bl 0x80BE53C
cmp r0,#0
beq @@end
cmp r0,#0
blt @@end
bl load_pixels_overworld
@@end:
pop {pc}
//==============================================================================
//Prints the target window if and only if the cursor's position changed in this input management function
c495a_status_target:
@ -2724,6 +2776,34 @@ pop {pc}
.pool
//==============================================================================
//Prints the cash window and then stores the buffer to vram
b8894_printCashWindowAndStore:
push {lr}
bl printCashWindow
bl store_pixels_overworld
pop {pc}
//==============================================================================
//UNUSED
bac46_statusWindowNumbersStore:
push {lr}
bl statusWindowNumbers
bl store_pixels_overworld
pop {pc}
//==============================================================================
//Prints the status text and numbers in the buffer, then loads it in vram
b8320_statusWindowTextStore:
push {lr}
push {r0}
bl statusWindowText
pop {r0}
mov r1,#0
bl statusNumbersPrint
bl store_pixels_overworld
pop {pc}
//==============================================================================
//Loads the vram into the buffer, it's called each time there is only the main file_select window active (a good way to set the whole thing up)
load_pixels_overworld:
@ -2733,7 +2813,7 @@ ldr r0,=#0x6002000 //Source
str r0,[r1]
ldr r0,=#0x2014000 //Target
str r0,[r1,#4]
ldr r0,=#0xA4001000 //Store 0x4000 bytes - When VBlank and in words of 32 bits
ldr r0,=#0xA4001000 //Store 0x4000 bytes - When HBlank and in words of 32 bits
str r0,[r1,#8]
ldr r0,[r1,#8]
pop {r0-r1,pc}