Added some conditional messages.

Added emote graphics.
This commit is contained in:
Ariel Antonitis 2021-04-18 01:38:08 -04:00
parent e647e926a8
commit 875c4edd50
12 changed files with 260 additions and 57 deletions

View file

@ -55,6 +55,12 @@ callfunc ScrFunc_bufferlivemonspeciesname
.byte \out .byte \out
.endm .endm
.macro emote obj:req id:req
callfunc ScrFunc_emote
.byte \obj
.byte \id
.endm
EventScript_Follower:: EventScript_Follower::
lock lock
faceplayer faceplayer
@ -73,6 +79,7 @@ EventScript_Follower::
EventScript_FollowerFly:: EventScript_FollowerFly::
callfunc ScrFunc_followerfly callfunc ScrFunc_followerfly
EventScript_FollowerEnd:: EventScript_FollowerEnd::
waitfieldeffect FLDEFF_EMOTE
release release
end end
@ -147,17 +154,13 @@ EventScript_FollowerBurnPainful::
return return
@ Message address must be loaded into bank 0 @ Message address must be loaded into bank 0
EventScript_FollowerGeneric:: @ same as Std_MsgboxDefault EventScript_FollowerGeneric:: @ similar to Std_MsgboxDefault
waitfieldeffect FLDEFF_EMOTE
message 0x0 message 0x0
waitmessage waitmessage
waitbuttonpress waitbuttonpress
return return
EventScript_FollowerLove::
applymovement 0xFE ContestHall_Movement_Heart
waitmovement 0xFE
goto EventScript_FollowerGeneric
EnterPokeballMovement:: EnterPokeballMovement::
.byte 0x9F @ EnterPokeball .byte 0x9F @ EnterPokeball
step_end step_end

View file

@ -1,14 +1,13 @@
Happy (Special): Happy (Special):
{STR_VAR_1} greeted the two. (when standing in front of 2 trainers).
{STR_VAR_1} is very eager! ( gym ) must have type advantage.
{STR_VAR_1} is very composed and sure of itself (in a gym with a type advantage).
{STR_VAR_1} greeted Amphy!
{STR_VAR_1} greeted your mom. {STR_VAR_1} greeted your mom.
Your pokemon is staring intently at the mountain peak. Your pokemon is staring intently at the mountain peak.
{STR_VAR_1} is staring straight at the pokemon league. {STR_VAR_1} is staring straight at the pokemon league.
{STR_VAR_1} is staring at the sea. {STR_VAR_1} is staring at the sea.
{STR_VAR_1} greeted everyone! {STR_VAR_1} greeted everyone!
Your pokemon seems happy about the great weather. {STR_VAR_1} greeted the two. (when standing in front of 2 trainers).
{STR_VAR_1} is very eager! ( gym ) must have type advantage.
{STR_VAR_1} is very composed and sure of itself (in a gym with a type advantage).
{STR_VAR_1} greeted Amphy!
Neutral (Special): Neutral (Special):
(CELEBI) danced happily ( Pokemon Exclusive ). (CELEBI) danced happily ( Pokemon Exclusive ).
(CELEBI) danced beautiful ( Pokemon Exclusive ). (CELEBI) danced beautiful ( Pokemon Exclusive ).
@ -187,5 +186,3 @@ Curious (Special):
{STR_VAR_1} seems to be hearing a strange sound. (Team rocket hide out). {STR_VAR_1} seems to be hearing a strange sound. (Team rocket hide out).
{STR_VAR_1} is concerned about the other side of the fence, it seems. {STR_VAR_1} is concerned about the other side of the fence, it seems.
{STR_VAR_1} is looking at the machine in a strange manner. (Power plant). {STR_VAR_1} is looking at the machine in a strange manner. (Power plant).
Poisoned:
{STR_VAR_1} is shivering with the effects of being poisoned.

View file

@ -47,4 +47,4 @@ def export_messages(infile, outfile, n=None, indent=2):
if __name__ == '__main__': if __name__ == '__main__':
export_messages('emotions.txt', 'emotions.h', n=7) export_messages('emotions.txt', 'emotions.h', n=1)

19
graphics/misc/emotes.pal Normal file
View file

@ -0,0 +1,19 @@
JASC-PAL
0100
16
255 255 0
151 48 0
74 75 87
88 88 97
164 72 167
248 63 2
78 128 207
48 160 0
237 131 0
205 144 203
168 168 178
251 167 159
240 176 183
219 181 221
165 225 69
247 249 246

