summaryrefslogtreecommitdiff
path: root/Implementing-the-“textcolor”-script-command-from-FRLG-and-give-object-events-their-own-text-colour.md
blob: d36b713b4119462b48d062cdb64ced922c737f1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
In FireRed and LeafGreen, there is a scripting command that allows text to be a different colour. When it was used, it also stored the value of the last text colour in `gSpecialVar_PrevTextColor` so the colour could be restored later on in the script. The script for the player obtaining an item used this so it could get the correct colour of the text before the obtain item script was executed. This method was also integrated into object event interaction in that the text colour would be blue if the player was interacting with any “male” pic like a Youngster, a Bug Catcher or Brock and red if the player was interacting with any “female” pic like a Lass, a Picnicker or Misty. Anything else was the default dark grey. This feature only allowed 3 possible text colours, which are blue, red and dark grey and used a look up table for getting the correct text colour for the object event.

This tutorial will walk you through how to implement this into Emerald whilst also removing the restrictions it had.
```NOTE: this tutorial expects you to have dynamic overworld palettes as this uses bytes in the object event graphics info struct that got made redundant with the dynamic palette system.```

Open field_specials.c and add the following function:
```c
u8 ContextNpcGetTextColor(void)
{
    u8 gfxId;
    const struct ObjectEventGraphicsInfo *graphicsInfo;

    if (gSpecialVar_TextColor != 0xFF)
        return gSpecialVar_TextColor;
    else if (gSelectedObjectEvent == 0)
        gSpecialVar_TextColor = TEXT_COLOR_DARK_GRAY;
    else
    {
        gfxId = gObjectEvents[gSelectedObjectEvent].graphicsId;
        if (gfxId >= OBJ_EVENT_GFX_VAR_0)
            gfxId = VarGetObjectEventGraphicsId(gfxId - OBJ_EVENT_GFX_VAR_0);
        graphicsInfo = GetObjectEventGraphicsInfo(gfxId);
        gSpecialVar_TextColor = graphicsInfo->textColor;
    }
}
```
This function is what handles the context of the text. The `if (gSpecialVar_TextColor; != 0xFF)`… if I’m honest, I’m not sure what it does as of writing this. I think it looks for values that aren’t FF, if the value is FF, that particular snippet won’t do anything. The else if check looks for the selected object event. This is 0 when interacting with signs or any other text that hasn’t been triggered by the player interacting with an object event. What we need to be paying attention to is the `gSpecialVar_TextColor = graphicsInfo->textColor;`. This is how the function gets the object event text colour.

Extern it somewhere in `include/field_specials.h` like so:
```c
u8 ContextNpcGetTextColor(void);
```

Next, we want to open menu.c and add the following function:
```c
void AddTextPrinterForMessageWithTextColor(bool8 allowSkippingDelayWithButtonPress)
{
    u8 color;
    gTextFlags.canABSpeedUpPrint = allowSkippingDelayWithButtonPress;

    color = ContextNpcGetTextColor();
    AddTextPrinterParameterized2(0, 1, gStringVar4, GetPlayerTextSpeedDelay(), NULL, gSpecialVar_TextColor, 1, 3);      
}
```
I put this above `AddTextPrinterForMessage` which is the function base Emerald uses.
In this function, we have the local variable `color`. This variable is what we’re using to call the `ContextNpcGetTextColor` function we added earlier. Because of `ContextNpcGetTextColor` we are able to use `gSpecialVar_TextColor` as the colour value in `AddTextPrinterParameterized2` and because of the logic from the aforementioned functions, the colour value in `AddTextPrinterParameterized2`, will be the value of `graphicsInfo->textColor`.

Don’t forget to extern the function somewhere in `menu.h` like this:
```c
void AddTextPrinterForMessageWithTextColor(bool8 allowSkippingDelayWithButtonPress);
```

At the top of menu.c, add the following:
```diff
#include "event_data.h"
+    #include "field_specials.h"
```
This is so we can use the aformentioned `ContextNpcGetTextColor` function.

We need to open `field_message_box.c` and find the function `StartDrawFieldMessage` and make the following change:
```diff
static void StartDrawFieldMessage(void)
{

-    AddTextPrinterForMessage(TRUE);
+    AddTextPrinterForMessageWithTextColor(TRUE);
    CreateTask_DrawFieldMessage();
}
```
`StartDrawFieldMessage` is the function that handles message boxes in the overworld.

Next, we want to open `field_control_avatar.c` go to the function `ProcessPlayerFieldInput` and make the following change:
```diff
int ProcessPlayerFieldInput(struct FieldInput *input)
{
    struct MapPosition position;
    u8 playerDirection;
    u16 metatileBehavior;

    gSpecialVar_LastTalked = 0;
    gSelectedObjectEvent = 0;

+   gSpecialVar_TextColor = 0xFF;
```
This is so any text colour logic is reset when you gain control of the player in the overworld.

This is the object event side of things done. 

