diff --git a/README.md b/README.md index f544b97..3970742 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ A few years after that, I tried it again from scratch with the intent of having This project aims to both complete the VWF codebase and to provide a tool for translating the game's dialogue. My new intent is to bring the hack to a state where I can just sit down and translate text efficiently in my spare time with a graphical tool. Not only that, but having such a tool means that other people can contribute! ## Screenshots -![](./screenshots/itshappening2.png) ![](./screenshots/itshappening4.png) ![](./screenshots/itshappening5.png) ![](./screenshots/m2-status2.png) +![](./screenshots/itshappening2.png) ![](./screenshots/itshappening4.png) ![](./screenshots/itshappening5.png) ![](./screenshots/m2-status2.png) ![](./screenshots/m2-battle-slugs.png) ![](./screenshots/m2-fileselect.png) # Building @@ -52,7 +52,7 @@ This project aims to both complete the VWF codebase and to provide a tool for tr - Windows: grab the latest release [here](https://github.com/Kingcom/armips/releases) and copy the executable to `bin/armips.exe`. - Linux: follow the [README](https://github.com/Kingcom/armips/blob/master/Readme.md) to build `armips` and copy the executable to `bin/armips`. 2. Building the ROM - 1. Run `build.ps1` (like in Step 4). + 1. Run `build.ps1`. 2. The default compiled ROM is copied to `bin/m12.gba`. 3. (Optional) Build the GUI script tool: 1. `dotnet build tools/ScriptTool` (don't set the output directory) diff --git a/screenshots/m2-battle-slugs.png b/screenshots/m2-battle-slugs.png new file mode 100644 index 0000000..f7f7e1f Binary files /dev/null and b/screenshots/m2-battle-slugs.png differ diff --git a/screenshots/m2-fileselect.png b/screenshots/m2-fileselect.png new file mode 100644 index 0000000..44e07cf Binary files /dev/null and b/screenshots/m2-fileselect.png differ diff --git a/src/c/vwf.c b/src/c/vwf.c index 6ff4f4d..c195354 100644 --- a/src/c/vwf.c +++ b/src/c/vwf.c @@ -22,7 +22,9 @@ int get_tile_number(int x, int y) { x--; y--; - return m2_coord_table[x + ((y >> 1) * 28)] + (y & 1) * 32; + if(y > 0xF) + y = 0xE + (y & 1); + return m2_coord_table[x + ((y >> 1) * 28)] + (y & 1) * 32; //This is... Very not suited for tilemaps of variable width, which can have more than 0x10 tiles vertically. } int get_tile_number_with_offset(int x, int y) @@ -52,14 +54,107 @@ byte reduce_bit_depth(int row, int foreground) return lower | (upper << 4); } -void print_file_string(int x, int y, int length, byte *str, int unknown) +// x,y: tile coordinates +void clear_tile_file(int x, int y, int pixels, int tile_offset_file) { - int *tilesetBasePtr = (int *)(0x82B79B4 + (unknown * 20)); + // Clear pixels + int tileIndex = get_tile_number(x, y) + tile_offset_file; + if(((tileIndex << 3) != (0xC9C0 >> 2)) && ((tileIndex << 3) != (0xC9E0 >> 2))) + cpufastset(&pixels, &vram[tileIndex * 8], CPUFASTSET_FILL | 8); +} + +// x,y: tile coordinates +void clear_rect_file(int x, int y, int width, int height, int pixels, int tile_offset_file, unsigned short *tilesetDestPtr) +{ + for (int tileY = 0; tileY < height; tileY++) + { + for (int tileX = 0; tileX < width; tileX++) + { + if((tilesetDestPtr[x + tileX + ((y + tileY) * width)] & 0x3FF) != 0x95) + clear_tile_file(x + tileX, y + tileY, pixels, tile_offset_file); + else + break; + } + } +} + +void wrapper_file_string(int x, int y, int length, byte *str, int window_selector) +{ + m2_cstm_last_printed[0] = window_selector; //First time setup + print_file_string(x, y, length, str, window_selector, 0); +} + +void wrapper_delete_string(int x, int y, int length, byte *str, int window_selector) +{ + print_file_string(x, y, length, str - 0x20 + 0x40 - 0x15, window_selector, 0x6000); +} + +void wrapper_name_string(int x, int y, int length, byte *str, int window_selector) +{ + char String[length]; + for(int i = 0; i < length; i++) + { + if(str[i] == 0xFD) + String[i] = 0x70; + else if(str[i] == 0xF1) + String[i] = 0x53; + else + String[i] = str[i]; + } + print_file_string(x, y, length, String, window_selector, 0x7800); +} + +void wrapper_name_summary_string(int x, int y, int length, byte *str, int window_selector) +{ + char String[length]; + for(int i = 0; i < length; i++) + String[i] = str[i]; + print_file_string(x, y, length, String, window_selector, 0x2800); +} + +int count_pixels(byte *str, int length) +{ + int pixels = 0; + 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); + int tiles = pixels >> 3; + if((pixels & 7) != 0) + tiles +=1; + return tiles; +} + +void wrapper_copy_string(int x, int y, int length, byte *str, int window_selector) +{ + print_file_string(x, y, length, str, window_selector, 0x6000); +} + +void clearArr(int x, int y, int width, unsigned short *tilesetDestPtr) +{ + for(int i = x; i < width - 2; i++) + { + if((tilesetDestPtr[i + (y * width)] & 0x3FF) != 0x95) + { + tilesetDestPtr[i + (y * width)] = 0x13F; + tilesetDestPtr[i + ((y+1) * width)] = 0x13F; + } + else + break; + } +} + +void print_file_string(int x, int y, int length, byte *str, int window_selector, int offset) +{ + int *tilesetBasePtr = (int *)(0x82B79B4 + (window_selector * 20)); int width = tilesetBasePtr[2]; unsigned short *tilesetDestPtr = (unsigned short *)(tilesetBasePtr[0]); - + clearArr(x, y, width, tilesetDestPtr); //Cleans all of the arrangements this line could ever use + int pixelX = x * 8; - int pixelY = y * 8; + int pixelY = (y * 8) + 3; + int realmask = *palette_mask; + *palette_mask = 0; //File select is special and changes its palette_mask on the fly. + clear_rect_file(x, y, width, 2, 0x11111111, 0x400 + (offset >> 5), tilesetDestPtr); //Clean the rectangle before printing for (int i = 0; i < length; i++) { @@ -93,15 +188,500 @@ void print_file_string(int x, int y, int length, byte *str, int unknown) pixelY, 0, 9, - vram + 0x2000, + vram + 0x2000 + (offset >> 2), &get_tile_number, tilesetDestPtr, - width); + width, + (offset >>5)); pixelX += pixels; } + *palette_mask = realmask; } +void format_options_cc(char String[], int *index, byte cmd) +{ + String[(*index)++] = 0xFE; + String[(*index)++] = cmd; +} + +void options_setup(char String[]) +{ + int index = 0; + char Continue[] = "Continue"; + for(int i = 0; i < (sizeof(Continue) -1); i++) + String[index++] = encode_ascii(Continue[i]); + + // Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = 64; + + char Copy[] = "Copy"; + for(int i = 0; i < (sizeof(Copy) -1); i++) + String[index++] = encode_ascii(Copy[i]); + + // Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = 97; + + char Delete[] = "Delete"; + for(int i = 0; i < (sizeof(Delete) -1); i++) + String[index++] = encode_ascii(Delete[i]); + + // Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = 137; + + char Setup[] = "Set Up"; + for(int i = 0; i < (sizeof(Setup) -1); i++) + String[index++] = encode_ascii(Setup[i]); + + //END + String[index++] = 0xFF; +} + +void text_speed_setup(char String[], int selector) +{ + int index = 0; + char Text_Speed[] = "Please select text speed."; + char Medium[] = "Medium"; + char Fast[] = "Fast"; + char Slow[] = "Slow"; + switch(selector) + { + case 0: + for(int i = 0; i < (sizeof(Text_Speed) -1); i++) + String[index++] = encode_ascii(Text_Speed[i]); + break; + case 1: + for(int i = 0; i < (sizeof(Fast) -1); i++) + String[index++] = encode_ascii(Fast[i]); + break; + case 2: + for(int i = 0; i < (sizeof(Medium) -1); i++) + String[index++] = encode_ascii(Medium[i]); + break; + default: + for(int i = 0; i < (sizeof(Slow) -1); i++) + String[index++] = encode_ascii(Slow[i]); + break; + } + //END + String[index++] = 0xFF; +} + +void delete_setup(char String[], int selector) +{ + int index = 0; + char Delete[] = "Are you sure you want to delete?"; + char No[] = "No"; + char Yes[] = "Yes"; + switch(selector) + { + case 0: + for(int i = 0; i < (sizeof(Delete) -1); i++) + String[index++] = encode_ascii(Delete[i]); + break; + case 1: + for(int i = 0; i < (sizeof(No) -1); i++) + String[index++] = encode_ascii(No[i]); + break; + default: + for(int i = 0; i < (sizeof(Yes) -1); i++) + String[index++] = encode_ascii(Yes[i]); + break; + } + //END + String[index++] = 0xFF; +} + +void text_flavour_setup(char String[], int selector) +{ + int index = 0; + char Text_Flavour_1[] = "Which style of windows"; + char Text_Flavour_2[] = "do you prefer?"; + char Plain[] = "Plain flavor"; + char Mint[] = "Mint flavor"; + char Strawberry[] = "Strawberry flavor"; + char Banana[] = "Banana flavor"; + char Peanut[] = "Peanut flavor"; + switch(selector) + { + case 0: + for(int i = 0; i < (sizeof(Text_Flavour_1) -1); i++) + String[index++] = encode_ascii(Text_Flavour_1[i]); + break; + case 1: + for(int i = 0; i < (sizeof(Text_Flavour_2) -1); i++) + String[index++] = encode_ascii(Text_Flavour_2[i]); + break; + case 2: + for(int i = 0; i < (sizeof(Plain) -1); i++) + String[index++] = encode_ascii(Plain[i]); + break; + case 3: + for(int i = 0; i < (sizeof(Mint) -1); i++) + String[index++] = encode_ascii(Mint[i]); + break; + case 4: + for(int i = 0; i < (sizeof(Strawberry) -1); i++) + String[index++] = encode_ascii(Strawberry[i]); + break; + case 5: + for(int i = 0; i < (sizeof(Banana) -1); i++) + String[index++] = encode_ascii(Banana[i]); + break; + default: + for(int i = 0; i < (sizeof(Peanut) -1); i++) + String[index++] = encode_ascii(Peanut[i]); + break; + } + //END + String[index++] = 0xFF; +} + +void description_setup(char String[], int selector) +{ + int index = 0; + char Ness[] = "Please name him."; + char Paula[] = "Name her, too."; + char Jeff[] = "Name your friend."; + char Poo[] = "Name another friend."; + char King[] = "Name your pet."; + char FavFood[] = "Favorite homemade food?"; + char FavThing[] = "What's your favorite thing?"; + switch(selector) + { + case 3: + for(int i = 0; i < (sizeof(Ness) -1); i++) + String[index++] = encode_ascii(Ness[i]); + break; + case 4: + for(int i = 0; i < (sizeof(Paula) -1); i++) + String[index++] = encode_ascii(Paula[i]); + break; + case 5: + for(int i = 0; i < (sizeof(Jeff) -1); i++) + String[index++] = encode_ascii(Jeff[i]); + break; + case 6: + for(int i = 0; i < (sizeof(Poo) -1); i++) + String[index++] = encode_ascii(Poo[i]); + break; + case 7: + for(int i = 0; i < (sizeof(King) -1); i++) + String[index++] = encode_ascii(King[i]); + break; + case 8: + for(int i = 0; i < (sizeof(FavFood) -1); i++) + String[index++] = encode_ascii(FavFood[i]); + break; + default: + for(int i = 0; i < (sizeof(FavThing) -1); i++) + String[index++] = encode_ascii(FavThing[i]); + break; + } + //END + String[index++] = 0xFF; +} + +void copy_setup(char String[]) +{ + int index = 0; + char Copy[] = "Copy to where?"; + for(int i = 0; i < (sizeof(Copy) -1); i++) + String[index++] = encode_ascii(Copy[i]); + //END + String[index++] = 0xFF; +} + +void letterSetup(char String[], int selector, bool capital, int *index) +{ + char base = capital ? 'A' : 'a'; + int value = 9 - (selector >> 1); + for(int i = 0; i < value; i++) + { + String[(*index)++] = encode_ascii(base + i + (selector * 9)); + // Re-position + format_options_cc(String, &(*index), CUSTOMCC_SET_X); + if(i != value -1) + String[(*index)++] = (2 * (i + 2)) << 3; + else + String[(*index)++] = (24) << 3; + } + switch(selector) + { + case 0: + String[(*index)++] = 93; + // Re-position + format_options_cc(String, &(*index), CUSTOMCC_SET_X); + String[(*index)++] = (26) << 3; + String[(*index)++] = 83; + break; + case 1: + String[(*index)++] = 87; + // Re-position + format_options_cc(String, &(*index), CUSTOMCC_SET_X); + String[(*index)++] = (26) << 3; + String[(*index)++] = 174; + break; + default: + String[(*index)++] = 94; + // Re-position + format_options_cc(String, &(*index), CUSTOMCC_SET_X); + String[(*index)++] = (26) << 3; + String[(*index)++] = 95; + break; + } +} +void numbersSetup(char String[], int *index) +{ + char base = '0'; + for(int i = 0; i < 10; i++) + { + String[(*index)++] = encode_ascii(base + i); + // Re-position + format_options_cc(String, &(*index), CUSTOMCC_SET_X); + if(i != 9) + String[(*index)++] = (2 * (i + 2)) << 3; + else + String[(*index)++] = (24) << 3; + } + String[(*index)++] = 81; + // Re-position + format_options_cc(String, &(*index), CUSTOMCC_SET_X); + String[(*index)++] = (26) << 3; + String[(*index)++] = 0xAC; +} + +void alphabet_setup(char String[], int selector, bool capital) +{ + int index = 0; + char Capital[] = "CAPITAL"; + char Small[] = "small"; + char DontCare[] = "Don't Care"; + char Backspace[] = "Backspace"; + char Ok[] = "OK"; + switch(selector) + { + case 0: + case 1: + case 2: + letterSetup(String, selector, capital, &index); + break; + case 3: + numbersSetup(String, &index); + break; + case 4: + for(int i = 0; i < (sizeof(Capital) -1); i++) + String[index++] = encode_ascii(Capital[i]); + //Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = (9) << 3; + for(int i = 0; i < (sizeof(Small) -1); i++) + String[index++] = encode_ascii(Small[i]); + //Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = (24) << 3; + String[index++] = 111; + // Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = (26) << 3; + String[index++] = 0xAF; + break; + default: + for(int i = 0; i < (sizeof(DontCare) -1); i++) + String[index++] = encode_ascii(DontCare[i]); + //Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = (19) << 3; + for(int i = 0; i < (sizeof(Backspace) -1); i++) + String[index++] = encode_ascii(Backspace[i]); + //Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = (27) << 3; + for(int i = 0; i < (sizeof(Ok) -1); i++) + String[index++] = encode_ascii(Ok[i]); + break; + } + //END + String[index++] = 0xFF; +} + +void summary_setup(char String[], int selector) +{ + int index = 0; + char FavFood[] = "Favorite food:"; + char FavThing[] = "Coolest thing:"; + char AreYouSure[] = "Are you sure?"; + char Yep[] = "Yep"; + char Nope[] = "Nope"; + switch(selector) + { + case 0: + for(int i = 0; i < (sizeof(FavFood) -1); i++) + String[index++] = encode_ascii(FavFood[i]); + break; + case 1: + for(int i = 0; i < (sizeof(FavThing) -1); i++) + String[index++] = encode_ascii(FavThing[i]); + break; + default: + for(int i = 0; i < (sizeof(AreYouSure) -1); i++) + String[index++] = encode_ascii(AreYouSure[i]); + //Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = (0x10) << 3; + for(int i = 0; i < (sizeof(Yep) -1); i++) + String[index++] = encode_ascii(Yep[i]); + //Re-position + format_options_cc(String, &index, CUSTOMCC_SET_X); + String[index++] = (0x14) << 3; + for(int i = 0; i < (sizeof(Nope) -1); i++) + String[index++] = encode_ascii(Nope[i]); + break; + } + //END + String[index++] = 0xFF; +} + +void print_windows(int window_selector) +{ + char String[64]; + int offset = 0; + switch(window_selector) + { + case 0x10: //Delete + offset = 0x6000; + delete_setup(String, 0); + print_file_string(1, 1, 0x40, String, window_selector, offset); + delete_setup(String, 1); + print_file_string(2, 5, 0x40, String, window_selector, offset); + delete_setup(String, 2); + print_file_string(2, 7, 0x40, String, window_selector, offset); + m2_cstm_last_printed[0] = window_selector | (m2_cstm_last_printed[0] & 0x20); + break; + case 0xE: //Options + offset = 0x1800; + options_setup(String); + print_file_string(2, 1, 0x40, String, window_selector, offset); + m2_cstm_last_printed[0] = window_selector | (m2_cstm_last_printed[0] & 0x20); + break; + case 1: //Text Speed + if(((m2_cstm_last_printed[0] & 0x1F) != 2) && ((m2_cstm_last_printed[0] & 0x1F) != 1)) //If Text Flavour is printed, then this is too. No need to reprint. Avoids tearing + { + offset = 0x6000; + text_speed_setup(String, 0); + print_file_string(1, 1, 0x40, String, window_selector, offset); + text_speed_setup(String, 1); + print_file_string(2, 3, 0x40, String, window_selector, offset); + text_speed_setup(String, 2); + print_file_string(2, 5, 0x40, String, window_selector, offset); + text_speed_setup(String, 3); + print_file_string(2, 7, 0x40, String, window_selector, offset); + m2_cstm_last_printed[0] = window_selector | (m2_cstm_last_printed[0] & 0x20); + } + break; + case 0x2: //Text Flavour + if((m2_cstm_last_printed[0] & 0x1F) != 2){ + offset = 0x2800; + text_flavour_setup(String, 0); + print_file_string(1, 1, 0x40, String, window_selector, offset); + text_flavour_setup(String, 1); + print_file_string(1, 3, 0x40, String, window_selector, offset); + text_flavour_setup(String, 2); + print_file_string(2, 5, 0x40, String, window_selector, offset); + text_flavour_setup(String, 3); + print_file_string(2, 7, 0x40, String, window_selector, offset); + text_flavour_setup(String, 4); + print_file_string(2, 9, 0x40, String, window_selector, offset); + text_flavour_setup(String, 5); + print_file_string(2, 11, 0x40, String, window_selector, offset); + text_flavour_setup(String, 6); + print_file_string(2, 13, 0x40, String, window_selector, offset); + m2_cstm_last_printed[0] = window_selector; //Set the alphabet bit to 0. + } + break; + case 0xF: //Copy + offset = 0x6000; + copy_setup(String); + print_file_string(1, 1, 0x40, String, window_selector, offset); + break; + case 0x3: //Ness' name + description + case 0x4: //Paula's name + description + case 0x5: //Jeff's name + description + case 0x6: //Poo's name + description + case 0x7: //King's name + description + case 0x8: //FavFood's name + description + case 0x9: //FavThing's name + description + if((m2_cstm_last_printed[0] & 0x1F) != window_selector){ + offset = 0x1800; + description_setup(String, window_selector); + print_file_string(9, 1, 0x40, String, window_selector, offset); + m2_cstm_last_printed[0] = window_selector | (m2_cstm_last_printed[0] & 0x20); + } + break; + case 0xA: //Alphabet 1 + if((m2_cstm_last_printed[0] & 0x20) == 0) //Print this once and stop + { + //Main thing + offset = 0x2800; + alphabet_setup(String, 0, true); + print_file_string(2, 1, 0x40, String, window_selector, offset); + alphabet_setup(String, 1, true); + print_file_string(2, 3, 0x40, String, window_selector, offset); + alphabet_setup(String, 2, true); + print_file_string(2, 5, 0x40, String, window_selector, offset); + alphabet_setup(String, 3, true); + print_file_string(2, 7, 0x40, String, window_selector, offset); + alphabet_setup(String, 4, true); + print_file_string(2, 9, 0x40, String, window_selector, offset); + alphabet_setup(String, 5, true); + print_file_string(2, 13, 0x40, String, window_selector, offset); + m2_cstm_last_printed[0] = (m2_cstm_last_printed[0] & 0x1F) | 0x20; //Printed flag + } + break; + case 0xB: //Alphabet 2 + if((m2_cstm_last_printed[0] & 0x40) == 0) //Print this once and stop + { + //Main thing + offset = 0x2800; + alphabet_setup(String, 0, false); + print_file_string(2, 1, 0x40, String, window_selector, offset); + alphabet_setup(String, 1, false); + print_file_string(2, 3, 0x40, String, window_selector, offset); + alphabet_setup(String, 2, false); + print_file_string(2, 5, 0x40, String, window_selector, offset); + alphabet_setup(String, 3, false); + print_file_string(2, 7, 0x40, String, window_selector, offset); + alphabet_setup(String, 4, true); + print_file_string(2, 9, 0x40, String, window_selector, offset); + alphabet_setup(String, 5, true); + print_file_string(2, 13, 0x40, String, window_selector, offset); + m2_cstm_last_printed[0] = (m2_cstm_last_printed[0] & 0x1F) | 0x40; //Printed flag + } + + break; + case 0xC: //Alphabet 3 - Won't use + + break; + case 0xD: //Is this okay? Yes No + offset = 0x2800; + summary_setup(String, 0); + print_file_string(0xC, 5, 0x40, String, window_selector, offset); + summary_setup(String, 1); + print_file_string(0xC, 0xB, 0x40, String, window_selector, offset); + summary_setup(String, 2); + print_file_string(0x1, 0x11, 0x40, String, window_selector, offset); + m2_cstm_last_printed[0] = window_selector; //Set the alphabet bit to 0. + break; + default: //File select string, already printed + break; + } + +} + + void format_file_cc(FILE_SELECT *file, int *index, byte cmd) { file->formatted_str[(*index)++] = 0xFE; @@ -185,6 +765,39 @@ void format_file_string(FILE_SELECT *file) file->formatted_str[index++] = encode_ascii(speedStr[i]); file->formatted_str[index++] = 0xFF; + + //Delete part + + index = (0x40 - 0x15); //Maximum length of this is 0x15 with the 0xFF. The strings do not collide... By 1 byte. If you were to remove this string's end (which you could), it would be by 2 bytes. + + file->formatted_str[index++] = (byte)(slot + ZERO); + file->formatted_str[index++] = encode_ascii(':'); + file->formatted_str[index++] = encode_ascii(' '); + + // Name + for (int i = 0; i < 5; i++) + { + byte name_chr = file->ness_name[i]; + + if (name_chr != 0xFF) + file->formatted_str[index++] = name_chr; + else + file->formatted_str[index++] = encode_ascii(' '); + } + + // Re-position + format_file_cc(file, &index, CUSTOMCC_SET_X); + file->formatted_str[index++] = 72; + + for (int i = 0; i < (sizeof(levelStr) - 1); i++) + file->formatted_str[index++] = encode_ascii(levelStr[i]); + + if (tens > 0) + file->formatted_str[index++] = tens + ZERO; + + file->formatted_str[index++] = ones + ZERO; + + file->formatted_str[index++] = 0xFF; } byte print_character(byte chr, int x, int y) @@ -208,12 +821,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, 0); } 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, 0); } // Prints a special tile. Pixels are copied to the VWF buffer. @@ -251,7 +864,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, int tilemapOffset) { int tileWidth = m2_font_widths[font]; int tileHeight = m2_font_heights[font]; @@ -265,6 +878,8 @@ byte print_character_with_callback(byte chr, int x, int y, int font, int foregro int tileX = x >> 3; int tileY = y >> 3; + + int offsetY = y & 7; for (int dTileY = 0; dTileY < tileHeight; dTileY++) // dest tile Y { @@ -275,45 +890,71 @@ byte print_character_with_callback(byte chr, int x, int y, int font, int foregro { // 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 for (int row = 0; row < 8; row++) { - int canvasRow = dest[(tileIndex * 8) + row]; + int canvasRow = dest[(realTileIndex * 8) + ((row + offsetY) & 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[(tileIndex * 8) + row] = canvasRow; + dest[(realTileIndex * 8) + ((row + offsetY) & 7)] = canvasRow; + if(offsetY != 0 && ((row + offsetY) == 7)) + realTileIndex = getTileCallback(tileX + dTileX, tileY + dTileY + 1); } if (tilemapPtr != NULL) - tilemapPtr[tileX + dTileX + ((tileY + dTileY) * tilemapWidth)] = paletteMask | tileIndex; + { + tilemapPtr[tileX + dTileX + ((tileY + dTileY) * tilemapWidth)] = paletteMask | (tileIndex + tilemapOffset); + if(useful) + tilemapPtr[tileX + dTileX + ((tileY + dTileY + 1) * tilemapWidth)] = paletteMask | (realTileIndex + tilemapOffset); + } 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 for (int row = 0; row < 8; row++) { - int canvasRow = dest[(tileIndex * 8) + row]; + int canvasRow = dest[(realTileIndex * 8) + ((row + offsetY) & 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[(tileIndex * 8) + row] = canvasRow; + dest[(realTileIndex * 8) + ((row + offsetY) & 7)] = canvasRow; + if(offsetY != 0 && ((row + offsetY) == 7)) + realTileIndex = getTileCallback(tileX + dTileX + 1, tileY + dTileY + 1); } - + if (tilemapPtr != NULL) - tilemapPtr[tileX + dTileX + 1 + ((tileY + dTileY) * tilemapWidth)] = paletteMask | tileIndex; + { + tilemapPtr[tileX + dTileX + 1 + ((tileY + dTileY) * tilemapWidth)] = paletteMask | (tileIndex + tilemapOffset); + if(useful) + tilemapPtr[tileX + dTileX + 1 + ((tileY + dTileY + 1) * tilemapWidth)] = paletteMask | (realTileIndex + tilemapOffset); + } } renderedWidth -= 8; diff --git a/src/c/vwf.h b/src/c/vwf.h index 12f82b8..77539e4 100644 --- a/src/c/vwf.h +++ b/src/c/vwf.h @@ -28,6 +28,7 @@ byte decode_character(byte chr); byte encode_ascii(char chr); int get_tile_number(int x, int y); +int count_pixels(byte *str, int length); int expand_bit_depth(byte row, int foreground); byte reduce_bit_depth(int row, int foreground); byte print_character(byte chr, int x, int y); @@ -37,7 +38,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, int tilemapOffset); 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); @@ -67,7 +68,8 @@ void print_number_menu_current(byte digit, WINDOW* window); void clear_number_menu(WINDOW* window); void format_cash_window(int value, int padding, byte* str); void handle_first_window(WINDOW* window); -void print_file_string(int x, int y, int length, byte *str, int unknown); +void print_file_string(int x, int y, int length, byte *str, int window_selector, int offset); +void wrapper_file_string(int x, int y, int length, byte *str, int window_selector); void format_file_string(FILE_SELECT *file); extern unsigned short m2_coord_table[]; @@ -81,6 +83,7 @@ extern byte m12_other_str5[]; extern byte m12_other_str6[]; extern byte m12_other_str7[]; extern byte m12_other_str8[]; +extern byte m2_cstm_last_printed[]; extern void cpufastset(void *source, void *dest, int mode); extern byte* m2_strlookup(int *offset_table, byte *strings, int index); diff --git a/src/data/m2-alphabet-template.bin b/src/data/m2-alphabet-template.bin new file mode 100644 index 0000000..e859331 Binary files /dev/null and b/src/data/m2-alphabet-template.bin differ diff --git a/src/data/m2-delete-template.bin b/src/data/m2-delete-template.bin new file mode 100644 index 0000000..9aef54e Binary files /dev/null and b/src/data/m2-delete-template.bin differ diff --git a/src/data/m2-descriptions-template.bin b/src/data/m2-descriptions-template.bin new file mode 100644 index 0000000..a9ed097 Binary files /dev/null and b/src/data/m2-descriptions-template.bin differ diff --git a/src/data/m2-flavour-template.bin b/src/data/m2-flavour-template.bin new file mode 100644 index 0000000..db780a3 Binary files /dev/null and b/src/data/m2-flavour-template.bin differ diff --git a/src/data/m2-options-template.bin b/src/data/m2-options-template.bin new file mode 100644 index 0000000..e72c49a Binary files /dev/null and b/src/data/m2-options-template.bin differ diff --git a/src/data/m2-summary-template.bin b/src/data/m2-summary-template.bin new file mode 100644 index 0000000..4804fd4 Binary files /dev/null and b/src/data/m2-summary-template.bin differ diff --git a/src/data/m2-textspeed-template.bin b/src/data/m2-textspeed-template.bin new file mode 100644 index 0000000..6135f58 Binary files /dev/null and b/src/data/m2-textspeed-template.bin differ diff --git a/src/m2-hack.asm b/src/m2-hack.asm index 2b89ae6..7831544 100644 --- a/src/m2-hack.asm +++ b/src/m2-hack.asm @@ -1036,7 +1036,7 @@ nop //Naming screen name length .org 0x8004F54 :: mov r2,#5 //Ness -.org 0x8004F78 :: mov r0,#5 //Paula +.org 0x8004F78 :: mov r0,#5 :: str r0,[sp,#0x18] :: bl _4f7c_window_selector //Paula .org 0x8004F9C :: mov r0,#5 //Jeff .org 0x8004FC0 :: mov r1,#5 //Poo @@ -1054,7 +1054,9 @@ nop // Main file select window resize .org 0x82B79BC :: dw 0x1C // new window width .org 0x8003998 :: mov r0,1 // new window x -.org 0x8003A04 :: mov r1,1 +.org 0x8003F92 :: mov r0,1 +.org 0x80053DC :: mov r0,1 +.org 0x8003A04 :: mov r0,1 .org 0x8003B40 :: mov r0,0x10 // new cursor x .org 0x86DB070 :: .incbin "data/m2-fileselect-template.bin" @@ -1066,12 +1068,79 @@ nop .org 0x8002284 :: bl format_file_string // Printing -.org 0x80038CC :: mov r2,0x40 :: bl print_file_string -.org 0x80038DE :: mov r2,0x40 :: bl print_file_string -.org 0x80038F2 :: mov r2,0x40 :: bl print_file_string +.org 0x80038CC :: mov r2,0x40 :: bl wrapper_file_string +.org 0x80038DE :: mov r2,0x40 :: bl wrapper_file_string +.org 0x80038F2 :: mov r2,0x40 :: bl wrapper_file_string -// Bump file select cursor up by 3 pixels -.org 0x8003844 :: add r0,r5,1 +// Bump file select cursor up by 3 pixels - Not needed now that the text is 3 pixels lower +//.org 0x8003844 :: add r0,r5,1 + +// File select options +.org 0x8004092 :: bl _4092_print_window //Printing +.org 0x80041D4 :: bl _41D4_cursor_X //New cursor's X + +//Text Speed options +.org 0x8003BBC :: bl _4092_print_window //Printing +.org 0x8003FA2 :: bl _4092_print_window +.org 0x82B79D0 :: dw 0x10 //new window width +.org 0x86DB0FC :: .incbin "data/m2-textspeed-template.bin" + +//Text Flavour options +.org 0x8003D8A :: bl _4092_print_window //Printing +.org 0x8003D86 :: mov r1,#4 //new window Y +.org 0x8003DB6 :: mov r1,#4 +.org 0x8003E0C :: mov r1,#4 +.org 0x8003E8C :: mov r1,#4 +.org 0x8003EF8 :: mov r1,#4 +.org 0x80053F2 :: mov r1,#4 +.org 0x82B79E4 :: dw 0xF //new window width +.org 0x82B79E8 :: dw 0x10 //new window height +.org 0x86DB1F8 :: .incbin "data/m2-flavour-template.bin" + +//Delete +.org 0x8004410 :: mov r1,#3 :: mov r2,#0x15 :: bl wrapper_delete_string +.org 0x800441E :: bl _4092_print_window //Printing +.org 0x82B7AFC :: dw 0x15 //new window width +.org 0x86DBE8C :: .incbin "data/m2-delete-template.bin" + +//Copy +.org 0x8004294 :: bl _4298_print_window //Printing - 1 slot available +.org 0x80042BA :: bl _4092_print_window //Printing - 2 slots available +.org 0x8004268 :: mov r2,#0x2 :: bl wrapper_copy_string + +//Descriptions and Names +.org 0x8004ED2 :: bl wrapper_name_string //Printing names +.org 0x8004EDC :: bl _4092_print_window //Printing descriptions +.org 0x86DB2B8 :: .incbin "data/m2-descriptions-template.bin" +.org 0x82B7A00 :: dw 0x86DB2B8 //Point all the descriptions + names to the same template +.org 0x82B7A14 :: dw 0x86DB2B8 +.org 0x82B7A28 :: dw 0x86DB2B8 +.org 0x82B7A3C :: dw 0x86DB2B8 +.org 0x82B7A50 :: dw 0x86DB2B8 +.org 0x82B7A64 :: dw 0x86DB2B8 + +//Alphabets +.org 0x80051A4 :: bl _4092_print_window //Printing +.org 0x8004EA2 :: bl _4092_print_window //Printing +.org 0x82B7A8C :: dw 0x86DB5C4 +.org 0x86DB5C4 :: .incbin "data/m2-alphabet-template.bin" + +//Summary +.org 0x80055B0 :: bl _4092_print_window //Printing +.org 0x80054F2 :: mov r2,#5 :: bl wrapper_name_summary_string //Printing Ness' name +.org 0x8005502 :: mov r2,#5 :: bl wrapper_name_summary_string //Printing Paula's name +.org 0x8005512 :: mov r2,#5 :: bl wrapper_name_summary_string //Printing Jeff's name +.org 0x8005522 :: mov r2,#5 :: bl wrapper_name_summary_string //Printing Poo's name +.org 0x800555C :: nop :: nop //Sends to a bunch of 0xFF +.org 0x800556A :: nop :: nop //Sends to a bunch of 0xFF +.org 0x8005530 :: mov r0,#0x11 //New x for King's name +.org 0x8005536 :: bl wrapper_name_summary_string //Printing King's name +.org 0x8005578 :: bl count_pixels :: mov r2,#6 :: mov r4,#0x17 :: sub r0,r4,r0 //Count length of Food's name in tiles +.org 0x8005588 :: bl wrapper_name_summary_string //Printing Food's name +.org 0x8005596 :: bl count_pixels :: mov r2,#6 :: sub r4,r4,r0 //Count length of Food's name in tiles +.org 0x80055A6 :: bl wrapper_name_summary_string //Printing Thing's name +.org 0x80056F0 :: add r0,#0x90 //New cursor's X +.org 0x86DBC6C :: .incbin "data/m2-summary-template.bin" //============================================================================== // Data files diff --git a/src/m2-vwf-entries.asm b/src/m2-vwf-entries.asm index 9115114..e4e42d2 100644 --- a/src/m2-vwf-entries.asm +++ b/src/m2-vwf-entries.asm @@ -1580,4 +1580,59 @@ bl get_print_inventory_window //Prints old inventory bl 0x80BD7F8 //Copies old arrangements, this includes the highlight pop {r5,pc} +.pool + +//============================================================================== +_4092_print_window: +push {lr} +push {r0-r4} +mov r0,r2 +bl print_windows +pop {r0-r4} +bl 0x800341C +pop {pc} + +//============================================================================== +_4298_print_window: +push {lr} +push {r0-r4} +ldr r0,[sp,#0x20] +bl print_windows +pop {r0-r4} +mov r2,#0 +mov r3,#0 +pop {pc} + +//============================================================================== +_41D4_cursor_X: +push {lr} +cmp r0,#1 +bne @@next1 +mov r0,#5 +b @@end +@@next1: +cmp r0,#6 +bne @@next2 +mov r0,#11 +b @@end +@@next2: +cmp r0,#11 +bne @@next3 +mov r0,#15 +b @@end +@@next3: +mov r0,#20 + +@@end: +lsl r0,r0,#3 +pop {pc} + +//============================================================================== +_4f7c_window_selector: +push {lr} +mov r0,#4 +mov r10,r0 +ldr r1,=#0x82B7FF8 +pop {pc} + .pool \ No newline at end of file