Implement field_name_box (#7697)
Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
parent
5ce49f3cb7
commit
59a214828e
@ -2654,3 +2654,11 @@
|
||||
callnative ScriptChangeFollowerNPCBattlePartner
|
||||
.2byte \battlePartner
|
||||
.endm
|
||||
|
||||
@ Manually buffer a string as the speaker's name for namebox.
|
||||
@ The next shown message/msgbox will include a namebox, if the provided string is not NULL.
|
||||
@ An SP_NAME_* constant can also be used, it'll take the name from gSpeakerNamesTable instead.
|
||||
.macro setspeaker name:req
|
||||
callnative SetSpeaker
|
||||
.4byte \name
|
||||
.endm
|
||||
|
||||
@ -459,6 +459,13 @@ JPN = FC 15
|
||||
ENG = FC 16
|
||||
PAUSE_MUSIC = FC 17
|
||||
RESUME_MUSIC = FC 18
|
||||
SPEAKER = FC 19
|
||||
|
||||
@ Speaker names, the order must be matching with include/constants/speaker_names.h
|
||||
NAME_NONE = 00
|
||||
NAME_MOM = 01
|
||||
NAME_PLAYER = 02
|
||||
NAME_COUNT = 03
|
||||
|
||||
@ fonts
|
||||
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
#include "constants/union_room.h"
|
||||
#include "constants/vars.h"
|
||||
#include "constants/weather.h"
|
||||
#include "constants/speaker_names.h"
|
||||
.include "asm/macros.inc"
|
||||
.include "asm/macros/event.inc"
|
||||
.include "constants/constants.inc"
|
||||
|
||||
100
docs/tutorials/how_to_namebox.md
Normal file
100
docs/tutorials/how_to_namebox.md
Normal file
@ -0,0 +1,100 @@
|
||||
# How to Use Namebox
|
||||
|
||||
_New implementation made by mudskipper13, originally made by Tustin2121._
|
||||
|
||||
## Overview
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
This is a broad and self-contained implementation of Tustin2121's namebox feature branch [here](https://github.com/tustin2121/pokeemerald/tree/feature/namebox), which includes the following:
|
||||
- Cleaner implementation of namebox onto both the field message box _and_ the field PokéNav textbox.
|
||||
- New configs:
|
||||
- `OW_NAME_BOX_USE_DYNAMIC_WIDTH` lets the namebox use dynamic window width depending on the speaker's string length.
|
||||
- When disabled and/or the speaker name is too long, `OW_NAME_BOX_DEFAULT_WIDTH` will be used as the maximum width.
|
||||
- `OW_NAME_BOX_NPC_TRAINER` lets any approaching NPC trainers shows a namebox in their dialogue automagically.
|
||||
- `OW_NAME_BOX_DEFAULT_WIDTH` and `OW_NAME_BOX_DEFAULT_HEIGHT` sets the default width and height.
|
||||
- `OW_NAME_BOX_FOREGROUND_COLOR` and `OW_NAME_BOX_SHADOW_COLOR` sets the default text colors, the background color is handled by the engine.
|
||||
- `OW_FLAG_SUPPRESS_NAME_BOX` lets you enable/disable the namebox globally, assign a flag from [`include/constants/flags.h`](/include/constants/flags.h) onto this config to be able to use it.
|
||||
- Added a Speaker Name table, frequently-used names can be stored into `gSpeakerNamesTable` in [`src/data/speaker_names.h`](/src/data/speaker_names.h) and they can accessed by using a `SP_NAME_*` constant defined in [`include/constants/speaker_names.h`](/include/constants/speaker_names.h).
|
||||
- Added a new scripting macro `setspeaker ([textPointer]/[SP_NAME_*])`.
|
||||
- Besides a text pointer, it is possible to use the Speaker Name table to set the textPointer with the `gSpeakerNamesTable` array instead.
|
||||
- Feed it either `NULL` or `SP_NAME_NONE` will remove the namebox instead.
|
||||
- `release`, `releaseall`, and `closemessage` will automatically remove the namebox, together with the messagebox.
|
||||
- Added a new text control code/inline text `{SPEAKER NAME_*}`.
|
||||
- Unlike the `setspeaker` macro, you can only use the `SP_NAME_*` constants for this. It is partly due to the text engine's limitation itself.
|
||||
- You'll need to add the constants into `charmap.txt` to be able to use them for the same reason as above.
|
||||
- Feed it `SP_NAME_NONE` to remove the namebox manually.
|
||||
- Similarly, `release`, `releaseall`, and `closemessage` will automatically remove the namebox, together with the message box.
|
||||
|
||||
## Usage
|
||||
|
||||
### `setspeaker`
|
||||
#### Using a text pointer
|
||||
First, define your speaker's string.
|
||||
```
|
||||
Speaker_Jeremy:
|
||||
.string "Jeremy$"
|
||||
```
|
||||
|
||||
And then in your script, add the `setspeaker` with the speaker's name earlier.
|
||||
```
|
||||
...
|
||||
setspeaker Speaker_Jeremy
|
||||
...
|
||||
```
|
||||
|
||||
If you are using poryscript, you can also include the string right there with the `setspeaker` aka inline.
|
||||
```
|
||||
...
|
||||
setspeaker("Jeremy")
|
||||
...
|
||||
```
|
||||
#### Using a `SP_NAME_*` constant
|
||||
Add the `setspeaker` with your constant.
|
||||
```
|
||||
setspeaker SP_NAME_JEREMY
|
||||
```
|
||||
For instruction on how to add a new Speaker Name, continue [here](#adding-a-new-speaker-name).
|
||||
|
||||
### `SPEAKER` inline
|
||||
The usage is identical to using `setspeaker` with `SP_NAME_*` constant, but instead it's within your _text_ script and uses the constant you added to `charmap.txt`.
|
||||
```
|
||||
"{SPEAKER NAME_JEREMY}Yo wassup!"
|
||||
```
|
||||
For instruction on how to add a new Speaker Name, continue [here](#adding-a-new-speaker-name).
|
||||
|
||||
### Adding a new Speaker Name
|
||||
1. Add a new constant to [`include/constants/speaker_names.h`](/include/constants/speaker_names.h) just after `SP_NAME_NONE` _and_ before `SP_NAME_COUNT`.
|
||||
```diff
|
||||
enum SpeakerNames {
|
||||
SP_NAME_NONE = 0,
|
||||
SP_NAME_MOM,
|
||||
SP_NAME_PLAYER,
|
||||
+ SP_NAME_JEREMY,
|
||||
SP_NAME_COUNT
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
2. Add an entry to `gSpeakerNamesTable` in [`src/data/speaker_names.h`](/src/data/speaker_names.h) with your newly added constant as the array index.
|
||||
```diff
|
||||
const u8 *const gSpeakerNamesTable[SP_NAME_COUNT] =
|
||||
{
|
||||
[SP_NAME_MOM] = COMPOUND_STRING("MOM"),
|
||||
[SP_NAME_PLAYER] = COMPOUND_STRING("{PLAYER}"),
|
||||
+ [SP_NAME_JEREMY] = COMPOUND_STRING("JEREMY"),
|
||||
};
|
||||
```
|
||||
|
||||
3. In order for this constant to be usable for `{SPEAKER}` inline, you'll need to add your constant onto [`charmap.txt`](/charmap.txt). **Do note that the order here MUST match with the one in [`include/constants/speaker_names.h`](/include/constants/speaker_names.h)!**
|
||||
```diff
|
||||
@ Speaker names, the order must be matching with include/constants/speaker_names.h
|
||||
NAME_NONE = 00
|
||||
NAME_MOM = 01
|
||||
NAME_PLAYER = 02
|
||||
-NAME_COUNT = 03
|
||||
+NAME_JEREMY = 03
|
||||
+NAME_COUNT = 04
|
||||
```
|
||||
BIN
docs/tutorials/img/namebox/msgbox.gif
Normal file
BIN
docs/tutorials/img/namebox/msgbox.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 540 KiB |
BIN
docs/tutorials/img/namebox/npc_trainers.gif
Normal file
BIN
docs/tutorials/img/namebox/npc_trainers.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
BIN
docs/tutorials/img/namebox/pokenav.gif
Normal file
BIN
docs/tutorials/img/namebox/pokenav.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 784 KiB |
BIN
graphics/pokenav/name_box.png
Normal file
BIN
graphics/pokenav/name_box.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 205 B |
BIN
graphics/text_window/name_box.png
Normal file
BIN
graphics/text_window/name_box.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 213 B |
@ -110,6 +110,7 @@
|
||||
#define OW_FLAG_NO_TRAINER_SEE 0 // If this flag is set, trainers will not battle the player unless they're talked to.
|
||||
#define OW_FLAG_NO_COLLISION 0 // If this flag is set, the player will be able to walk over tiles with collision. Mainly intended for debugging purposes.
|
||||
#define OW_FLAG_POKE_RIDER 0 // If this flag is set, the player will be able to use fly from the Pokenav Region Map and the Town Map key item by pressing 'R' on a city/location they are able to fly to.
|
||||
#define OW_FLAG_SUPPRESS_NAME_BOX 0 // If this flag is set, any namebox (whether its from a macro or a code) will not show up until this flag is unset.
|
||||
|
||||
#define BATTLE_PYRAMID_RANDOM_ENCOUNTERS FALSE // If set to TRUE, battle pyramid Pokemon will be generated randomly based on the round's challenge instead of hardcoded in src/data/battle_frontier/battle_pyramid_level_50_wild_mons.h (or open_level_wild_mons.h)
|
||||
|
||||
@ -142,4 +143,15 @@
|
||||
// Berry Blender
|
||||
#define BERRY_BLENDER_THROW_ALL_BERRIES_AT_ONCE TRUE // This is a small little addition, that basically speeds up the animation where all players' berries are thrown into the blender. Self-explanatory I hope!
|
||||
|
||||
// Namebox Speaker configs
|
||||
#define OW_NAME_BOX_USE_DYNAMIC_WIDTH TRUE // When TRUE, the namebox window can use different width depending on the length of the speaker's name.
|
||||
#define OW_NAME_BOX_NPC_TRAINER FALSE // When TRUE, any approaching NPC trainers will have a namebox shown automagically. The name will be taken from their trainer data.
|
||||
#define OW_NAME_BOX_DEFAULT_WIDTH 8 // Maximum width of what OW_NAME_BOX_USE_DYNAMIC_WIDTH can set. Also the default width when the config above is set to FALSE (or the dynamic width exceeds this value).
|
||||
#define OW_NAME_BOX_DEFAULT_HEIGHT 2 // Maximum height of the namebox window.
|
||||
|
||||
// Text colors of Namebox. The numbers corresponds to the palette index.
|
||||
// The BG color is not provided as it always needs to be 0.
|
||||
#define OW_NAME_BOX_FOREGROUND_COLOR 1
|
||||
#define OW_NAME_BOX_SHADOW_COLOR 2
|
||||
|
||||
#endif // GUARD_CONFIG_OVERWORLD_H
|
||||
|
||||
@ -232,6 +232,7 @@
|
||||
#define EXT_CTRL_CODE_ENG 0x16
|
||||
#define EXT_CTRL_CODE_PAUSE_MUSIC 0x17
|
||||
#define EXT_CTRL_CODE_RESUME_MUSIC 0x18
|
||||
#define EXT_CTRL_CODE_SPEAKER 0x19
|
||||
|
||||
#define TEXT_COLOR_TRANSPARENT 0x0
|
||||
#define TEXT_COLOR_WHITE 0x1
|
||||
|
||||
11
include/constants/speaker_names.h
Normal file
11
include/constants/speaker_names.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef GUARD_CONSTANTS_SPEAKER_NAMES_H
|
||||
#define GUARD_CONSTANTS_SPEAKER_NAMES_H
|
||||
|
||||
enum SpeakerNames {
|
||||
SP_NAME_NONE = 0,
|
||||
SP_NAME_MOM,
|
||||
SP_NAME_PLAYER,
|
||||
SP_NAME_COUNT
|
||||
};
|
||||
|
||||
#endif // GUARD_CONSTANTS_SPEAKER_NAMES_H
|
||||
17
include/field_name_box.h
Normal file
17
include/field_name_box.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef GUARD_FIELD_NAME_BOX_H
|
||||
#define GUARD_FIELD_NAME_BOX_H
|
||||
|
||||
extern EWRAM_DATA const u8 *gSpeakerName;
|
||||
extern const u8 *const gSpeakerNamesTable[];
|
||||
|
||||
void TrySpawnNamebox(void);
|
||||
u32 GetNameboxWindowId(void);
|
||||
void DestroyNamebox(void);
|
||||
void FillNamebox(void);
|
||||
void DrawNamebox(u32 windowId, bool32 copyToVram);
|
||||
void ClearNamebox(u32 windowId, bool32 copyToVram);
|
||||
void SetSpeakerName(const u8 *name);
|
||||
u32 GetNameboxWidth(void);
|
||||
void TrySpawnAndShowNamebox(const u8 *speaker);
|
||||
|
||||
#endif // GUARD_FIELD_NAME_BOX_H
|
||||
@ -19,5 +19,6 @@ void BufferPokedexRatingForMatchCall(u8 *destStr);
|
||||
bool32 SelectMatchCallMessage(int trainerId, u8 *str);
|
||||
void LoadMatchCallWindowGfx(u32 windowId, u32 destOffset, u32 paletteId);
|
||||
void DrawMatchCallTextBoxBorder(u32 windowId, u32 tileOffset, u32 paletteId);
|
||||
void RedrawMatchCallTextBoxBorder(void);
|
||||
|
||||
#endif //GUARD_MATCH_CALL_H
|
||||
|
||||
@ -135,5 +135,6 @@ u8 AddSecondaryPopUpWindow(void);
|
||||
u8 GetSecondaryPopUpWindowId(void);
|
||||
void RemoveSecondaryPopUpWindow(void);
|
||||
void HBlankCB_DoublePopupWindow(void);
|
||||
void RedrawDialogueFrame(void);
|
||||
|
||||
#endif // GUARD_MENU_H
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
#include "data.h"
|
||||
#include "vs_seeker.h"
|
||||
#include "item.h"
|
||||
#include "field_name_box.h"
|
||||
#include "constants/battle_frontier.h"
|
||||
#include "constants/battle_setup.h"
|
||||
#include "constants/event_objects.h"
|
||||
@ -1488,9 +1489,19 @@ static const u8 *ReturnEmptyStringIfNull(const u8 *string)
|
||||
static const u8 *GetIntroSpeechOfApproachingTrainer(void)
|
||||
{
|
||||
if (gApproachingTrainerId == 0)
|
||||
{
|
||||
if (OW_NAME_BOX_NPC_TRAINER)
|
||||
gSpeakerName = GetTrainerNameFromId(TRAINER_BATTLE_PARAM.opponentA);
|
||||
|
||||
return ReturnEmptyStringIfNull(TRAINER_BATTLE_PARAM.introTextA);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OW_NAME_BOX_NPC_TRAINER)
|
||||
gSpeakerName = GetTrainerNameFromId(TRAINER_BATTLE_PARAM.opponentB);
|
||||
|
||||
return ReturnEmptyStringIfNull(TRAINER_BATTLE_PARAM.introTextB);
|
||||
}
|
||||
}
|
||||
|
||||
const u8 *GetTrainerALoseText(void)
|
||||
|
||||
5
src/data/speaker_names.h
Normal file
5
src/data/speaker_names.h
Normal file
@ -0,0 +1,5 @@
|
||||
const u8 *const gSpeakerNamesTable[SP_NAME_COUNT] =
|
||||
{
|
||||
[SP_NAME_MOM] = COMPOUND_STRING("MOM"),
|
||||
[SP_NAME_PLAYER] = COMPOUND_STRING("{PLAYER}"),
|
||||
};
|
||||
@ -7,6 +7,7 @@
|
||||
#include "field_message_box.h"
|
||||
#include "text_window.h"
|
||||
#include "script.h"
|
||||
#include "field_name_box.h"
|
||||
|
||||
static EWRAM_DATA u8 sFieldMessageBoxMode = 0;
|
||||
EWRAM_DATA u8 gWalkAwayFromSignpostTimer = 0;
|
||||
@ -39,9 +40,12 @@ static void Task_DrawFieldMessage(u8 taskId)
|
||||
task->tState++;
|
||||
break;
|
||||
case 1:
|
||||
DrawDialogueFrame(0, TRUE);
|
||||
task->tState++;
|
||||
break;
|
||||
u32 nameboxWinId = GetNameboxWindowId();
|
||||
DrawDialogueFrame(0, TRUE);
|
||||
if (nameboxWinId != WINDOW_NONE)
|
||||
DrawNamebox(nameboxWinId, TRUE);
|
||||
task->tState++;
|
||||
break;
|
||||
case 2:
|
||||
if (RunTextPrintersAndIsPrinter0Active() != TRUE)
|
||||
{
|
||||
@ -123,6 +127,7 @@ bool8 ShowFieldMessageFromBuffer(void)
|
||||
|
||||
static void ExpandStringAndStartDrawFieldMessage(const u8 *str, bool32 allowSkippingDelayWithButtonPress)
|
||||
{
|
||||
TrySpawnNamebox();
|
||||
StringExpandPlaceholders(gStringVar4, str);
|
||||
AddTextPrinterForMessage(allowSkippingDelayWithButtonPress);
|
||||
CreateTask_DrawFieldMessage();
|
||||
@ -138,6 +143,7 @@ void HideFieldMessageBox(void)
|
||||
{
|
||||
DestroyTask_DrawFieldMessage();
|
||||
ClearDialogWindowAndFrame(0, TRUE);
|
||||
DestroyNamebox();
|
||||
sFieldMessageBoxMode = FIELD_MESSAGE_BOX_HIDDEN;
|
||||
}
|
||||
|
||||
|
||||
194
src/field_name_box.c
Normal file
194
src/field_name_box.c
Normal file
@ -0,0 +1,194 @@
|
||||
#include "global.h"
|
||||
#include "main.h"
|
||||
#include "menu.h"
|
||||
#include "bg.h"
|
||||
#include "window.h"
|
||||
#include "text.h"
|
||||
#include "string_util.h"
|
||||
#include "international_string_util.h"
|
||||
#include "script_menu.h"
|
||||
#include "field_message_box.h"
|
||||
#include "graphics.h"
|
||||
#include "script.h"
|
||||
#include "field_name_box.h"
|
||||
#include "event_data.h"
|
||||
#include "match_call.h"
|
||||
#include "malloc.h"
|
||||
#include "constants/speaker_names.h"
|
||||
#include "data/speaker_names.h"
|
||||
|
||||
#define NAME_BOX_BASE_TILE_TOTAL (6)
|
||||
#define NAME_BOX_BASE_TILE_NUM (0x194 - (OW_NAME_BOX_DEFAULT_WIDTH * OW_NAME_BOX_DEFAULT_HEIGHT) - NAME_BOX_BASE_TILE_TOTAL)
|
||||
|
||||
static EWRAM_INIT u8 sNameboxWindowId = WINDOW_NONE;
|
||||
EWRAM_DATA const u8 *gSpeakerName = NULL;
|
||||
|
||||
static const u32 sNameBoxDefaultGfx[] = INCBIN_U32("graphics/text_window/name_box.4bpp");
|
||||
static const u32 sNameBoxPokenavGfx[] = INCBIN_U32("graphics/pokenav/name_box.4bpp");
|
||||
|
||||
static void WindowFunc_DrawNamebox(u8, u8, u8, u8, u8, u8);
|
||||
static void WindowFunc_ClearNamebox(u8, u8, u8, u8, u8, u8);
|
||||
|
||||
void TrySpawnNamebox(void)
|
||||
{
|
||||
u8 *strbuf = AllocZeroed(32 * sizeof(u8));
|
||||
if ((OW_FLAG_SUPPRESS_NAME_BOX != 0 && FlagGet(OW_FLAG_SUPPRESS_NAME_BOX)) || gSpeakerName == NULL || !strbuf)
|
||||
{
|
||||
// Re-check again in case anything but !strbuf is TRUE.
|
||||
if (strbuf)
|
||||
Free(strbuf);
|
||||
|
||||
DestroyNamebox();
|
||||
return;
|
||||
}
|
||||
|
||||
StringExpandPlaceholders(strbuf, gSpeakerName);
|
||||
|
||||
u32 fontId = FONT_SMALL;
|
||||
u32 winWidth = OW_NAME_BOX_DEFAULT_WIDTH;
|
||||
|
||||
if (OW_NAME_BOX_USE_DYNAMIC_WIDTH)
|
||||
{
|
||||
winWidth = ConvertPixelWidthToTileWidth(GetStringWidth(fontId, strbuf, -1));
|
||||
if (winWidth > OW_NAME_BOX_DEFAULT_WIDTH)
|
||||
winWidth = OW_NAME_BOX_DEFAULT_WIDTH;
|
||||
}
|
||||
|
||||
if (sNameboxWindowId != WINDOW_NONE)
|
||||
{
|
||||
DestroyNamebox();
|
||||
RedrawDialogueFrame();
|
||||
}
|
||||
|
||||
bool32 matchCall = IsMatchCallTaskActive();
|
||||
|
||||
struct WindowTemplate template =
|
||||
{
|
||||
.bg = 0,
|
||||
.tilemapLeft = 2,
|
||||
.tilemapTop = 13,
|
||||
.width = winWidth,
|
||||
.height = OW_NAME_BOX_DEFAULT_HEIGHT,
|
||||
.paletteNum = matchCall ? 14 : DLG_WINDOW_PALETTE_NUM,
|
||||
.baseBlock = 0x194 - (OW_NAME_BOX_DEFAULT_WIDTH * OW_NAME_BOX_DEFAULT_HEIGHT),
|
||||
};
|
||||
|
||||
sNameboxWindowId = AddWindow(&template);
|
||||
FillNamebox();
|
||||
|
||||
u8 colors[3] = {TEXT_COLOR_TRANSPARENT, OW_NAME_BOX_FOREGROUND_COLOR, OW_NAME_BOX_SHADOW_COLOR};
|
||||
u8 bakColors[3];
|
||||
int strX = GetStringCenterAlignXOffset(fontId, strbuf, (winWidth * 8));
|
||||
if (matchCall)
|
||||
{
|
||||
colors[1] = 1;
|
||||
colors[2] = 0;
|
||||
}
|
||||
|
||||
SaveTextColors(&bakColors[0], &bakColors[1], &bakColors[2]);
|
||||
AddTextPrinterParameterized3(sNameboxWindowId, fontId, strX, 0, colors, 0, strbuf);
|
||||
RestoreTextColors(&bakColors[0], &bakColors[1], &bakColors[2]);
|
||||
PutWindowTilemap(sNameboxWindowId);
|
||||
Free(strbuf);
|
||||
}
|
||||
|
||||
u32 GetNameboxWindowId(void)
|
||||
{
|
||||
return sNameboxWindowId;
|
||||
}
|
||||
|
||||
void DestroyNamebox(void)
|
||||
{
|
||||
if (sNameboxWindowId == WINDOW_NONE)
|
||||
return;
|
||||
|
||||
ClearNamebox(sNameboxWindowId, TRUE);
|
||||
ClearWindowTilemap(sNameboxWindowId);
|
||||
RemoveWindow(sNameboxWindowId);
|
||||
sNameboxWindowId = WINDOW_NONE;
|
||||
gSpeakerName = NULL;
|
||||
}
|
||||
|
||||
u32 GetNameboxWidth(void)
|
||||
{
|
||||
return gWindows[sNameboxWindowId].window.width;
|
||||
}
|
||||
|
||||
static const u32 *GetNameboxGraphics(void)
|
||||
{
|
||||
if (IsMatchCallTaskActive())
|
||||
return sNameBoxPokenavGfx;
|
||||
else
|
||||
return sNameBoxDefaultGfx;
|
||||
}
|
||||
|
||||
void FillNamebox(void)
|
||||
{
|
||||
u32 winSize = GetNameboxWidth();
|
||||
const u32 *gfx = GetNameboxGraphics();
|
||||
|
||||
for (u32 i = 0; i < winSize; i++)
|
||||
{
|
||||
#define TILE(x) (8 * x)
|
||||
CopyToWindowPixelBuffer(sNameboxWindowId, &gfx[TILE(1)], TILE_SIZE_4BPP, i);
|
||||
CopyToWindowPixelBuffer(sNameboxWindowId, &gfx[TILE(4)], TILE_SIZE_4BPP, i + winSize);
|
||||
#undef TILE
|
||||
}
|
||||
}
|
||||
|
||||
void DrawNamebox(u32 windowId, bool32 copyToVram)
|
||||
{
|
||||
LoadBgTiles(GetWindowAttribute(sNameboxWindowId, WINDOW_BG), GetNameboxGraphics(), 0x0C0, NAME_BOX_BASE_TILE_NUM);
|
||||
CallWindowFunction(windowId, WindowFunc_DrawNamebox);
|
||||
PutWindowTilemap(windowId);
|
||||
if (copyToVram == TRUE)
|
||||
CopyWindowToVram(windowId, COPYWIN_FULL);
|
||||
}
|
||||
|
||||
void ClearNamebox(u32 windowId, bool32 copyToVram)
|
||||
{
|
||||
CallWindowFunction(windowId, WindowFunc_ClearNamebox);
|
||||
ClearWindowTilemap(windowId);
|
||||
if (copyToVram == TRUE)
|
||||
CopyWindowToVram(windowId, COPYWIN_FULL);
|
||||
}
|
||||
|
||||
static void WindowFunc_DrawNamebox(u8 bg, u8 L, u8 T, u8 w, u8 h, u8 p)
|
||||
{
|
||||
// left-most
|
||||
FillBgTilemapBufferRect(bg, NAME_BOX_BASE_TILE_NUM, L - 1, T, 1, 1, p);
|
||||
FillBgTilemapBufferRect(bg, NAME_BOX_BASE_TILE_NUM + 3, L - 1, T + 1, 1, 1, p);
|
||||
|
||||
// right-most
|
||||
FillBgTilemapBufferRect(bg, NAME_BOX_BASE_TILE_NUM + 2, L + w, T, 1, 1, p);
|
||||
FillBgTilemapBufferRect(bg, NAME_BOX_BASE_TILE_NUM + 5, L + w, T + 1, 1, 1, p);
|
||||
}
|
||||
|
||||
static void WindowFunc_ClearNamebox(u8 bg, u8 L, u8 T, u8 w, u8 h, u8 p)
|
||||
{
|
||||
FillBgTilemapBufferRect(bg, 0, L - 1, T, w + 2, h, 0); // palette doesn't matter
|
||||
}
|
||||
|
||||
void SetSpeaker(struct ScriptContext *ctx)
|
||||
{
|
||||
u32 arg = ScriptReadWord(ctx);
|
||||
const u8 *speaker = NULL;
|
||||
|
||||
if (arg < SP_NAME_COUNT)
|
||||
speaker = gSpeakerNamesTable[arg];
|
||||
else if (arg >= ROM_START && arg < ROM_END)
|
||||
speaker = (const u8 *)arg;
|
||||
|
||||
gSpeakerName = speaker;
|
||||
}
|
||||
|
||||
// useful for other context e.g. match call
|
||||
void TrySpawnAndShowNamebox(const u8 *speaker)
|
||||
{
|
||||
gSpeakerName = speaker;
|
||||
TrySpawnNamebox();
|
||||
if (sNameboxWindowId != WINDOW_NONE)
|
||||
DrawNamebox(sNameboxWindowId, TRUE);
|
||||
else // either NULL or SP_NAME_NONE
|
||||
RedrawDialogueFrame();
|
||||
}
|
||||
@ -27,6 +27,7 @@
|
||||
#include "task.h"
|
||||
#include "wild_encounter.h"
|
||||
#include "window.h"
|
||||
#include "field_name_box.h"
|
||||
#include "constants/abilities.h"
|
||||
#include "constants/battle_frontier.h"
|
||||
#include "constants/event_objects.h"
|
||||
@ -1321,9 +1322,11 @@ static bool32 MatchCall_PrintIntro(u8 taskId)
|
||||
{
|
||||
FillWindowPixelBuffer(tWindowId, PIXEL_FILL(8));
|
||||
|
||||
// Ready the message
|
||||
// Ready the message (and the speaker's name if possible)
|
||||
if (!sMatchCallState.triggeredFromScript)
|
||||
SelectMatchCallMessage(sMatchCallState.trainerId, gStringVar4);
|
||||
|
||||
TrySpawnAndShowNamebox(gSpeakerName);
|
||||
InitMatchCallTextPrinter(tWindowId, gStringVar4);
|
||||
return TRUE;
|
||||
}
|
||||
@ -1348,9 +1351,9 @@ static bool32 MatchCall_PrintMessage(u8 taskId)
|
||||
static bool32 MatchCall_SlideWindowOut(u8 taskId)
|
||||
{
|
||||
s16 *data = gTasks[taskId].data;
|
||||
if (ChangeBgY(0, 0x600, BG_COORD_SUB) <= -0x2000)
|
||||
if (ChangeBgY(0, 0x600, BG_COORD_SUB) <= -0x4000)
|
||||
{
|
||||
FillBgTilemapBufferRect_Palette0(0, 0, 0, 14, 30, 6);
|
||||
FillBgTilemapBufferRect_Palette0(0, 0, 0, 12, 30, 8);
|
||||
DestroyTask(tIconTaskId);
|
||||
RemoveWindow(tWindowId);
|
||||
CopyBgTilemapBufferToVram(0);
|
||||
@ -1404,6 +1407,31 @@ static void DrawMatchCallTextBoxBorder_Internal(u32 windowId, u32 tileOffset, u3
|
||||
FillBgTilemapBufferRect_Palette0(bg, ((paletteId << 12) & 0xF000) | (tileNum + 7), x + width, y + height, 1, 1);
|
||||
}
|
||||
|
||||
static u8 GetMatchCallWindowId(void)
|
||||
{
|
||||
if (!IsMatchCallTaskActive())
|
||||
return WINDOW_NONE;
|
||||
|
||||
u32 taskId = FindTaskIdByFunc(ExecuteMatchCall);
|
||||
return gTasks[taskId].tWindowId;
|
||||
}
|
||||
|
||||
// redraw only the top-half
|
||||
void RedrawMatchCallTextBoxBorder(void)
|
||||
{
|
||||
u32 windowId = GetMatchCallWindowId();
|
||||
u32 bg = GetWindowAttribute(windowId, WINDOW_BG);
|
||||
u32 x = GetWindowAttribute(windowId, WINDOW_TILEMAP_LEFT);
|
||||
u32 y = GetWindowAttribute(windowId, WINDOW_TILEMAP_TOP);
|
||||
u32 width = GetWindowAttribute(windowId, WINDOW_WIDTH);
|
||||
u32 tileNum = TILE_MC_WINDOW + GetBgAttribute(bg, BG_ATTR_BASETILE);
|
||||
u32 paletteId = 14;
|
||||
|
||||
FillBgTilemapBufferRect_Palette0(bg, ((paletteId << 12) & 0xF000) | (tileNum + 0), x - 1, y - 1, 1, 1);
|
||||
FillBgTilemapBufferRect_Palette0(bg, ((paletteId << 12) & 0xF000) | (tileNum + 1), x, y - 1, width, 1);
|
||||
FillBgTilemapBufferRect_Palette0(bg, ((paletteId << 12) & 0xF000) | (tileNum + 2), x + width, y - 1, 1, 1);
|
||||
}
|
||||
|
||||
static void InitMatchCallTextPrinter(int windowId, const u8 *str)
|
||||
{
|
||||
struct TextPrinterTemplate printerTemplate;
|
||||
|
||||
48
src/menu.c
48
src/menu.c
@ -22,6 +22,7 @@
|
||||
#include "task.h"
|
||||
#include "text_window.h"
|
||||
#include "window.h"
|
||||
#include "match_call.h"
|
||||
#include "config/overworld.h"
|
||||
#include "constants/songs.h"
|
||||
|
||||
@ -341,6 +342,53 @@ void DrawDialogueFrame(u8 windowId, bool8 copyToVram)
|
||||
CopyWindowToVram(windowId, COPYWIN_FULL);
|
||||
}
|
||||
|
||||
static void WindowFunc_RedrawDialogueFrame(u8 bg, u8 tilemapLeft, u8 tilemapTop, u8 width, u8 height, u8 paletteNum)
|
||||
{
|
||||
FillBgTilemapBufferRect(bg,
|
||||
DLG_WINDOW_BASE_TILE_NUM + 1,
|
||||
tilemapLeft - 2,
|
||||
tilemapTop - 1,
|
||||
1,
|
||||
1,
|
||||
DLG_WINDOW_PALETTE_NUM);
|
||||
FillBgTilemapBufferRect(bg,
|
||||
DLG_WINDOW_BASE_TILE_NUM + 3,
|
||||
tilemapLeft - 1,
|
||||
tilemapTop - 1,
|
||||
1,
|
||||
1,
|
||||
DLG_WINDOW_PALETTE_NUM);
|
||||
FillBgTilemapBufferRect(bg,
|
||||
DLG_WINDOW_BASE_TILE_NUM + 4,
|
||||
tilemapLeft,
|
||||
tilemapTop - 1,
|
||||
width - 1,
|
||||
1,
|
||||
DLG_WINDOW_PALETTE_NUM);
|
||||
FillBgTilemapBufferRect(bg,
|
||||
DLG_WINDOW_BASE_TILE_NUM + 5,
|
||||
tilemapLeft + width - 1,
|
||||
tilemapTop - 1,
|
||||
1,
|
||||
1,
|
||||
DLG_WINDOW_PALETTE_NUM);
|
||||
FillBgTilemapBufferRect(bg,
|
||||
DLG_WINDOW_BASE_TILE_NUM + 6,
|
||||
tilemapLeft + width,
|
||||
tilemapTop - 1,
|
||||
1,
|
||||
1,
|
||||
DLG_WINDOW_PALETTE_NUM);
|
||||
}
|
||||
|
||||
void RedrawDialogueFrame(void)
|
||||
{
|
||||
if (IsMatchCallTaskActive())
|
||||
RedrawMatchCallTextBoxBorder();
|
||||
else
|
||||
CallWindowFunction(0, WindowFunc_RedrawDialogueFrame);
|
||||
}
|
||||
|
||||
void DrawStdWindowFrame(u8 windowId, bool8 copyToVram)
|
||||
{
|
||||
CallWindowFunction(windowId, WindowFunc_DrawStandardFrame);
|
||||
|
||||
@ -706,6 +706,7 @@ u8 GetExtCtrlCodeLength(u8 code)
|
||||
[EXT_CTRL_CODE_ENG] = 1,
|
||||
[EXT_CTRL_CODE_PAUSE_MUSIC] = 1,
|
||||
[EXT_CTRL_CODE_RESUME_MUSIC] = 1,
|
||||
[EXT_CTRL_CODE_SPEAKER] = 1,
|
||||
};
|
||||
|
||||
u8 length = 0;
|
||||
|
||||
12
src/text.c
12
src/text.c
@ -12,6 +12,8 @@
|
||||
#include "menu.h"
|
||||
#include "dynamic_placeholder_text_util.h"
|
||||
#include "fonts.h"
|
||||
#include "field_name_box.h"
|
||||
#include "constants/speaker_names.h"
|
||||
|
||||
static u16 RenderText(struct TextPrinter *);
|
||||
static u32 RenderFont(struct TextPrinter *);
|
||||
@ -1228,6 +1230,13 @@ static u16 RenderText(struct TextPrinter *textPrinter)
|
||||
case EXT_CTRL_CODE_ENG:
|
||||
textPrinter->japanese = FALSE;
|
||||
return RENDER_REPEAT;
|
||||
case EXT_CTRL_CODE_SPEAKER:
|
||||
{
|
||||
enum SpeakerNames name = *textPrinter->printerTemplate.currentChar++;
|
||||
TrySpawnAndShowNamebox(gSpeakerNamesTable[name]);
|
||||
|
||||
return RENDER_REPEAT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHAR_PROMPT_CLEAR:
|
||||
@ -1418,6 +1427,7 @@ static u32 UNUSED GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 lett
|
||||
case EXT_CTRL_CODE_SKIP:
|
||||
case EXT_CTRL_CODE_CLEAR_TO:
|
||||
case EXT_CTRL_CODE_MIN_LETTER_SPACING:
|
||||
case EXT_CTRL_CODE_SPEAKER:
|
||||
++strPos;
|
||||
break;
|
||||
case EXT_CTRL_CODE_RESET_FONT:
|
||||
@ -1566,6 +1576,7 @@ s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing)
|
||||
case EXT_CTRL_CODE_ESCAPE:
|
||||
case EXT_CTRL_CODE_SHIFT_RIGHT:
|
||||
case EXT_CTRL_CODE_SHIFT_DOWN:
|
||||
case EXT_CTRL_CODE_SPEAKER:
|
||||
++str;
|
||||
break;
|
||||
case EXT_CTRL_CODE_FONT:
|
||||
@ -1735,6 +1746,7 @@ u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str)
|
||||
case EXT_CTRL_CODE_SKIP:
|
||||
case EXT_CTRL_CODE_CLEAR_TO:
|
||||
case EXT_CTRL_CODE_MIN_LETTER_SPACING:
|
||||
case EXT_CTRL_CODE_SPEAKER:
|
||||
++strPos;
|
||||
break;
|
||||
case EXT_CTRL_CODE_RESET_FONT:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user