You need to declare `textColor` in `global.fieldmap.h` at `struct ObjectEventGraphicsInfo` like so:
```diff
struct ObjectEventGraphicsInfo
{
    /*0x00*/ u16 tileTag;
    /*0x02*/ u16 paletteTag;
-   /*0x04*/ u16 reflectionPaletteTag;
+   /*0x04*/ u16 textColor;
    /*0x06*/ u16 size;
    /*0x08*/ s16 width;
    /*0x0A*/ s16 height;
    /*0x0C*/ u8 paletteSlot:4;
             u8 shadowSize:2;
             u8 inanimate:1;
             u8 disableReflectionPaletteLoad:1;
    /*0x0D*/ u8 tracks;
    /*0x10*/ const struct OamData *oam;
    /*0x14*/ const struct SubspriteTable *subspriteTables;
    /*0x18*/ const union AnimCmd *const *anims;
    /*0x1C*/ const struct SpriteFrameImage *images;
    /*0x20*/ const union AffineAnimCmd *const *affineAnims;
};
```
We’re not done though.

We’re gonna implement the `textcolor` scripting command so you can make particular scripts be the colour you want.

Go to `scrcmd.c` and add the following function:
```c
bool8 ScrCmd_textcolor(struct ScriptContext * ctx)
 {
     gSpecialVar_PrevTextColor = gSpecialVar_TextColor;
     gSpecialVar_TextColor = ScriptReadByte(ctx);
     return FALSE;
 }
```
This is the script command function for the textcolor script command. `ctx` is the byte the command reads. If you notice, it’s using `gSpecialVar_TextColor` again. This means, we are essentially inputting a value for `gSpecialVar_TextColor`.
`gSpecialVar_PrevTextColor` stores the last value of `gSpecialVar_TextColor` before the new value is used so it can possibly be restored later on.

We want to go to `data/script_cmd_table.inc` and go to line 202 and change the following:

```diff
-    .4byte ScrCmd_nop1                     @ 0xc7
+    .4byte ScrCmd_textcolor                @ 0xc7
```

This is so the scripting system knows to use `ScrCmd_textcolor` we added earlier.


We want to declare these new special vars we’re using! Go to `event_data.c` on line 15, make the follow change:

```diff
EWRAM_DATA u16 gSpecialVar_0x8000 = 0;
EWRAM_DATA u16 gSpecialVar_0x8001 = 0;
EWRAM_DATA u16 gSpecialVar_0x8002 = 0;
EWRAM_DATA u16 gSpecialVar_0x8003 = 0;
EWRAM_DATA u16 gSpecialVar_0x8004 = 0;
EWRAM_DATA u16 gSpecialVar_0x8005 = 0;
EWRAM_DATA u16 gSpecialVar_0x8006 = 0;
EWRAM_DATA u16 gSpecialVar_0x8007 = 0;
EWRAM_DATA u16 gSpecialVar_0x8008 = 0;
EWRAM_DATA u16 gSpecialVar_0x8009 = 0;
EWRAM_DATA u16 gSpecialVar_0x800A = 0;
EWRAM_DATA u16 gSpecialVar_0x800B = 0;
EWRAM_DATA u16 gSpecialVar_Result = 0;
EWRAM_DATA u16 gSpecialVar_LastTalked = 0;
EWRAM_DATA u16 gSpecialVar_Facing = 0;
EWRAM_DATA u16 gSpecialVar_MonBoxId = 0;
EWRAM_DATA u16 gSpecialVar_MonBoxPos = 0;
-    EWRAM_DATA u16 gSpecialVar_Unused_0x8014 = 0;
+    EWRAM_DATA u16 gSpecialVar_TextColor = 0;
+    EWRAM_DATA u16 gSpecialVar_PrevTextColor = 0;
EWRAM_DATA static u8 gSpecialFlags[SPECIAL_FLAGS_SIZE] = {0};
```
And on line 30 in `include/event_data.h`, make the following change:

```diff
extern u16 gSpecialVar_0x8000;
extern u16 gSpecialVar_0x8001;
extern u16 gSpecialVar_0x8002;
extern u16 gSpecialVar_0x8003;
extern u16 gSpecialVar_0x8004;
extern u16 gSpecialVar_0x8005;
extern u16 gSpecialVar_0x8006;
extern u16 gSpecialVar_0x8007;
extern u16 gSpecialVar_0x8008;
extern u16 gSpecialVar_0x8009;
extern u16 gSpecialVar_0x800A;
extern u16 gSpecialVar_0x800B;
extern u16 gSpecialVar_Result;
extern u16 gSpecialVar_LastTalked;
extern u16 gSpecialVar_Facing;
extern u16 gSpecialVar_MonBoxId;
extern u16 gSpecialVar_MonBoxPos;
-    extern u16 gSpecialVar_Unused_0x8014;
+    extern u16 gSpecialVar_TextColor;
+    extern u16 gSpecialVar_PrevTextColor;
```
We need to define them to constants because `PrevTextColor` and `TextColor` can be used in scripts. So we need to go to `include/constants/vars` and find `#define VAR_UNUSED_0x08014` with `#define VAR_TEXT_COLOR` and add a new constant.
The changes should look something like this:
```diff
-   #define VAR_UNUSED_08014           0x0814
+   #define VAR_TEXT_COLOR             0x8014
#define VAR_TRAINER_BATTLE_OPPONENT_A 0x8015 // Alias of gTrainerBattleOpponent_A
+   #define VAR_PREV_TEXT_COLOR        0x8016

-   #define SPECIAL_VARS_END           0x8015
+   #define SPECIAL_VARS_END           0x8016
```
Lastly you will want to edit `data\event_scripts`

```diff
-   .4byte gSpecialVar_Unused_0x8014
+   .4byte gSpecialVar_TextColor
```

And with that, you should have successfully reimplemented `textcolor` and gave object events their own text colour.