BIN
graphics/misc/emotes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -35,6 +35,7 @@
#define FLDEFF_USE_FLY 31 #define FLDEFF_USE_FLY 31
#define FLDEFF_FLY_IN 32 #define FLDEFF_FLY_IN 32
#define FLDEFF_QUESTION_MARK_ICON 33 #define FLDEFF_QUESTION_MARK_ICON 33
#define FLDEFF_EMOTE 33 // shares a slot with FLDEFF_QUESTION_MARK_ICON
#define FLDEFF_FEET_IN_FLOWING_WATER 34 #define FLDEFF_FEET_IN_FLOWING_WATER 34
#define FLDEFF_BIKE_TIRE_TRACKS 35 #define FLDEFF_BIKE_TIRE_TRACKS 35
#define FLDEFF_SAND_DISGUISE 36 #define FLDEFF_SAND_DISGUISE 36

View file

@ -13,6 +13,7 @@
#define N_FOLLOWER_LOVE_MESSAGES 10 #define N_FOLLOWER_LOVE_MESSAGES 10
#define N_FOLLOWER_SURPRISE_MESSAGES 20 #define N_FOLLOWER_SURPRISE_MESSAGES 20
#define N_FOLLOWER_CURIOUS_MESSAGES 7 #define N_FOLLOWER_CURIOUS_MESSAGES 7
#define N_FOLLOWER_POISONED_MESSAGES 1
struct MonCoords struct MonCoords
{ {
@ -141,5 +142,6 @@ extern const char * const gFollowerPensiveMessages[];
extern const char * const gFollowerLoveMessages[]; extern const char * const gFollowerLoveMessages[];
extern const char * const gFollowerSurpriseMessages[]; extern const char * const gFollowerSurpriseMessages[];
extern const char * const gFollowerCuriousMessages[]; extern const char * const gFollowerCuriousMessages[];
extern const char * const gFollowerPoisonedMessages[];
#endif // GUARD_DATA_H #endif // GUARD_DATA_H

View file

@ -1,5 +1,6 @@
OBJEVENTGFXDIR := graphics/object_events/pics OBJEVENTGFXDIR := graphics/object_events/pics
FLDEFFGFXDIR := graphics/field_effects/pics FLDEFFGFXDIR := graphics/field_effects/pics
MISCGFXDIR := graphics/misc
$(OBJEVENTGFXDIR)/people/brendan/walking.4bpp: %.4bpp: %.png $(OBJEVENTGFXDIR)/people/brendan/walking.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 4 $(GFX) $< $@ -mwidth 2 -mheight 4
@ -1913,3 +1914,6 @@ $(OBJEVENTGFXDIR)/pokemon/jirachi.4bpp: %.4bpp: %.png
$(OBJEVENTGFXDIR)/pokemon/deoxys.4bpp: %.4bpp: %.png $(OBJEVENTGFXDIR)/pokemon/deoxys.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4 $(GFX) $< $@ -mwidth 4 -mheight 4
$(MISCGFXDIR)/emotes.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 2

View file

@ -780,3 +780,4 @@ const u16 gObjectEventPal_HoOh[] = INCBIN_U16("graphics/object_events/palettes/h
const u16 gObjectEventPal_Lugia[] = INCBIN_U16("graphics/object_events/palettes/lugia.gbapal"); const u16 gObjectEventPal_Lugia[] = INCBIN_U16("graphics/object_events/palettes/lugia.gbapal");
const u16 gObjectEventPaletteLight[] = INCBIN_U16("graphics/object_events/palettes/light.gbapal"); const u16 gObjectEventPaletteLight[] = INCBIN_U16("graphics/object_events/palettes/light.gbapal");
const u16 gObjectEventPaletteEmotes[] = INCBIN_U16("graphics/misc/emotes.gbapal");

View file

@ -31,6 +31,8 @@ const char * const gFollowerHappyMessages[] = {
(const char []) _("{STR_VAR_1} seems very happy to see\nyou!"), (const char []) _("{STR_VAR_1} seems very happy to see\nyou!"),
(const char []) _("{STR_VAR_1} faced this way and\ngrinned."), (const char []) _("{STR_VAR_1} faced this way and\ngrinned."),
(const char []) _("{STR_VAR_1} happily cuddled up to\nyou!"), (const char []) _("{STR_VAR_1} happily cuddled up to\nyou!"),
// Conditional messages begin here, index 31
(const char []) _("Your pokemon seems happy about the\ngreat weather."),
}; };
// Unconditional neutral messages // Unconditional neutral messages
@ -147,3 +149,7 @@ const char * const gFollowerCuriousMessages[] = {
(const char []) _("{STR_VAR_1} is sniffing at you."), (const char []) _("{STR_VAR_1} is sniffing at you."),
(const char []) _("{STR_VAR_1} seems to be a little\nhesitant..."), (const char []) _("{STR_VAR_1} seems to be a little\nhesitant..."),
}; };
const char * const gFollowerPoisonedMessages[] = {
(const char []) _("{STR_VAR_1} is shivering with the\neffects of being poisoned."),
};

View file

@ -450,8 +450,9 @@ const u8 gInitialMovementTypeFacingDirections[] = {
#define OBJ_EVENT_PAL_TAG_LUGIA 0x1121 #define OBJ_EVENT_PAL_TAG_LUGIA 0x1121
#define OBJ_EVENT_PAL_TAG_RS_BRENDAN 0x1122 #define OBJ_EVENT_PAL_TAG_RS_BRENDAN 0x1122
#define OBJ_EVENT_PAL_TAG_RS_MAY 0x1123 #define OBJ_EVENT_PAL_TAG_RS_MAY 0x1123
#define OBJ_EVENT_PAL_TAG_DYNAMIC 0x1124 #define OBJ_EVENT_PAL_TAG_DYNAMIC 0x1124
#define OBJ_EVENT_PAL_TAG_LIGHT 0x8001 #define OBJ_EVENT_PAL_TAG_EMOTES 0x1125
#define OBJ_EVENT_PAL_TAG_LIGHT 0x8001
#define OBJ_EVENT_PAL_TAG_NONE 0x11FF #define OBJ_EVENT_PAL_TAG_NONE 0x11FF
#include "data/object_events/object_event_graphics_info_pointers.h" #include "data/object_events/object_event_graphics_info_pointers.h"
@ -500,6 +501,7 @@ static const struct SpritePalette sObjectEventSpritePalettes[] = {
{gObjectEventPal_RubySapphireMay, OBJ_EVENT_PAL_TAG_RS_MAY}, {gObjectEventPal_RubySapphireMay, OBJ_EVENT_PAL_TAG_RS_MAY},
{gObjectEventPal_Npc1, OBJ_EVENT_PAL_TAG_DYNAMIC}, {gObjectEventPal_Npc1, OBJ_EVENT_PAL_TAG_DYNAMIC},
{gObjectEventPaletteLight, OBJ_EVENT_PAL_TAG_LIGHT}, {gObjectEventPaletteLight, OBJ_EVENT_PAL_TAG_LIGHT},
{gObjectEventPaletteEmotes, OBJ_EVENT_PAL_TAG_EMOTES},
{NULL, 0x0000}, {NULL, 0x0000},
}; };
@ -1731,6 +1733,8 @@ enum {
FOLLOWER_EMOTION_LOVE, FOLLOWER_EMOTION_LOVE,
FOLLOWER_EMOTION_SURPRISE, FOLLOWER_EMOTION_SURPRISE,
FOLLOWER_EMOTION_CURIOUS, FOLLOWER_EMOTION_CURIOUS,
FOLLOWER_EMOTION_MUSIC,
FOLLOWER_EMOTION_POISONED,
FOLLOWER_EMOTION_LENGTH, FOLLOWER_EMOTION_LENGTH,
}; };
@ -1742,21 +1746,45 @@ static const struct FollowerMessagePool followerBasicMessages[] = {
[FOLLOWER_EMOTION_UPSET] = {gFollowerUpsetMessages, EventScript_FollowerGeneric, N_FOLLOWER_UPSET_MESSAGES}, [FOLLOWER_EMOTION_UPSET] = {gFollowerUpsetMessages, EventScript_FollowerGeneric, N_FOLLOWER_UPSET_MESSAGES},
[FOLLOWER_EMOTION_ANGRY] = {gFollowerAngryMessages, EventScript_FollowerGeneric, N_FOLLOWER_ANGRY_MESSAGES}, [FOLLOWER_EMOTION_ANGRY] = {gFollowerAngryMessages, EventScript_FollowerGeneric, N_FOLLOWER_ANGRY_MESSAGES},
[FOLLOWER_EMOTION_PENSIVE] = {gFollowerPensiveMessages, EventScript_FollowerGeneric, N_FOLLOWER_PENSIVE_MESSAGES}, [FOLLOWER_EMOTION_PENSIVE] = {gFollowerPensiveMessages, EventScript_FollowerGeneric, N_FOLLOWER_PENSIVE_MESSAGES},
[FOLLOWER_EMOTION_LOVE] = {gFollowerLoveMessages, EventScript_FollowerLove, N_FOLLOWER_LOVE_MESSAGES}, [FOLLOWER_EMOTION_LOVE] = {gFollowerLoveMessages, EventScript_FollowerGeneric, N_FOLLOWER_LOVE_MESSAGES},
[FOLLOWER_EMOTION_SURPRISE] = {gFollowerSurpriseMessages, EventScript_FollowerGeneric, N_FOLLOWER_SURPRISE_MESSAGES}, [FOLLOWER_EMOTION_SURPRISE] = {gFollowerSurpriseMessages, EventScript_FollowerGeneric, N_FOLLOWER_SURPRISE_MESSAGES},
[FOLLOWER_EMOTION_CURIOUS] = {gFollowerCuriousMessages, EventScript_FollowerGeneric, N_FOLLOWER_CURIOUS_MESSAGES}, [FOLLOWER_EMOTION_CURIOUS] = {gFollowerCuriousMessages, EventScript_FollowerGeneric, N_FOLLOWER_CURIOUS_MESSAGES},
[FOLLOWER_EMOTION_POISONED] = {gFollowerPoisonedMessages, EventScript_FollowerGeneric, N_FOLLOWER_POISONED_MESSAGES},
};
// Display an emote above an object event
// Note that this is not a movement action
static void ObjectEventEmote(struct ObjectEvent *objEvent, u8 emotion) {
emotion %= FOLLOWER_EMOTION_LENGTH;
ObjectEventGetLocalIdAndMap(objEvent, &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]);
gFieldEffectArguments[7] = emotion;
FieldEffectStart(FLDEFF_EMOTE);
}
// Script-accessible version of the above
bool8 ScrFunc_emote(struct ScriptContext *ctx) {
u8 localId = ScriptReadByte(ctx);
u8 emotion = ScriptReadByte(ctx) % FOLLOWER_EMOTION_LENGTH;
u8 i = GetObjectEventIdByLocalId(localId);
if (i < OBJECT_EVENTS_COUNT)
ObjectEventEmote(&gObjectEvents[i], emotion);
return FALSE;
}
struct SpecialEmote { // Used for storing conditional emotes
const u8 * script;
u16 index;
u8 emotion;
}; };
// Call an applicable follower message script // Call an applicable follower message script
bool8 ScrFunc_getfolloweraction(struct ScriptContext *ctx) // Essentially a big switch for follower messages bool8 ScrFunc_getfolloweraction(struct ScriptContext *ctx) // Essentially a big switch for follower messages
{ {
u16 value;
u16 species; u16 species;
u32 behavior; u32 behavior;
s16 health_percent; s16 health_percent;
u8 map_region;
u8 friendship; u8 friendship;
const u8 *message_choices[10] = {0}; struct SpecialEmote cond_emotes[16] = {0};
u8 n_choices = 0; u8 n_choices = 0;
struct ObjectEvent *objEvent = GetFollowerObject(); struct ObjectEvent *objEvent = GetFollowerObject();
struct Pokemon *mon = GetFirstLiveMon(); struct Pokemon *mon = GetFirstLiveMon();
@ -1771,44 +1799,22 @@ bool8 ScrFunc_getfolloweraction(struct ScriptContext *ctx) // Essentially a big
ScriptJump(ctx, EventScript_FollowerEnd); ScriptJump(ctx, EventScript_FollowerEnd);
behavior = MapGridGetMetatileBehaviorAt(objEvent->currentCoords.x, objEvent->currentCoords.y); behavior = MapGridGetMetatileBehaviorAt(objEvent->currentCoords.x, objEvent->currentCoords.y);
species = GetMonData(mon, MON_DATA_SPECIES); species = GetMonData(mon, MON_DATA_SPECIES);
// 1. Puddle splash or wet feet
if (MetatileBehavior_IsPuddle(behavior) || MetatileBehavior_IsShallowFlowingWater(behavior)) {
if (SpeciesHasType(species, TYPE_FIRE))
message_choices[n_choices++] = EventScript_FollowerUnhappyToBeWet;
else if (SpeciesToGraphicsInfo(species, 0)->tracks) // if follower is grounded
message_choices[n_choices++] = EventScript_FollowerSplashesAbout;
}
// 2. Weather-based messages
if (GetCurrentWeather() == WEATHER_RAIN || GetCurrentWeather() == WEATHER_RAIN_THUNDERSTORM) {
if (SpeciesHasType(species, TYPE_FIRE))
message_choices[n_choices++] = EventScript_FollowerUnhappyFace;
else if (SpeciesHasType(species, TYPE_WATER) || SpeciesHasType(species, TYPE_GRASS))
message_choices[n_choices++] = EventScript_FollowerHappyRain;
}
// 3. Health & status-based messages
health_percent = mon->hp * 100 / mon->maxHP;
if (health_percent <= 20)
message_choices[n_choices++] = EventScript_FollowerAboutToFall;
else if (health_percent < 50 || mon->status & 0x40) // STATUS1_PARALYSIS
message_choices[n_choices++] = EventScript_FollowerTryingToKeepUp;
// 4. More status messages
if (mon->status & (0x20 | 0x8)) // STATUS1_FREEZE | STATUS1_POISON
message_choices[n_choices++] = EventScript_FollowerIsShivering;
else if (mon->status & 0x10) // STATUS1_BURN
message_choices[n_choices++] = EventScript_FollowerBurnPainful;
// TODO: What influences a follower's emotion ?
// Happy, neutral, sad, upset, angry, daydream, love, surprise, quizzical
// Friendship: boost to 'happy' and 'love'
// Weather: Based on type
// Status/low health: boost to unhappy, poisoned
// Happy weights
// TODO: Add sprites from https://www.spriters-resource.com/ds_dsi/pokemonheartgoldsoulsilver/sheet/30497/ ?
friendship = GetMonData(mon, MON_DATA_FRIENDSHIP); friendship = GetMonData(mon, MON_DATA_FRIENDSHIP);
// // 1. Puddle splash or wet feet
// if (MetatileBehavior_IsPuddle(behavior) || MetatileBehavior_IsShallowFlowingWater(behavior)) {
// if (SpeciesHasType(species, TYPE_FIRE))
// message_choices[n_choices++] = EventScript_FollowerUnhappyToBeWet;
// else if (SpeciesToGraphicsInfo(species, 0)->tracks) // if follower is grounded
// message_choices[n_choices++] = EventScript_FollowerSplashesAbout;
// }
// Happy weights
emotion_weight[FOLLOWER_EMOTION_HAPPY] = 10; emotion_weight[FOLLOWER_EMOTION_HAPPY] = 10;
if (friendship > 170) if (friendship > 170)
emotion_weight[FOLLOWER_EMOTION_HAPPY] = 30; emotion_weight[FOLLOWER_EMOTION_HAPPY] = 30;
else if (friendship > 80) else if (friendship > 80)
emotion_weight[FOLLOWER_EMOTION_HAPPY] = 20; emotion_weight[FOLLOWER_EMOTION_HAPPY] = 20;
if (GetCurrentWeather() == WEATHER_SUNNY || GetCurrentWeather() == WEATHER_SUNNY_CLOUDS)
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_HAPPY, .index=31};
// Neutral weights // Neutral weights
emotion_weight[FOLLOWER_EMOTION_NEUTRAL] = 15; emotion_weight[FOLLOWER_EMOTION_NEUTRAL] = 15;
// Sad weights // Sad weights
@ -1834,6 +1840,28 @@ bool8 ScrFunc_getfolloweraction(struct ScriptContext *ctx) // Essentially a big
// TODO: Increase this if there is an item nearby, or if the pokemon has pickup // TODO: Increase this if there is an item nearby, or if the pokemon has pickup
emotion_weight[FOLLOWER_EMOTION_CURIOUS] = 5; emotion_weight[FOLLOWER_EMOTION_CURIOUS] = 5;
emotion = RandomWeightedIndex(emotion_weight, FOLLOWER_EMOTION_LENGTH); emotion = RandomWeightedIndex(emotion_weight, FOLLOWER_EMOTION_LENGTH);
if (mon->status & 0x8) // STATUS1_POISON
emotion = FOLLOWER_EMOTION_POISONED;
ObjectEventEmote(objEvent, emotion);
if (Random() & 1) { // With 50% chance, select special message using reservoir sampling
u8 i, j = 1;
struct SpecialEmote *choice = 0;
for (i = 0; i < n_choices; i++) {
if (cond_emotes[i].emotion == emotion) {
if (Random() < 0x10000 / (j++)) // Replace item with 1/j chance
choice = &cond_emotes[i];
}
}
if (choice) { // Only continue if a script was actually chosen
if (choice->script)
ScriptCall(ctx, choice->script);
else {
ctx->data[0] = (u32) followerBasicMessages[emotion].messages[choice->index];
ScriptCall(ctx, followerBasicMessages[emotion].script);
}
return FALSE;
}
}
ctx->data[0] = (u32) followerBasicMessages[emotion].messages[Random() % followerBasicMessages[emotion].length]; ctx->data[0] = (u32) followerBasicMessages[emotion].messages[Random() % followerBasicMessages[emotion].length];
ScriptCall(ctx, followerBasicMessages[emotion].script); ScriptCall(ctx, followerBasicMessages[emotion].script);
return FALSE; return FALSE;
@ -2119,7 +2147,7 @@ static u8 UpdateSpritePalette(const struct SpritePalette * spritePalette, struct
} }
// Find and update based on template's paletteTag // Find and update based on template's paletteTag
// TODO: Should this logic happen in CreateSpriteAt? // TODO: Add a better way to associate tags -> palettes besides listing them in sObjectEventSpritePalettes
u8 UpdateSpritePaletteByTemplate(const struct SpriteTemplate * template, struct Sprite * sprite) { u8 UpdateSpritePaletteByTemplate(const struct SpriteTemplate * template, struct Sprite * sprite) {
u8 i = FindObjectEventPaletteIndexByTag(template->paletteTag); u8 i = FindObjectEventPaletteIndexByTag(template->paletteTag);
if (i == 0xFF) if (i == 0xFF)
@ -7260,6 +7288,7 @@ bool8 MovementAction_EmoteExclamationMark_Step0(struct ObjectEvent *objectEvent,
bool8 MovementAction_EmoteQuestionMark_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) bool8 MovementAction_EmoteQuestionMark_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{ {
ObjectEventGetLocalIdAndMap(objectEvent, &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]); ObjectEventGetLocalIdAndMap(objectEvent, &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]);
gFieldEffectArguments[7] = -1;
FieldEffectStart(FLDEFF_QUESTION_MARK_ICON); FieldEffectStart(FLDEFF_QUESTION_MARK_ICON);
sprite->data[2] = 1; sprite->data[2] = 1;
return TRUE; return TRUE;

View file

@ -62,6 +62,9 @@ EWRAM_DATA u8 gApproachingTrainerId = 0;
static const u8 sEmotion_ExclamationMarkGfx[] = INCBIN_U8("graphics/misc/emotion_exclamation.4bpp"); static const u8 sEmotion_ExclamationMarkGfx[] = INCBIN_U8("graphics/misc/emotion_exclamation.4bpp");
static const u8 sEmotion_QuestionMarkGfx[] = INCBIN_U8("graphics/misc/emotion_question.4bpp"); static const u8 sEmotion_QuestionMarkGfx[] = INCBIN_U8("graphics/misc/emotion_question.4bpp");
static const u8 sEmotion_HeartGfx[] = INCBIN_U8("graphics/misc/emotion_heart.4bpp"); static const u8 sEmotion_HeartGfx[] = INCBIN_U8("graphics/misc/emotion_heart.4bpp");
// TODO: Credit https://www.spriters-resource.com/ds_dsi/pokemonheartgoldsoulsilver/sheet/30497/
static const u8 sEmotion_Gfx[] = INCBIN_U8("graphics/misc/emotes.4bpp");
static u8 (*const sDirectionalApproachDistanceFuncs[])(struct ObjectEvent *trainerObj, s16 range, s16 x, s16 y) = static u8 (*const sDirectionalApproachDistanceFuncs[])(struct ObjectEvent *trainerObj, s16 range, s16 x, s16 y) =
{ {
@ -147,6 +150,109 @@ static const struct SpriteFrameImage sSpriteImageTable_HeartIcon[] =
} }
}; };
static const struct SpriteFrameImage sSpriteImageTable_Emotes[] =
{
{ .data = (u8 *)sEmotion_Gfx+0*0x80, .size = 0x80}, // FOLLOWER_EMOTION_HAPPY
{ .data = (u8 *)sEmotion_Gfx+1*0x80, .size = 0x80}, // FOLLOWER_EMOTION_HAPPY
{ .data = (u8 *)sEmotion_Gfx+2*0x80, .size = 0x80}, // FOLLOWER_EMOTION_NEUTRAL
{ .data = (u8 *)sEmotion_Gfx+3*0x80, .size = 0x80}, // FOLLOWER_EMOTION_NEUTRAL
{ .data = (u8 *)sEmotion_Gfx+4*0x80, .size = 0x80}, // FOLLOWER_EMOTION_SAD
{ .data = (u8 *)sEmotion_Gfx+5*0x80, .size = 0x80}, // FOLLOWER_EMOTION_SAD
{ .data = (u8 *)sEmotion_Gfx+6*0x80, .size = 0x80}, // FOLLOWER_EMOTION_UPSET
{ .data = (u8 *)sEmotion_Gfx+7*0x80, .size = 0x80}, // FOLLOWER_EMOTION_UPSET
{ .data = (u8 *)sEmotion_Gfx+8*0x80, .size = 0x80}, // FOLLOWER_EMOTION_ANGRY
{ .data = (u8 *)sEmotion_Gfx+9*0x80, .size = 0x80}, // FOLLOWER_EMOTION_ANGRY
{ .data = (u8 *)sEmotion_Gfx+10*0x80, .size = 0x80}, // FOLLOWER_EMOTION_PENSIVE
{ .data = (u8 *)sEmotion_Gfx+11*0x80, .size = 0x80}, // FOLLOWER_EMOTION_PENSIVE
{ .data = (u8 *)sEmotion_Gfx+12*0x80, .size = 0x80}, // FOLLOWER_EMOTION_LOVE
{ .data = (u8 *)sEmotion_Gfx+13*0x80, .size = 0x80}, // FOLLOWER_EMOTION_LOVE
{ .data = (u8 *)sEmotion_Gfx+14*0x80, .size = 0x80}, // FOLLOWER_EMOTION_SURPRISE
{ .data = (u8 *)sEmotion_Gfx+15*0x80, .size = 0x80}, // FOLLOWER_EMOTION_SURPRISE
{ .data = (u8 *)sEmotion_Gfx+16*0x80, .size = 0x80}, // FOLLOWER_EMOTION_CURIOUS
{ .data = (u8 *)sEmotion_Gfx+17*0x80, .size = 0x80}, // FOLLOWER_EMOTION_CURIOUS
{ .data = (u8 *)sEmotion_Gfx+18*0x80, .size = 0x80}, // FOLLOWER_EMOTION_MUSIC
{ .data = (u8 *)sEmotion_Gfx+19*0x80, .size = 0x80}, // FOLLOWER_EMOTION_MUSIC
{ .data = (u8 *)sEmotion_Gfx+20*0x80, .size = 0x80}, // FOLLOWER_EMOTION_POISONED
{ .data = (u8 *)sEmotion_Gfx+21*0x80, .size = 0x80}, // FOLLOWER_EMOTION_POISONED
};
static const union AnimCmd sSpriteAnim_Emotes0[] = {
ANIMCMD_FRAME(0*2, 30),
ANIMCMD_FRAME(0*2+1, 30),
ANIMCMD_FRAME(0*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes1[] = {
ANIMCMD_FRAME(1*2, 30),
ANIMCMD_FRAME(1*2+1, 30),
ANIMCMD_FRAME(1*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes2[] = {
ANIMCMD_FRAME(2*2, 30),
ANIMCMD_FRAME(2*2+1, 30),
ANIMCMD_FRAME(2*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes3[] = {
ANIMCMD_FRAME(3*2, 30),
ANIMCMD_FRAME(3*2+1, 30),
ANIMCMD_FRAME(3*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes4[] = {
ANIMCMD_FRAME(4*2, 30),
ANIMCMD_FRAME(4*2+1, 30),
ANIMCMD_FRAME(4*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes5[] = {
ANIMCMD_FRAME(5*2, 30),
ANIMCMD_FRAME(5*2+1, 30),
ANIMCMD_FRAME(5*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes6[] = {
ANIMCMD_FRAME(6*2, 30),
ANIMCMD_FRAME(6*2+1, 30),
ANIMCMD_FRAME(6*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes7[] = {
ANIMCMD_FRAME(7*2, 30),
ANIMCMD_FRAME(7*2+1, 30),
ANIMCMD_FRAME(7*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes8[] = {
ANIMCMD_FRAME(8*2, 30),
ANIMCMD_FRAME(8*2+1, 30),
ANIMCMD_FRAME(8*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes9[] = {
ANIMCMD_FRAME(9*2, 30),
ANIMCMD_FRAME(9*2+1, 30),
ANIMCMD_FRAME(9*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes10[] = {
ANIMCMD_FRAME(10*2, 30),
ANIMCMD_FRAME(10*2+1, 30),
ANIMCMD_FRAME(10*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Icons1[] = static const union AnimCmd sSpriteAnim_Icons1[] =
{ {
ANIMCMD_FRAME(0, 60), ANIMCMD_FRAME(0, 60),
@ -165,12 +271,28 @@ static const union AnimCmd *const sSpriteAnimTable_Icons[] =
sSpriteAnim_Icons2 sSpriteAnim_Icons2
}; };
#define OBJ_EVENT_PAL_TAG_17 0x1110 // TODO: Move this into event_object_movement.h static const union AnimCmd *const sSpriteAnimTable_Emotes[] = {
sSpriteAnim_Emotes0,
sSpriteAnim_Emotes1,
sSpriteAnim_Emotes2,
sSpriteAnim_Emotes3,
sSpriteAnim_Emotes4,
sSpriteAnim_Emotes5,
sSpriteAnim_Emotes6,
sSpriteAnim_Emotes7,
sSpriteAnim_Emotes8,
sSpriteAnim_Emotes9,
sSpriteAnim_Emotes10,
};
// TODO: Move these declarations into even_object_movement.h
#define OBJ_EVENT_PAL_TAG_MAY 0x1110
#define OBJ_EVENT_PAL_TAG_EMOTES 0x1125
static const struct SpriteTemplate sSpriteTemplate_ExclamationQuestionMark = static const struct SpriteTemplate sSpriteTemplate_ExclamationQuestionMark =
{ {
.tileTag = 0xffff, .tileTag = 0xffff,
.paletteTag = OBJ_EVENT_PAL_TAG_17, .paletteTag = OBJ_EVENT_PAL_TAG_MAY,
.oam = &sOamData_Icons, .oam = &sOamData_Icons,
.anims = sSpriteAnimTable_Icons, .anims = sSpriteAnimTable_Icons,
.images = sSpriteImageTable_ExclamationQuestionMark, .images = sSpriteImageTable_ExclamationQuestionMark,
@ -189,6 +311,16 @@ static const struct SpriteTemplate sSpriteTemplate_HeartIcon =
.callback = SpriteCB_TrainerIcons .callback = SpriteCB_TrainerIcons
}; };
static const struct SpriteTemplate sSpriteTemplate_Emote = {
.tileTag = 0xffff,
.paletteTag = OBJ_EVENT_PAL_TAG_EMOTES,
.oam = &sOamData_Icons,
.anims = sSpriteAnimTable_Emotes,
.images = sSpriteImageTable_Emotes,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_TrainerIcons
};
// code // code
bool8 CheckForTrainersWantingBattle(void) bool8 CheckForTrainersWantingBattle(void)
{ {
@ -710,7 +842,17 @@ u8 FldEff_ExclamationMarkIcon(void)
u8 FldEff_QuestionMarkIcon(void) u8 FldEff_QuestionMarkIcon(void)
{ {
u8 spriteId = CreateSpriteAtEnd(&sSpriteTemplate_ExclamationQuestionMark, 0, 0, 0x52); u8 spriteId;
if (gFieldEffectArguments[7] >= 0) { // Use follower emotes
u8 emotion = gFieldEffectArguments[7];
spriteId = CreateSpriteAtEnd(&sSpriteTemplate_Emote, 0, 0, 0x52);
if (spriteId == MAX_SPRITES)
return 0;
SetIconSpriteData(&gSprites[spriteId], FLDEFF_EMOTE, emotion); // Set animation based on emotion
UpdateSpritePaletteByTemplate(&sSpriteTemplate_Emote, &gSprites[spriteId]);
return 0;
}
spriteId = CreateSpriteAtEnd(&sSpriteTemplate_ExclamationQuestionMark, 0, 0, 0x52);
if (spriteId != MAX_SPRITES) { if (spriteId != MAX_SPRITES) {
SetIconSpriteData(&gSprites[spriteId], FLDEFF_QUESTION_MARK_ICON, 1); SetIconSpriteData(&gSprites[spriteId], FLDEFF_QUESTION_MARK_ICON, 1);
@ -723,7 +865,6 @@ u8 FldEff_QuestionMarkIcon(void)
u8 FldEff_HeartIcon(void) u8 FldEff_HeartIcon(void)
{ {
u8 spriteId = CreateSpriteAtEnd(&sSpriteTemplate_HeartIcon, 0, 0, 0x52); u8 spriteId = CreateSpriteAtEnd(&sSpriteTemplate_HeartIcon, 0, 0, 0x52);
if (spriteId != MAX_SPRITES) if (spriteId != MAX_SPRITES)
{ {
struct Sprite *sprite = &gSprites[spriteId]; struct Sprite *sprite = &gSprites[spriteId];